npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

sf-bulk2-query

v2.0.1

Published

Salesforce Bulk API 2.0 Query utility with modern OAuth 2.0 authentication

Readme

SF-Bulk2-Query

A lightweight, zero-dependency Node.js module for executing SOQL queries using the Salesforce Bulk API 2.0.

Built for Node.js 18+ using native fetch, crypto, and stream utilities.


[!WARNING] Salesforce Authentication Deprecation Notice

  • SOAP API login() is disabled by default in new orgs and will be permanently retired in Summer '27.
  • OAuth 2.0 Username-Password Flow (grant_type=password) is disabled by default in new Connected Apps and will be retired in Winter '27.

We strongly recommend migrating to the OAuth 2.0 Client Credentials Flow or JWT Bearer Flow. Legacy username-password logins remain supported for backward compatibility, but emit a deprecation warning at runtime.


Features

  • Modern OAuth 2.0 Support:
    • Client Credentials Flow (Recommended for server-to-server / ETL)
    • JWT Bearer Token Flow (RFC 7523 - Enterprise headless & CI/CD)
    • Direct Access Token Injection (AWS Lambda, Next.js, @salesforce/cli)
    • Refresh Token Flow (Long-running background workers)
    • PKCE & Web Server Flow Utilities (Interactive web/CLI apps)
    • Legacy Username-Password Flow (Retained with deprecation warning)
  • Automatic Token Refresh: Seamlessly refreshes expired session tokens on 401 Unauthorized during long-running bulk queries without failing the job.
  • Zero External Dependencies: Pure Node.js 18+ utilizing native fetch, node:crypto, and node:stream.
  • Flexible Results Handling: Retrieve Bulk API 2.0 results as a sequential stream, write directly to disk, or read as parsed data.

Installation

npm install sf-bulk2-query

Requirements: Node.js 18.0.0 or higher.


Quick Start (Client Credentials Flow - Recommended)

The Client Credentials Flow is the modern Salesforce standard for headless, backend, and ETL integrations via External Client Apps.

import SalesforceBulkApiClient from 'sf-bulk2-query';

const client = new SalesforceBulkApiClient({
  salesforceInstance: 'https://mycompany.my.salesforce.com', // Your My Domain URL
  apiVersion: '60.0',
  auth: {
    type: 'client_credentials',
    clientId: process.env.SF_CLIENT_ID,
    clientSecret: process.env.SF_CLIENT_SECRET,
  },
});

// Download accounts to a local CSV file
await client.bulkQueryToFile('SELECT Id, Name, Industry FROM Account', './accounts.csv');

Authentication Methods

1. OAuth 2.0 Client Credentials Flow

Best for server-to-server background services and automated batch jobs.

import SalesforceBulkApiClient from 'sf-bulk2-query';

const client = new SalesforceBulkApiClient({
  salesforceInstance: 'https://mycompany.my.salesforce.com',
  auth: {
    type: 'client_credentials',
    clientId: 'YOUR_EXTERNAL_CLIENT_APP_CLIENT_ID',
    clientSecret: 'YOUR_EXTERNAL_CLIENT_APP_CLIENT_SECRET',
    // Optional: useBasicAuth: true to pass credentials in the Authorization header
  },
});

await client.login();

Salesforce Setup: Create an External Client App in Setup > App Manager. Enable the Client Credentials Flow and assign a configured Run-As integration user with required permissions.


2. OAuth 2.0 JWT Bearer Token Flow (RFC 7523)

Best for enterprise automated integrations and CI/CD pipelines using digital certificates.

import fs from 'node:fs';
import SalesforceBulkApiClient from 'sf-bulk2-query';

const privateKey = fs.readFileSync('./salesforce.key', 'utf8');

const client = new SalesforceBulkApiClient({
  salesforceInstance: 'https://login.salesforce.com', // or test.salesforce.com or My Domain
  auth: {
    type: 'jwt_bearer',
    clientId: process.env.SF_CLIENT_ID,
    username: '[email protected]',
    privateKey: privateKey, // PEM string, Buffer, or use `privateKeyPath: './salesforce.key'`
  },
});

await client.login();

Salesforce Setup: In Setup > App Manager, create a Connected App or External Client App. Check "Use digital signatures", upload your public certificate (.crt), and set OAuth policy to "Admin approved users are pre-authorized".


3. Pre-Authenticated Access Token (Direct Session)

Best for serverless functions (AWS Lambda), web applications, or CLI scripts where the access token was already acquired externally (e.g. from @salesforce/cli).

import SalesforceBulkApiClient from 'sf-bulk2-query';

const client = new SalesforceBulkApiClient({
  auth: {
    type: 'access_token',
    accessToken: 'YOUR_ACCESS_TOKEN_OR_SESSION_ID',
    instanceUrl: 'https://mycompany.my.salesforce.com',
  },
});

