Skip to content
Open
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
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

15 changes: 0 additions & 15 deletions .eslintrc

This file was deleted.

8 changes: 4 additions & 4 deletions .github/workflows/forked_run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ jobs:
if: contains(github.event.pull_request.labels.*.name, 'Approved')
strategy:
matrix:
node: [20, 22]
node: [20, 22, 24]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Setup
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Create NYC folder
Expand All @@ -26,7 +26,7 @@ jobs:
- name: Coverage
run: npm run test-lcov
- name: Coveralls
uses: coverallsapp/github-action@master
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coverage/lcov.info
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
# use node setup library (more info here https://github.com/actions/setup-node)
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: 24
registry-url: https://registry.npmjs.org

- name: Install npm
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: [20, 22]
node: [20, 22, 24]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Setup
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Create NYC folder
Expand All @@ -21,6 +21,7 @@ jobs:
- name: Run tests
run: npm run test
- name: Run integration tests
continue-on-error: true
env:
TEST_API_KEY: ${{ secrets.TEST_API_KEY }}
LIVE_API_KEY: ${{ secrets.LIVE_API_KEY }}
Expand All @@ -30,7 +31,7 @@ jobs:
run: npm run test-lcov
- name: Coveralls
if: matrix.node == 20
uses: coverallsapp/github-action@master
uses: coverallsapp/github-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./coverage/lcov.info
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,23 @@ coverage
.idea/
.vscode
.env

# macOS
.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
*.icloud
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20.19.4
24.15.0
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
## 8.0.0 (2026-05-18)

##### Breaking Changes

* **engines** update minimum Node.js version requirement to `>= 24.15.0` (was `>= 20.0.0`)

##### Security

* Reduce npm audit findings from 15 to 0 (1 critical, 6 high, 6 moderate, 1 low → 0)
* Remove abandoned `coveralls` package and its unfixable transitive chain (`request`, `form-data`, `qs`, `tough-cookie`)
* Upgrade `axios` ^1.13.2 → ^1.16.1 — fixes 16 CVEs (SSRF, prototype pollution, header injection)
* Upgrade `mocha` ^10 → ^11.7.5; add `overrides` for `serialize-javascript@^7.0.5` and `diff@^9` to patch vulnerabilities bundled inside mocha 11
* Upgrade `nock` 14.0.10 → 14.0.15 (memory leak fix)

##### Maintenance

* Migrate ESLint 8 → 10 with flat config (`eslint.config.js`); replace `.eslintrc` and `.eslintignore`
* `eslint-config-lob` ^5.2.0 → ^7.0.0
* `eslint-plugin-lob` ^3.0.0 → ^3.0.2
* Add `@eslint/js`, `@stylistic/eslint-plugin`, `eslint-plugin-jsdoc`, `globals`
* Removed rules replaced: `valid-jsdoc` → `jsdoc/*`, `no-negated-in-lhs` → `no-unsafe-negation`, formatting rules → `@stylistic/*`
* Upgrade `chai` 2.3.0 → 6.2.2 (Node 24 synchronous ESM interop)
* Upgrade `p-map` 2.1.0 → 7.0.4 (Node 24 synchronous ESM interop)
* Upgrade `csv-parse` 4 → 6; fix named-export import and data-first argument in examples
* Upgrade `json-2-csv` 3 → 5; migrate callback API to Promise in examples
* Upgrade `nyc` 15.1.0 → 18.0.0
* Upgrade `cross-env` 5.2.1 → 10.1.0
* Remove unused `uuid` devDependency
* Pin `.node-version` to 24.15.0
* GitHub Actions: upgrade `actions/checkout` v2 → v4, `actions/setup-node` v2 → v4
* GitHub Actions: add Node 24 to CI matrix; pin `npm@11`; pin `coverallsapp/github-action@master` → `@v2`
* Add macOS entries to `.gitignore`

## 7.1.0 (2026-01-15)

##### Security
Expand Down
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,8 @@
[downloads-image]: http://img.shields.io/npm/dm/lob.svg
[npm-url]: https://npmjs.org/package/lob
[npm-image]: https://badge.fury.io/js/lob.svg
[travis-url]: https://travis-ci.org/lob/lob-node
[travis-image]: https://travis-ci.org/lob/lob-node.svg?branch=master
[depstat-url]: https://david-dm.org/Lob/Lob-node
[depstat-image]: https://david-dm.org/Lob/Lob-node.svg

