chore: add CI/CD workflows, pin deps, TSDoc and contributing docs - #21
Merged
Conversation
Foundation - fix TS build error in FileUtils (fs.rmdirSync recursive removed -> fs.rmSync) - pin uuid ^11 and @paralleldrive/cuid2 ^2 (v14/v3 are ESM-only and break the CommonJS build + jest); native require() of the published bundle now works Dependencies / tooling - TypeScript 5.6 -> 5.9.3, target es2022, engines node>=18 - align pino peerDependency, drop @types/uuid (uuid ships its own types) - remove stale package-lock.json (bun is the package manager) and legacy .eslintrc.js Bug fixes - UUIDUtils.uuidV5Generate is now deterministic (stable URL namespace) - StringUtils: escape regex in countOccurrences/replaceOccurrences, drop dead hack - HashUtils.bcryptRandomString uses crypto.randomBytes instead of Math.random - fix CryptUtils JSDoc referencing HashUtils; remove dead snowflake.config.ts - attach Error cause to all rethrows (clears 54 eslint errors) Tests - add unit tests for cache, event, retry, file, log, http, storage (+130 tests) - remove duplicate snowflake.consolidated spec Docs & examples - add 21 per-service docs, rewrite docs/index.md, fix broken links, TS badge - clean examples/README, add basic examples, de-duplicate usage-example.js i18n: standardize comments, docs, test descriptions and identifiers to English bump: 12.0.1 -> 13.0.0
- add unit tests for previously-uncovered modules: errors/*, utils/cache & lazy-loader, cuid, gitflow-test, loggers (pino/winston/console), axios-client, s3-storage provider (mocked) - extend existing specs to cover error/catch branches and edge cases across validation (CPF/CNPJ/RG), crypt (rsa/ecc/chacha20/rc4), hash, file, storage, http, jwt, retry, snowflake, sort, benchmark, cache, object, queue, date - harden flaky randomFloatInRange assertion (rounding may reach max) - raise jest coverageThreshold 50% -> 95% lines/statements, 95% funcs, 88% branches
Errors
- BaseError/HttpError/StorageError/ValidationError now accept an options
object with `cause` and chain it to the native Error
- route every service/client/provider throw through the typed errors:
input guards -> ValidationError; file/storage -> StorageError;
http -> HttpError; other operational failures -> BaseError with a domain
code (CRYPTO_ERROR, HASH_ERROR, JWT_ERROR, SNOWFLAKE_ERROR, ...). Messages
preserved; RetryUtils still rethrows the caller's original error.
Signatures (BREAKING)
- CryptUtils, FileUtils and SortUtils now take a single destructured object
argument, matching the rest of the library (e.g. SortUtils.quickSort({ array }),
CryptUtils.aesEncrypt({ data, secretKey, iv }), FileUtils.writeFile({ filePath, data }))
Names (BREAKING)
- remove duplicate NumberUtils.isOdd (use isValidOdd) and NumberUtils.isValidPrime
(use MathUtils.isValidPrime)
Updated all tests, per-service docs and examples (incl. usage-example.js) to the
new API. tsc clean, 1182 tests green, coverage ~98% lines.
…(BREAKING)
Security / crypto (BREAKING)
- AES-256-CBC -> AES-256-GCM (authenticated; returns { encryptedData, iv, authTag })
- RSA encrypt/decrypt -> OAEP(sha256); ChaCha20 -> chacha20-poly1305 (AEAD)
- ECC default curve -> prime256v1; validate AES key by byte length
- remove RC4 entirely
- JWT: verify enforces an algorithms allowlist (default HS256, never 'none');
generate defaults expiresIn '1h' + pins HS256; refresh guards + allowlist;
decode/isExpired/getExpirationTime documented as unverified
- BaseError.toJSON no longer leaks stack by default
- LocalStorageProvider path-traversal confinement; listFiles depth bound
- ObjectUtils prototype-pollution guards (deepMerge, unflattenObject)
- RetryUtils backoff capped (maxDelay) + optional jitter
Correctness
- Snowflake: persist per-epoch instance (fixes same-ms id collisions); add epoch
to SnowflakeComponents; strict digit guard in decode
- S3 listFiles pagination (no 1000-key cap); fileExists 404 metadata; region URL
- native HttpClient: Content-Type on JSON, timeout rejection; documented contract
- ConvertUtils.value number->integer + null handling + unknown typing
- DateUtils detects invalid DateTime/timezone; deepMerge no longer drops source
- LazyLoader resets on factory rejection; Cache(null) no longer expires instantly
- cache/queue falsy-zero fixes; queue enqueue throws QueueFullError when full
API standardization (BREAKING)
- rename property predicates: NumberUtils isValidEven/Odd -> isEven/isOdd,
MathUtils isValidPrime -> isPrime, StringUtils isValidPalindrome -> isPalindrome
- capitalizeFirstLetter keeps original case of the tail
- add HttpError factories (409/422/429/502/503); ValidationError.invalidType detects array/null
- remove GitFlowTestUtils from the public API
- widen validation guards (ValidationError) across services; type `any` -> `unknown`
at key boundaries (Convert.value, isNumber, readJsonFile, RequestUtils)
test: fix flaky network mock (drop `virtual:true` on installed axios/aws-sdk mocks)
Tests/docs/examples updated. tsc clean, 1270 tests green, coverage ~98% lines.
- add root CLAUDE.md: architecture, conventions, dependency & security constraints, and dev workflow as an AI/contributor context index - reorganize docs/ into one folder per module (docs/<module>/README.md), preserving git history via renames - add docs/README.md master index (modules grouped by category) - add new module docs: errors, lazy-loader - rewrite root README.md for v13: features, conventions, module table, configurable services, error handling, security, doc links - delete community/meta docs (CODE_OF_CONDUCT, CONTRIBUTING, SECURITY, COMMIT_CONVENTION, LICENSE_INFO, STRUCTURE, compatibility, configuration, examples, index, log-service-detailed) and the .github/ folder - fix stale queue doc (enqueue now throws QueueFullError) and a dead link - tidy .npmignore (publish stays dist + README + LICENSE + package.json)
Found via an external consumer smoke-test (utils-dumb) exercising every module against the packed tarball: - SortUtils.timSort now clones its input (like every other sort) and validates the argument, instead of sorting the caller's array in place - SnowflakeUtils.isValidSnowflake now accepts the bigint returned by generate() (was string-only, so you could not validate your own ids); rejects negative bigints Adds regression tests for both.
SortUtils: every sort accepts `{ array, inPlace? }`. Default (false) keeps the
current behavior — returns a new sorted array, input untouched. `inPlace: true`
sorts the caller's array in place and returns the same reference (saves the
defensive copy / O(n) memory for large arrays). Fully additive.
Standards/contract tests (line coverage doesn't catch these):
- parametrized immutability test across all 18 sorts (default mode must not
mutate the caller's array) + inPlace mutation tests
- public-surface test: asserts every module/service/error class is exported
from the package root, and that removed scaffolding (GitFlowTestUtils) is not
- contract integration test: exercises one representative method per module
end to end + typed-error invariant (mirrors the external utils-dumb consumer,
but runs in CI)
Audit of every data-transformation method confirmed all of ArrayUtils and ObjectUtils already leave the caller's input untouched — except ObjectUtils.unflattenObject, which mutated the input object as an undocumented side effect. It now returns a deep copy by default (input untouched) and accepts `inPlace: true` to mutate in place, matching the SortUtils convention. deepFreeze keeps its intentional in-place behavior (Object.freeze semantics) and now documents it explicitly. Adds a parametrized immutability invariant test covering ArrayUtils/ObjectUtils transformations so a re-introduced mutation is caught in CI.
- CLAUDE.md: add a "four kinds of exports" mental model; document the non-mutating-by-default / inPlace convention and the deepFreeze exception; add a Testing & quality section (invariant guards: public-surface, contract, immutability; the external utils-dumb consumer and how to run it; the virtual-mock pitfall); note there is no CI workflow in-repo - docs/README.md: expand the conventions recap (mutability, is*/isValid*) and link to CLAUDE.md for architecture
Method-by-method audit of docs/<module>/README.md against the source: - array: remove phantom methods (chunk/union/difference); add findSubset/isSubset - cache: add the missing Cache<T> class section (constructor TTL, getOrCompute, …) - sort: add inPlace? to all 18 method signatures + per-method mutability note - snowflake: decode includes epoch; isValidSnowflake accepts bigint - retry: document maxDelay + jitter options - http/storage/file/request: native-client Content-Type/timeout, path confinement + S3 pagination, readJsonFile<T>, HttpRequestLike + spoofing note - crypt/hash/jwt: add the ValidationError/BaseError(code) throw notes
Additive opt-in mutation (default false = clone, returns new value) so callers can trade the defensive copy for in-place mutation when they own the input: - ArrayUtils: removeDuplicates, intersect, flatten, shuffle, sort - ObjectUtils: deepMerge, pick, omit, removeUndefined, removeNull (unflattenObject already had it; sorts already had it) inPlace:true mutates the caller's input and returns the same reference; default behavior is unchanged. Methods that produce a different structure (groupBy, flattenObject, invert), read-only checks, and deepClone get no inPlace (no coherent meaning); deepFreeze stays intentionally in-place. Documented in each module's "Mutability" section. Tests: per-method inPlace tests + a parametrized inPlace invariant (opt-in mutation returns the same reference) mirroring the immutability invariant.
- .github/workflows/ci.yml: on PR + push to main — bun type-check, lint, test:ci (coverage gate), build, and a gitleaks secret scan - .github/workflows/pr-version.yml: on PR open/sync/reopen — bump version + CHANGELOG from conventional commits (commit-and-tag-version, .versionrc.json) and commit "chore(release): vX.Y.Z" back to the PR branch before merge; bumps once per PR, same-repo PRs only - .gitleaks.toml: extend default ruleset + custom generic/AWS/GCP API-key rules; allowlist test fixtures/examples/docs (sample values, not real secrets) - add commit-and-tag-version devDep (maintained standard-version successor); point version scripts at it - CLAUDE.md: document the pipeline
…line - .github/workflows/release.yml: on push to main, tag vX.Y.Z (if untagged), publish to npm (--provenance, needs NPM_TOKEN), and create a GitHub release; the tag anchors the next PR's tag-based version computation - .gitleaks.toml: drop the custom rules (the built-in defaults already cover generic/AWS/GCP and the custom GCP regex was too long); keep useDefault + the fixtures allowlist - package.json: reset version to the last released 12.0.1 so the PR auto-version computes a clean 13.0.0 (do not hand-edit the version ahead of the bump) - CLAUDE.md: document the full release flow and required repo settings
Add TSDoc blocks to the 17 previously undocumented public members in WinstonLogger, ConsoleLogger, PinoLogger, AxiosClient, and the module- scoped isObject helper — completing 100% TSDoc coverage across src/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Remove ^ and ~ specifiers from every dep and devDep so that installations are fully reproducible without relying on the lockfile. Update peerDependencies to match the exact installed versions as well. Upgrade to the actual resolved versions: uuid 11.1.1, @paralleldrive/cuid2 2.3.1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document the monthly update cadence, the 3-month version-lag rule for supply-chain protection, the step-by-step update workflow, and the CJS compatibility requirements — alongside commit conventions, branch naming, PR process, and the v13 API contract. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
# Conflicts: # .github/workflows/ci.yml # .github/workflows/release.yml # CLAUDE.md # README.md # bun.lock # package.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
These commits were authored locally after PR #20 was opened and never pushed — so they were left out of the merge. This PR brings them to
main..github/workflows/):ci.yml(type-check → lint → test with 95% coverage gate → build → gitleaks secret scan),pr-version.yml(auto-bumps version on PR open/sync viacommit-and-tag-version),release.yml(tagsvX.Y.Z, publishes to npm with provenance, creates GitHub release on push tomain).gitleaks.toml: full built-in ruleset (useDefault = true); allowliststests/,examples/,docs/,usage-example.js,CHANGELOG.md,bun.lockpackage.jsonversion set to12.0.1so thepr-versionworkflow computes a clean13.0.0bump^/~specifiers removed fromdependencies,devDependencies,peerDependenciesandoverrides— every version is now an exact string matching what is installed inbun.lock/** */blocks to the 17 previously undocumented members inConsoleLogger,PinoLogger,WinstonLogger,AxiosClientand theisObjectmodule helperREADME.md: commit conventions, branch naming, PR process, v13 API contract, mutability rules; monthly update cadence, 3-month version-lag rule for supply-chain protection, step-by-step update workflow, CJS compatibility checklistNote on CI triggering
This PR will not trigger the CI workflows on open (same reason as PR #20 — GitHub only runs workflows already present on
main). After merge,mainwill have all three workflows and every future PR will have full CI + auto-versioning.Required repo settings before merge
pr-version.ymlto push the version bump commit back to the PR branchNPM_TOKEN— needed byrelease.ymlto publish to npmTest plan
release.ymlruns on push tomain, tagsv13.0.0, publishes to npm, creates GitHub releaseci.ymlandpr-version.ymlboth triggerGenerated with Claude Code