npm package: @ideadesignmedia/helpers
Description: A small but opinionated Node.js utility belt from Idea Design Media. It covers stream helpers, compression, filesystem shortcuts, HTTP helpers, collection utilities, numeric helpers, and quick validators. The library is written in CommonJS but ships with 
Author: ideadesignmedia
Latest version: 1.0.18

﻿# @ideadesignmedia/helpers

A small but opinionated Node.js utility belt from Idea Design Media. It covers stream helpers, compression, filesystem shortcuts, HTTP helpers, collection utilities, numeric helpers, and quick validators. The library is written in CommonJS but ships with full TypeScript declarations.

## Installation

```bash
npm install @ideadesignmedia/helpers
# or
yarn add @ideadesignmedia/helpers
```

## Usage

### CommonJS

```js
const helpers = require("@ideadesignmedia/helpers");

const { gzip, readFile, filter } = helpers;
```

### ES Modules / TypeScript

```ts
import helpers, { gzip, type Helpers } from "@ideadesignmedia/helpers";

await gzip("./logs/today.txt", "./logs/today.txt.gz");
```

> Note: To use the default import from TypeScript enable `esModuleInterop` (or `allowSyntheticDefaultImports`) in your `tsconfig`. Otherwise use `import helpers = require("@ideadesignmedia/helpers")`.

## TypeScript Support

The package now includes a hand-written `index.d.ts` file that mirrors the runtime API. Highlights:

- Strongly typed `FilterDescriptor`, `SortDescriptor`, and `FilterMode` interfaces for the dynamic filtering helpers.
- Overloads for functions such as `writeFile`, `compare`, and `timeout` to reflect their different behaviours.
- Full typings for Node.js primitives like `BufferingTransform`, `RequestOptions`, and HTTP headers.
- Namespace-style types (`Helpers.FilterDescriptor`, `Helpers.SortDescriptor`, etc.) that stay in sync with the runtime exports.

## API Reference

### Streams & Compression

- **`BufferingTransform(options?)`** - Transform stream that buffers up to `capacity` chunks before releasing them. Handy when a downstream consumer needs async setup time. Accepts all Node `TransformOptions` plus `capacity` (default `3`).
  ```js
  const { pipeline } = require("stream");
  const { BufferingTransform } = require("@ideadesignmedia/helpers");

  pipeline(source, new BufferingTransform({ capacity: 5 }), destination, console.error);
  ```
- **`gzip(file, dest)`** - Pipes `file` through gzip compression and writes to `dest`. Resolves with the destination path.
- **`unzipGzip(file, dest)`** - Inverse of `gzip`, inflating a `.gz` file into `dest`.
- **`unzip(input, output)`** - Uses `extract-zip` to unpack archives. Resolves with the absolute output directory.
- **`zip(input, outputPath, glob?)`** - Creates a zip archive using `archiver`. Provide either a directory path or a glob pattern. Optional `glob` settings are forwarded to `archiver.glob`.

### Filesystem & Serialization

- **`readFile(file)`** - Async file read. Parses `.json` files before resolving, otherwise returns the raw `Buffer`.
- **`writeFile(path, data, readBack?)`** - Writes strings, buffers, or objects (auto JSON stringification). When `readBack` is `true`, resolves with the result of `readFile`; otherwise resolves to `true`.
- **`copyDir(source, destination, callback)`** - Recursive directory copy that mirrors the folder structure before invoking the callback.
- **`jsonl(array)`** - Serialises an array of objects into JSON Lines (newline-delimited JSON) format.

### Networking

- **`download(link, destination, options?, timeout?)`** - Streams an HTTP(S) response to disk. Optional request options and timeout in milliseconds.
- **`upload(filepath, url, headers?, method?, options?)`** - Pushes a local file to an HTTP endpoint, setting `Content-Type` and `Content-Length` automatically. Resolves with parsed JSON.
- **`request(url, options?, body?)`** - Convenience wrapper around `http.request` or `https.request`. Resolves with parsed JSON when possible or the raw response string otherwise.

