@kjangid/array-async-tools
v1.0.1
Published
Object, array, and async utilities for transforming data, managing collections, and controlling asynchronous workflows.
Maintainers
Readme
@kjangid/array-async-tools
A production-grade, zero-runtime-dependency TypeScript utility library and standalone CLI toolkit designed for high-performance data transformations, collection manipulation, and robust asynchronous control flow.
Built natively for Node.js (>= 18.0.0), Modern Browsers, Bun, Deno, and Cloudflare Workers with dual ESM (.mjs) and CommonJS (.cjs) output, tree-shakeable subpath exports, and comprehensive prototype pollution defenses.
Table of Contents
Key Features
- Zero Runtime Dependencies: Every single utility is implemented from first principles. No hidden sub-dependencies, no supply-chain bloat.
- Dual ESM / CommonJS Architecture: Seamless integration in both modern native ESM (
import) and legacy CommonJS (require) runtimes with exact TypeScript type definitions (.d.ts/.d.cts). - Security by Default: Defenses against prototype pollution attacks (
__proto__,constructor,prototype) across object cloning, diffing, grouping, and cleaning. - Universal Runtime Support: Fully functional across Node.js 18+, Bun, Deno, modern web browsers, and edge environments like Cloudflare Workers.
- Standalone CLI: High-performance unified binary (
oa-tools) and dedicated binary aliases (oa-clone,oa-diff,oa-clean,oa-chunk,oa-sort,oa-retry,oa-timeout) supporting stdin pipes and file arguments. - 100% Test Pass Rate: Thorough test suites with >96% statement and branch coverage via Vitest and V8 coverage (168 tests across 18 test files).
Tools & Utilities Overview
| # | Utility | Category | Description |
| --- | ------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | deepClone | Object | Independent deep copy of nested objects/arrays handling circular references, Maps, Sets, Dates, RegExps, TypedArrays, and Errors. |
| 2 | deepEqual | Object | Recursive structural equality comparator for complex graphs, circular structures, Maps, Sets, and binary buffers. |
| 3 | objectDiff | Object | Computes structural differences returning added, removed, and updated fields with flat dot-paths or nested hierarchies. |
| 4 | objectClean | Object | Immutable cleaner filtering nulls, undefineds, empty strings, empty arrays, empty objects, and NaNs. |
| 5 | chunk | Array | Partitions arrays into uniform fixed-size batches for pagination, batch requests, and worker dispatching. |
| 6 | groupBy / groupByMap | Array | Groups elements by key or callback into a prototype-free record (Object.create(null)) or an ES6 Map. |
| 7 | uniqueArray | Array | Removes duplicates while preserving order, supporting primitive fast-paths, key selectors, or deep structural equality. |
| 8 | smartSort | Array | Pure stable sorting supporting multi-field ordering, natural string collation (e.g. v2 before v10), dates, and null placement. |
| 9 | debounce | Async | Delays callback execution until after a quiet period, supporting leading/trailing edges, maxWait guarantees, cancel(), and flush(). |
| 10 | throttle | Async | Regulates execution frequency to at most once per time window with configurable leading/trailing edges. |
| 11 | retry | Async | Automatically retries failed async tasks with exponential/linear backoff, full/half jitter, error filters, and AbortSignal support. |
| 12 | promiseTimeout | Async | Enforces execution deadlines, rejecting with TimeoutError or triggering fallback handlers with automated timer teardown. |
| 13 | AsyncQueue | Async | Concurrency-limited worker queue supporting priority scheduling, per-task timeouts, pause/resume, and lifecycle hooks (onIdle). |
Installation
# Using npm
npm install @kjangid/array-async-tools
# Using pnpm
pnpm add @kjangid/array-async-tools
# Using yarn
yarn add @kjangid/array-async-tools
# Using bun
bun add @kjangid/array-async-toolsFor global CLI usage:
npm install -g @kjangid/array-async-toolsQuick Start
import {
deepClone,
deepEqual,
objectDiff,
objectClean,
chunk,
groupBy,
uniqueArray,
smartSort,
debounce,
throttle,
retry,
promiseTimeout,
AsyncQueue,
} from "@kjangid/array-async-tools";
// 1. Safe Deep Cloning (Handles circular references)
const graph: any = { name: "Node A" };
graph.self = graph;
const clonedGraph = deepClone(graph);
console.log(clonedGraph.self === clonedGraph); // true (independent clone)
// 2. Structural Deep Equality
console.log(deepEqual({ a: [1, 2], d: new Date(0) }, { a: [1, 2], d: new Date(0) })); // true
// 3. Object Diffing
const before = { id: 1, config: { theme: "light", debug: false } };
const after = { id: 1, config: { theme: "dark", port: 8080 } };
const diff = objectDiff(before, after);
// diff.updated -> { 'config.theme': { before: 'light', after: 'dark' } }
// diff.removed -> { 'config.debug': false }
// diff.added -> { 'config.port': 8080 }
// 4. Object Cleaning
const dirty = { name: "Alice", bio: "", role: null, flags: [] };
const clean = objectClean(dirty, { emptyStrings: true, emptyArrays: true });
// { name: 'Alice' }
// 5. Array Chunking
const batches = chunk([1, 2, 3, 4, 5], 2);
// [[1, 2], [3, 4], [5]]
// 6. Resilient Async Retries
const data = await retry(
async ({ attempt }) => {
return await fetchUserData(attempt);
},
{ retries: 3, backoff: "exponential", factor: 2 },
);Subpath Imports (Tree-Shaking)
To minimize bundle size in web applications, each utility can be imported individually via dedicated subpaths:
import { deepClone } from "@kjangid/array-async-tools/deep-clone";
import { deepEqual } from "@kjangid/array-async-tools/deep-equal";
import { objectDiff } from "@kjangid/array-async-tools/object-diff";
import { objectClean } from "@kjangid/array-async-tools/object-clean";
import { chunk } from "@kjangid/array-async-tools/chunk";
import { groupBy } from "@kjangid/array-async-tools/group-by";
import { uniqueArray } from "@kjangid/array-async-tools/unique-array";
import { smartSort } from "@kjangid/array-async-tools/smart-sort";
import { debounce } from "@kjangid/array-async-tools/debounce";
import { throttle } from "@kjangid/array-async-tools/throttle";
import { retry } from "@kjangid/array-async-tools/retry";
import { promiseTimeout } from "@kjangid/array-async-tools/promise-timeout";
import { AsyncQueue } from "@kjangid/array-async-tools/async-queue";CLI Toolkit
The package provides a unified binary oa-tools along with dedicated binary aliases for standard command-line data processing:
# Display CLI help
oa-tools --help
# Piped stdin: chunk array into batches of 2
cat users.json | oa-tools chunk --size 2
# Compare two JSON files
oa-tools equal file1.json file2.json
# View JSON structural diff (exits with code 1 if changed with --check)
oa-tools diff file1.json file2.json --check
# Clean empty fields from payload
cat input.json | oa-tools clean --empty-strings --empty-objects
# Sort dataset naturally by a property
oa-tools sort records.json --by version --order asc
# Run an external command with retry logic
oa-tools retry --retries 3 --delay 2000 -- curl -f https://api.example.com/health
# Run an external command with a timeout deadline (milliseconds)
oa-tools timeout --ms 5000 -- npm testExit Codes
0: Success (or identical structures).1: Operation failure / Difference detected with--check/ Task execution failed.2: CLI usage syntax error / Missing required arguments.
Security Architecture
- Prototype Pollution Protection:
- Traversal logic in
deepClone,objectClean, andobjectDiffexplicitly skips__proto__,prototype, andconstructorproperties. groupByreturns prototype-less dictionaries created viaObject.create(null)so grouping on attacker-controlled keys (e.g.'__proto__') cannot poison Object prototypes.
- Traversal logic in
- Safe Object Creation:
- Exported
createSafeRecord()andsafeAssign()utilities ensure zero prototype pollution across object transformations.
- Exported
- Timer Teardown:
promiseTimeout,retry,debounce, andthrottleactively remove listeners and clear pending timers immediately on resolution, rejection, or abort, eliminating event-loop memory leaks.
NPM Scripts
| Script | Command | Purpose |
| ---------------- | ----------------------------------------------- | ----------------------------------------------- |
| lint | tsc --noEmit | Strict TypeScript typechecking as linter gate. |
| build | tsup | Compiles dual ESM/CJS and .d.ts declarations. |
| test | vitest run | Executes all 18 test suites once. |
| test:watch | vitest | Runs Vitest in interactive watch mode. |
| test:coverage | vitest run --coverage | Generates V8 code coverage reports. |
| typecheck | tsc --noEmit | Strict TypeScript compiler validation. |
| bump:patch | npm version patch | Increments patch version & creates git tag. |
| bump:minor | npm version minor | Increments minor version & creates git tag. |
| bump:major | npm version major | Increments major version & creates git tag. |
| prepublishOnly | npm run lint && npm run test && npm run build | Automated pre-release verification pipeline. |
| publish:dry | npm publish --dry-run | Verifies tarball contents without publishing. |
Release & Publishing (CI/CD)
This repository includes a production-ready, completely free CI/CD pipeline using GitHub Actions, npm Trusted Publishing (OIDC), and GitHub Releases. No static secrets (NPM_TOKEN) are stored in GitHub.
Release Workflow
npm version patch | minor | major
↓
git push --follow-tags
↓
GitHub tag v1.2.3
↓
GitHub Actions
↓
npm ci → lint → test → build → verify tag
↓
npm publish (OIDC + Provenance)
↓
GitHub ReleaseBump Version: Never manually edit version in
package.json. Usenpm version:npm version patch # Bug fixes (e.g. 1.0.0 -> 1.0.1) # or npm version minor # New backwards-compatible features (1.0.0 -> 1.1.0) # or npm version major # Breaking changes (1.0.0 -> 2.0.0)This automatically updates
package.json, creates a Git commit, and creates a signed Git tagvX.Y.Z.Push Commit & Tag:
git push --follow-tagsAutomated Publishing:
- The
.github/workflows/release.ymlworkflow triggers on thev*tag. - Verifies the Git tag matches
package.jsonversion. - Runs
npm ci→npm run lint→npm test→npm run build. - Publishes to npm using OpenID Connect (OIDC) with provenance attestation.
- Automatically drafts and publishes a GitHub Release with auto-generated release notes.
- The
One-Time npm Trusted Publishing Configuration
Before your first release, configure npmjs.com to trust GitHub Actions:
- Log in to npmjs.com.
- Navigate to your package settings:
https://www.npmjs.com/package/@kjangid/array-async-tools/access(or go to Account Settings → Trusted Publishers if creating the package for the first time). - Under Trusted Publishers, click "Add Trusted Publisher" and select "GitHub Actions".
- Configure the publisher:
- GitHub Organization / User:
kajangid - Repository:
ObjectArrayAsyncTools - Workflow filename:
release.yml - Environment: (leave blank)
- GitHub Organization / User:
- Click "Add Publisher".
Once configured, releases occur automatically via Git tags without managing or rotating API tokens.
Documentation Index
- Architecture Guide: Runtime design, memory models, module decomposition, and bundling design.
- Installation Guide: Setup instructions for Node, Bun, Deno, Browsers, and Cloudflare Workers.
- Features Reference: Comprehensive API reference, type signatures, and real-world code examples for all 13 tools.
- Limitations & Boundaries: Edge cases, recursion boundaries, memory limits, and performance considerations.
- Testing & Quality Guide: Test matrix, coverage reports, and security attack test cases.
- Deployment Guide: Step-by-step npm release workflow, automated CI/CD, and publishing checklist.
License
MIT © Karan Jangid