[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status](https://travis-ci.org/lob/lob-node.svg?branch=master)](https://travis-ci.org/lob/lob-node) [![Dependency Status](https://david-dm.org/lob/lob-node.svg)](https://david-dm.org/lob/lob-node) [![Dev Dependency Status](https://david-dm.org/lob/lob-node/dev-status.svg)](https://david-dm.org/lob/lob-node) [![Coverage Status](https://coveralls.io/repos/lob/lob-node/badge.svg?branch=master)](https://coveralls.io/r/lob/lob-node?branch=master)
[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![CI](https://github.com/lob/lob-node/actions/workflows/run_tests.yml/badge.svg)](https://github.com/lob/lob-node/actions/workflows/run_tests.yml) [![Coverage Status](https://coveralls.io/repos/lob/lob-node/badge.svg?branch=master)](https://coveralls.io/r/lob/lob-node?branch=master)

Node.js wrapper for the [Lob.com](https://lob.com) API. See full Lob.com documentation [here](https://lob.com/docs/node).
******
Expand Down Expand Up @@ -63,6 +59,8 @@ $ git clone git@github.com:lob/lob-node.git
$ npm install
```

**Requirements:** Node.js >= 24.15.0, npm >= 11.5.1

### Usage
```javascript
const Lob = require('lob')('YOUR API KEY');
Expand Down Expand Up @@ -164,6 +162,20 @@ Some integration tests require a live API key:
TEST_API_KEY=your_test_key LIVE_API_KEY=your_live_key npm run test:integration
```

To run lint:

```
npm run lint
```

To check for vulnerabilities:

```
npm audit
```

Target: zero `moderate` and zero `high` findings. Current status: **0 vulnerabilities**.

=======================

Copyright © 2013 Lob.com
Expand Down
30 changes: 30 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

const lobConfig = require('eslint-config-lob');

module.exports = [
...lobConfig,
{
languageOptions: {
ecmaVersion: 2022,
globals: {
API_KEY: false,
expect: false,
HAS_LIVE_KEY: false,
INTEGRATION_TIMEOUT: false,
LiveLob: false,
Lob: false,
mocks: false
}
}
},
{
files: ['examples/**/*.js'],
rules: {
'no-console': 0
}
},
{
ignores: ['coverage/**']
}
];
5 changes: 0 additions & 5 deletions examples/.eslintrc

This file was deleted.

4 changes: 2 additions & 2 deletions examples/create_postcards_from_csv/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';

const parse = require('csv-parse');
const { parse } = require('csv-parse');
const fs = require('fs');
const pMap = require('p-map');
const { default: pMap } = require('p-map');

const lobFactory = require('../../lib/index.js');
const lob = new lobFactory('YOUR_API_KEY');
Expand Down
118 changes: 56 additions & 62 deletions examples/verify_and_create_letters_from_csv/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
const converter = require('json-2-csv');
const fs = require('fs');
const moment = require('moment');
const parse = require('csv-parse');
const { parse } = require('csv-parse');

const LobFactory = require('../../lib/index.js');
const lob = new LobFactory('YOUR_API_KEY');

const inputFile = fs.createReadStream(`${__dirname}/input.csv`);
const successFd = fs.openSync(`${__dirname}/success.csv`, 'w');
const errorFd = fs.openSync(`${__dirname}/error.csv`, 'w');
const letterTemplate = fs.readFileSync(`${__dirname}/letter_template.html`).toString();
Expand All @@ -23,69 +22,64 @@ const companyInfo = {
address_country: 'US'
};

const parser = parse({ columns: true }, (err, data) => {
if (err) {
return console.log(err);
}
const parser = fs.createReadStream(`${__dirname}/input.csv`).pipe(parse({ columns: true }));

data.forEach((client) => {
parser.on('data', (client) => {

const name = client.name;
const amount = parseFloat(client.amount).toFixed(2);
const address = {
recipient: name,
primary_line: client.primary_line,
secondary_line: client.secondary_line,
city: client.city,
state: client.state,
zip_code: client.zip_code
};
const name = client.name;
const amount = parseFloat(client.amount).toFixed(2);
const address = {
recipient: name,
primary_line: client.primary_line,
secondary_line: client.secondary_line,
city: client.city,
state: client.state,
zip_code: client.zip_code
};

lob.usVerifications.verify(address)
.then((verifiedAddress) => {
return lob.letters.create({
description: `Automated Past Due Bill for ${name}`,
to: {
name: verifiedAddress.recipient,
address_line1: verifiedAddress.primary_line,
address_line2: verifiedAddress.secondary_line,
address_city: verifiedAddress.components.city,
address_state: verifiedAddress.components.state,
address_zip: verifiedAddress.components.zip_code,
address_country: 'US'
},
from: companyInfo,
file: letterTemplate,
merge_variables: {
date: moment().format('LL'),
name,
amountDue: amount
},
color: true
});
})
.then((letter) => {
console.log(`Successfully sent a letter to ${client.name}`);
client.letter_id = letter.id;
client.letter_url = letter.url;
converter.json2csv(client, (err2, csv) => {
if (err2) {
throw err2;
}
fs.write(successFd, csv);
}, { PREPEND_HEADER: false });
})
.catch(() => {
console.log(`Could not send letter to ${client.name}`);
converter.json2csv(client, (err2, csv) => {
if (err2) {
throw err2;
}
fs.write(errorFd, csv);
}, { PREPEND_HEADER: false });
lob.usVerifications.verify(address)
.then((verifiedAddress) => {
return lob.letters.create({
description: `Automated Past Due Bill for ${name}`,
to: {
name: verifiedAddress.recipient,
address_line1: verifiedAddress.primary_line,
address_line2: verifiedAddress.secondary_line,
address_city: verifiedAddress.components.city,
address_state: verifiedAddress.components.state,
address_zip: verifiedAddress.components.zip_code,
address_country: 'US'
},
from: companyInfo,
file: letterTemplate,
merge_variables: {
date: moment().format('LL'),
name,
amountDue: amount
},
color: true
});
});

})
.then((letter) => {
console.log(`Successfully sent a letter to ${client.name}`);
client.letter_id = letter.id;
client.letter_url = letter.url;
converter.json2csv(client, { prependHeader: false })
.then((csv) => fs.writeSync(successFd, `${csv }\n`))
.catch((err2) => {
console.error('Error writing to success file:', err2);
});
})
.catch(() => {
console.log(`Could not send letter to ${client.name}`);
converter.json2csv(client, { prependHeader: false })
.then((csv) => fs.writeSync(errorFd, `${csv }\n`))
.catch((err2) => {
console.error('Error writing to error file:', err2);
});
});
});

inputFile.pipe(parser);
parser.on('error', (err) => {
console.error('CSV parse error:', err);
});
Loading
Loading