### Timing & Control Flow

- **`timeout(callback, ms, args?)`** - Awaitable wrapper over `setTimeout` that safely handles extremely large delays by chunking them. Resolves with either the callback result or the native timeout handle.
- **`compare(a, b)`** - Deep comparison helper. Supports dates, arrays, objects, and even functional comparators (`compare(fn, value)` runs the predicate).

### Collections & Objects

- **`filter(data, filters)`** - Multi-purpose filtering engine. Each filter descriptor looks like:
  ```ts
  const filters: Helpers.FilterDescriptor<User>[] = [
    {
      name: "age",
      type: "number",
      mode: { name: "gte", value: 18 }
    },
    {
      name: "tags",
      type: "array",
      mode: { name: "includes", value: "pro" }
    }
  ];
  const adults = helpers.filter(users, filters);
  ```
  Supports string, number, array, object, and date comparisons, nested comparisons via `mode.compare` (`"or"`, `"not"`, etc.), and optional match limits via `count`.
- **`sort(data, fields)`** - Multi-level sorter. Each descriptor has `name`, optional `type`, and `direction` (`true` for descending). Note: sorts happen in place.
- **`search(value, items, indexes)`** - Builds buckets of matching records keyed by the field that matched.
- **`swap(array, a, b)`** - Returns a shallow-copied array with two indices swapped.
- **`insert(array, from, to)`** - Moves one element from index `from` to `to`. The original array is mutated because it relies on `splice` -- clone first if you need immutability.
- **`index(array, page, size)`** - Simple pagination helper returning the slice for the requested page.
- **`compareArrays(next, prev)`** - Returns `{ added, removed }` diffs between two arrays.
- **`filterKeys(obj, keys)`** - Omits provided keys from an object, returning a shallow clone.

### Numbers & Math

- **`parseNumber(value)`** - Safe `parseFloat` wrapper that falls back to `0`.
- **`sum(values)`** - Adds numeric or numeric-string values together.
- **`average(values)`** - Arithmetic mean helper.
- **`movingAverage(values, days)`** - Simple moving average over the first `days` entries.
- **`EMA(values, days)`** - Exponential moving average using the smoothing constant `2 / (days + 1)`.
- **`standardDeviation(values)`** - Sample standard deviation (note: mutates the input array because it calls `splice`).
- **`round(value)`** - Bankers-style rounding that prefers the nearest integer when `.5` is involved.
- **`currency(num)`** - Locale-aware formatting with two decimal places.

### Strings & Validation

- **`isEmail(value)`**, **`isAlphanumeric(value)`**, **`isLetters(value)`** - Regex validators.
- **`isDate(value)`** - Checks that a string can be parsed into a valid date.
- **`nameCompare(a, b)`** - Case-insensitive comparator that returns `-1`, `0`, or `1`; ideal for `Array.prototype.sort`.

### Security

- **`encrypt(plain, key?, buffer?)`** and **`decrypt(cipher, key?, buffer?)`** - AES-256-CTR helpers. The `buffer` argument must be a 16-character initialization vector string.

## Examples

A few quick patterns:

```ts
import helpers from "@ideadesignmedia/helpers";

// Filter and paginate a dataset
const filtered = helpers.filter(users, [
  { name: "status", type: "string", mode: { name: "equal", value: "active" } }
]);
const page = helpers.index(filtered, 0, 25);

// Stream upload a zipped directory
await helpers.zip("./dist", "./dist.zip");
await helpers.upload("./dist.zip", "https://api.example.com/upload", { Authorization: "Bearer token" });

// Serialize logs to JSONL and gzip them
const body = helpers.jsonl(logEntries);
await helpers.writeFile("./logs/run.jsonl", body);
await helpers.gzip("./logs/run.jsonl", "./logs/run.jsonl.gz");
```

## License

MIT (c) Idea Design Media