// No need to call client.login()!
const stream = await client.bulkQueryAsStream('SELECT Id, Name FROM Contact');

You can also provide an onRefresh callback to dynamically re-fetch tokens:

const client = new SalesforceBulkApiClient({
  auth: {
    type: 'access_token',
    accessToken: currentToken,
    instanceUrl: 'https://mycompany.my.salesforce.com',
    onRefresh: async () => {
      const refreshed = await fetchTokenFromSecretManager();
      return { accessToken: refreshed.token };
    },
  },
});

4. OAuth 2.0 Refresh Token Flow

Best for long-running daemons that have already received an offline refresh token from an initial user authorization.

import SalesforceBulkApiClient from 'sf-bulk2-query';

const client = new SalesforceBulkApiClient({
  salesforceInstance: 'https://login.salesforce.com',
  auth: {
    type: 'refresh_token',
    clientId: process.env.SF_CLIENT_ID,
    clientSecret: process.env.SF_CLIENT_SECRET, // optional depending on app settings
    refreshToken: process.env.SF_REFRESH_TOKEN,
  },
});

await client.login();

5. Authorization Code Flow with PKCE Utilities

For web apps or CLI tools requiring user interaction, this package exports PKCE generation and token exchange helpers:

import {
  generatePkceChallenge,
  getAuthorizationUrl,
  exchangeCodeForTokens,
} from 'sf-bulk2-query';

// Step 1: Generate PKCE challenge
const { codeVerifier, codeChallenge } = generatePkceChallenge();

// Step 2: Build the authorization URL and redirect the user
const authUrl = getAuthorizationUrl({
  clientId: 'YOUR_CLIENT_ID',
  redirectUri: 'https://localhost:3000/callback',
  codeChallenge: codeChallenge,
});
console.log('Open this URL to authorize:', authUrl);

// Step 3: In your callback handler, exchange code for tokens
const tokenResponse = await exchangeCodeForTokens({
  code: callbackCode,
  clientId: 'YOUR_CLIENT_ID',
  redirectUri: 'https://localhost:3000/callback',
  codeVerifier: codeVerifier,
});

// Step 4: Initialize client with returned session
const client = new SalesforceBulkApiClient({
  auth: {
    accessToken: tokenResponse.access_token,
    instanceUrl: tokenResponse.instance_url,
  },
});

6. Legacy Username & Password Flow (Deprecated)

Maintained for backwards compatibility. Will log a deprecation warning alerting you of Salesforce's Winter '27 retirement.

import SalesforceBulkApiClient, { SalesforceCredentials } from 'sf-bulk2-query';

const creds = new SalesforceCredentials(
  '[email protected]',
  'password',
  'security_token',
  'client_id',
  'client_secret'
);

const client = new SalesforceBulkApiClient('https://login.salesforce.com', '58.0', creds);
await client.login();

API Reference

Constructor

// Modern options-object signature:
const client = new SalesforceBulkApiClient(options);

// Legacy 3-argument signature:
const client = new SalesforceBulkApiClient(salesforceInstance, apiVersion, creds);

Options Object

  • salesforceInstance (string): Salesforce instance URL (e.g. 'https://login.salesforce.com' or 'https://mycompany.my.salesforce.com'). Defaults to 'https://login.salesforce.com'.
  • apiVersion (string): Salesforce Bulk API version (e.g. '60.0'). Defaults to '58.0'.
  • pollTime (number): Job polling interval in milliseconds. Defaults to 10000 (10 seconds).
  • auth (object): Authentication configuration (see examples above).

Methods

login([creds]): Promise<AuthResult>

Authenticates with Salesforce using the configured strategy. Not required if initialized with auth.type: 'access_token'.

bulkQueryAsStream(query, [options]): Promise<Readable>

Executes a SOQL query using Bulk API 2.0 and returns a readable stream emitting CSV chunks.

  • options.allRows (boolean): If true, queries deleted and archived records (queryAll).
  • options.pageSize (number): Chunk size for pulling results.

bulkQueryToFile(query, filename, [options]): Promise<void>

Executes a SOQL query and writes the complete CSV output to the specified local file path.

bulkQueryAsData(query, [options]): Promise<string>

Executes a SOQL query and buffers the full CSV result into a string in memory.

startBulkQuery(query, [allRows]): Promise<FetchResponse>

Starts a Bulk API 2.0 job and returns { status, statusText, headers, body }. body.id contains the Salesforce Job ID.

checkJobStatus(jobId): Promise<FetchResponse>

Checks the current processing state of a bulk job.

pollJobTillComplete(jobId, [pollTime]): Promise<string>

Polls until the job status reaches 'JobComplete', or throws if 'Failed' / 'Aborted'.


Running Tests

npm test

Runs all unit tests with Node.js's built-in test runner.


License

MIT