@ix-xs/node-comfort 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +150 -0
  2. package/README.md +32 -30
  3. package/index.js +3 -3
  4. package/package.json +8 -7
  5. package/src/Arr.js +222 -58
  6. package/src/Async.js +322 -90
  7. package/src/Cache.js +148 -44
  8. package/src/Checker.js +257 -26
  9. package/src/Cli.js +404 -145
  10. package/src/Color.js +224 -83
  11. package/src/Crypto.js +481 -106
  12. package/src/Emitter.js +104 -37
  13. package/src/Env.js +176 -42
  14. package/src/FS.js +203 -60
  15. package/src/Func.js +226 -76
  16. package/src/Http.js +311 -149
  17. package/src/Id.js +281 -96
  18. package/src/Logger.js +302 -78
  19. package/src/Num.js +182 -60
  20. package/src/Obj.js +340 -125
  21. package/src/SQLite.js +426 -105
  22. package/src/Schema.js +602 -87
  23. package/src/Str.js +316 -86
  24. package/src/Sys.js +197 -54
  25. package/src/Time.js +572 -317
  26. package/src/Utils.js +62 -41
  27. package/src/errors.js +54 -11
  28. package/src/internal/shared.js +415 -0
  29. package/types/index.d.ts +59 -17
  30. package/types/src/Arr.d.ts +78 -0
  31. package/types/src/Arr.d.ts.map +1 -1
  32. package/types/src/Async.d.ts +52 -1
  33. package/types/src/Async.d.ts.map +1 -1
  34. package/types/src/Cache.d.ts +33 -7
  35. package/types/src/Cache.d.ts.map +1 -1
  36. package/types/src/Checker.d.ts +155 -2
  37. package/types/src/Checker.d.ts.map +1 -1
  38. package/types/src/Cli.d.ts +97 -15
  39. package/types/src/Cli.d.ts.map +1 -1
  40. package/types/src/Color.d.ts +7 -1
  41. package/types/src/Color.d.ts.map +1 -1
  42. package/types/src/Crypto.d.ts +99 -13
  43. package/types/src/Crypto.d.ts.map +1 -1
  44. package/types/src/Emitter.d.ts +36 -17
  45. package/types/src/Emitter.d.ts.map +1 -1
  46. package/types/src/Env.d.ts +31 -1
  47. package/types/src/Env.d.ts.map +1 -1
  48. package/types/src/FS.d.ts +36 -5
  49. package/types/src/FS.d.ts.map +1 -1
  50. package/types/src/Func.d.ts +147 -19
  51. package/types/src/Func.d.ts.map +1 -1
  52. package/types/src/Http.d.ts +113 -43
  53. package/types/src/Http.d.ts.map +1 -1
  54. package/types/src/Id.d.ts +60 -8
  55. package/types/src/Id.d.ts.map +1 -1
  56. package/types/src/Logger.d.ts +53 -2
  57. package/types/src/Logger.d.ts.map +1 -1
  58. package/types/src/Num.d.ts +48 -7
  59. package/types/src/Num.d.ts.map +1 -1
  60. package/types/src/Obj.d.ts +67 -4
  61. package/types/src/Obj.d.ts.map +1 -1
  62. package/types/src/SQLite.d.ts +123 -14
  63. package/types/src/SQLite.d.ts.map +1 -1
  64. package/types/src/Schema.d.ts +256 -7
  65. package/types/src/Schema.d.ts.map +1 -1
  66. package/types/src/Str.d.ts +49 -1
  67. package/types/src/Str.d.ts.map +1 -1
  68. package/types/src/Sys.d.ts +51 -6
  69. package/types/src/Sys.d.ts.map +1 -1
  70. package/types/src/Time.d.ts +130 -34
  71. package/types/src/Time.d.ts.map +1 -1
  72. package/types/src/Utils.d.ts +15 -11
  73. package/types/src/Utils.d.ts.map +1 -1
  74. package/types/src/errors.d.ts +27 -3
  75. package/types/src/errors.d.ts.map +1 -1
  76. package/types/src/internal/shared.d.ts +123 -0
  77. package/types/src/internal/shared.d.ts.map +1 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,155 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
5
5
  [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [2.1.0] - 2026-10-12
8
+
9
+ Every module was read again, line by line. The result: about sixty new functions and options, a hot path
10
+ that is several times faster almost everywhere, a long list of edge cases fixed, and a new documentation
11
+ website. Nothing has to change in a project that used 2.0 the documented way. The few behaviours that
12
+ did change are listed under "Changed".
13
+
14
+ ### Added
15
+
16
+ - **logger**: `redact` hides the keys you name in everything that is logged, `onLog` receives each entry
17
+ (`LogEntry`) to forward it to another service, and `DEBUG=db,http:*` chooses which scopes print their
18
+ debug lines.
19
+ - **fs**: `fs.findUp()` (also `nc.findUp()`) walks up the folders to find a file, `writeFile()` and
20
+ `writeJSON()` take `fsync` to wait for the disk, and watchers emit `"error"`.
21
+ - **checker**: `isHostname`, `isMACAddress`, `isIBAN`, `isE164`, `isObjectId`, `isULID`, `isDataURL`,
22
+ `isMimeType`, `isTimeZone`, `isLocale`, `isCron` and `isASCII`.
23
+ - **env**: `env.example()` writes a `.env.example` from your specification, and `load({ cascade })` reads
24
+ `.env`, `.env.local`, `.env.{mode}` and `.env.{mode}.local` in the usual order.
25
+ - **schema**: `pipe()`, `discriminatedUnion()`, `toJSONSchema()`, object `required()`, `merge()` and
26
+ `keyof()`, number `gt()`, `lt()` and `safe()`, string `date()`, `slug()`, `hex()`, `base64()`, `ulid()`,
27
+ `semver()` and `hostname()`. `safeParse()` gives the list of `issues` without building an error.
28
+ - **http**: `params` fills a path such as `"users/:id"`, `schema` validates the response and gives
29
+ `data` its type,
30
+ `cookies` lists every `Set-Cookie`, headers can be a `Headers` object or pairs, and retries take `jitter`
31
+ and text delays (`"2s"`).
32
+ - **SQLite**: filters and sorts on JSON paths (`"settings.theme"`), `paginate()`, `increment()`,
33
+ `onConflict` for `insert()` and `insertMany()`, `defaultExpression` for columns,
34
+ `transaction({ immediate })`, a `synchronous` option, and reads from views and temporary tables.
35
+ - **time**: `time.parse()` reads a date from text with a pattern, `isSame()`, `range()`, `fromUnix()`, the
36
+ `Do` and `z` tokens, and `formatDuration()` accepts text such as `"90m"`.
37
+ - **id**: `uuidv5()`, `objectId()` and `prefixed()`.
38
+ - **crypto**: `verifyHmac()` for webhook signatures, `generateKeyPair()`, and JSON Web Tokens signed with
39
+ RSA, ECDSA or Ed25519 keys (`RS256`, `PS256`, `ES256`, `EdDSA`...).
40
+ - **cli**: `cli.tree()`, `cli.spin()` runs a promise under a spinner, `args()` learns commands
41
+ (`commands`), `env` fallbacks, `examples` in the help and `choices` for numbers. Tables accept cells of
42
+ several lines. Menus understand Home, End, Page Up, Page Down and Escape.
43
+ - **color**: `color.truncate()` cuts colored text to a width without breaking its colors.
44
+ - **sys**: `shutdown()`, `freePort()` and `localIP()`.
45
+ - **func**: `batch()` groups calls into one, `dedupe()` shares a call that is already running, and
46
+ `pipeAsync()`.
47
+ - **async**: `parallel()`, `rateLimit()` and `abortable()`.
48
+ - **Cache**: `getOrSet(..., { staleWhileRevalidate })` answers with the old value while the new one loads,
49
+ and `resetStats()`.
50
+ - **Emitter**: `on()` and `once()` take `{ signal }`, and `listeners()`.
51
+ - **str**: `upperFirst`, `lowerFirst`, `humanize` and `chunk`. **num**: `pad`, `percentChange` and
52
+ `product`. **arr**: `duplicates`, `xor`, `takeWhile`, `dropWhile` and `toSentence`. **obj**: `update`,
53
+ `sortKeys` and `paths`.
54
+ - **Durations are text everywhere.** The last options that only took milliseconds (`debounce`, `throttle`,
55
+ `memoize`, `retry`, `timeout`, `delay`, `waitFor`...) accept `"5m"` or `"1.5s"` like the rest of the
56
+ package.
57
+ - Errors serialize with `JSON.stringify()` (name, code, message, fields and cause), and `instanceof` works
58
+ across two copies of the package.
59
+
60
+ ### Faster
61
+
62
+ Measured on the same machine, before and after, with Node 24.
63
+
64
+ | Operation | Speedup |
65
+ | --- | --- |
66
+ | `nc.info()` | 124x |
67
+ | `time.parseDuration("5m")` | 68x |
68
+ | `str.plural()` | 57x |
69
+ | `time.format()` with month and day names | 39x |
70
+ | `id.code()` | 39x |
71
+ | `id.uuidv7()` | 28x |
72
+ | `num.format()` | 23x |
73
+ | `checker.isIP()` | 19x |
74
+ | `obj.get()` with a dot path | 14x |
75
+ | `emitter.emit()` | 10x |
76
+ | `schema.is()` on invalid data | 9x |
77
+ | `schema.safeParse()` on invalid data | 5x |
78
+ | `db.get()` and `db.getAll()` | 3x to 4x |
79
+
80
+ `sys.which("node")` went from 23 ms to 0.13 ms on Windows. What is slow in JavaScript (`Intl` objects,
81
+ random bytes, stack traces, prepared statements) is now created once and reused.
82
+
83
+ ### Changed
84
+
85
+ Behaviours that differ from 2.0. Each one fixes something that was wrong or unsafe.
86
+
87
+ - **logger**: `DEBUG=name` only turns on the debug lines of the scopes it names (it used to turn on all
88
+ of them). `DEBUG=*`, `DEBUG=1` and `LOG_LEVEL=debug` show everything.
89
+ - **time**: `startOf()`, `endOf()`, `add()` and `diff()` follow `setTimezone()` instead of the system zone.
90
+ Adding whole days or weeks keeps the time of day when the clocks change in between (it added 24 hours
91
+ per day); `"24h"` stays exact. `add(date, "soon")` throws a `TypeError` (unreadable text used to add
92
+ nothing), and so does a unit that does not exist (it was read as milliseconds).
93
+ - **crypto**: `decrypt()` always fails with a `NodeComfortError` whose code is `ERR_DECRYPT` (malformed
94
+ input used to throw a `TypeError`), and refuses shortened authentication tags. `hash()` and `hmac()`
95
+ throw a `TypeError` for `null`, `undefined`, plain objects and empty secrets. `safeEqual()` returns
96
+ `false` when a value is missing. A wrong key type for a token is a `TypeError`, and the algorithms a
97
+ token may use follow from the key that verifies it.
98
+ - **cli**: leaving a menu or a password prompt with Ctrl+C or Escape rejects with an `AbortError`.
99
+ `cli.table([])` returns `""`. The
100
+ `LineReader` type is gone from the public types.
101
+ - **http**: the query and headers of a call are added to those of the client instead of replacing them.
102
+ A request whose body is a stream is never retried. With `responseType: "stream"` the timeout stops when
103
+ the headers arrive. `download()` writes to a temporary file first, so a failed download never destroys
104
+ the file that was there.
105
+ - **schema**: `pick()`, `omit()`, `partial()` and `extend()` keep `strict()`. Names inherited from
106
+ `Object.prototype` (`toString`, `constructor`) are never read from the input.
107
+ - **SQLite**: a column whose default is `CURRENT_TIMESTAMP` gets the time of the insert (it used to store
108
+ that text), and with `dates: true` the dates SQLite writes itself are read as UTC. Columns of joins and renamed columns are converted like the others, with Node 22.16 or later.
109
+ - **env**: in `load()`, the first file that defines a variable wins, whatever `override` says. `override`
110
+ only decides whether files may replace what was already in the environment. A file you load yourself
111
+ wins over the `.env` loaded at startup, so `.env.local` and `cascade` work without turning anything off.
112
+ A reference such as `${HOST}` takes the value `HOST` really ends up with.
113
+ - **sys**: `run()` rejects on a timeout it cannot read (it used to mean no timeout), and on Windows a
114
+ timeout or an abort stops the whole process tree.
115
+ - **fs**: an atomic write keeps the permissions of the file it replaces.
116
+ - **func**: `retry()` stops as soon as the function is aborted. `memoize()` no longer confuses
117
+ `f(undefined)` with `f(null)`, and accepts `bigint` arguments.
118
+ - **num**: `min()` and `max()` return `NaN` when one value is `NaN`, like `Math.min()`. `sum([0.1, 0.2, 0.3])`
119
+ is `0.6`.
120
+ - **obj**: `isEmpty()` looks inside a `Map` and a `Set`, and is `false` for a `Date`, a `RegExp` and an
121
+ `Error`. `unset()` on an array index removes the item instead of leaving a hole. `clone()` keeps class
122
+ instances and copies buffers. `merge()` never shares a nested object with its inputs.
123
+ - **checker**: `isEmpty()` is `false` for a `Date`, a `RegExp` and an `Error`.
124
+ - **utils**: `JSONString()` never throws, and writes an error with its name, message and stack.
125
+
126
+ ### Fixed
127
+
128
+ - Timers longer than 24.8 days (`wait("30d")`, cache expiry, `timeout()`) no longer fire at once.
129
+ - Object helpers (`pick`, `omit`, `filter`, `mapValues`, `flatten`, `groupBy`, `keyBy`, `countBy`, `props`,
130
+ `env.parse`...) are safe with keys named `__proto__`, `constructor` or `toString`.
131
+ - `safeEqual()` no longer reveals the length of the secret.
132
+ - `str.stripTags()` leaves `a < b and c > d` alone, `unescapeHTML()` accepts invalid code points,
133
+ `capitalize()` handles letters outside the basic plane, and padding counts what you see.
134
+ - `num.formatBytes()` and `num.abbreviate()` change unit when rounding reaches the next one (`"1 MB"`,
135
+ not `"1024 KB"`).
136
+ - `isYesterday()` and `isTomorrow()` are right on the days the clocks change.
137
+ - `cache.getOrSet()` respects a `delete()`, a `clear()` or a `set()` made while the value was loading.
138
+ - A shutdown handler that never finishes can no longer let the process end with a success code.
139
+ - `sys.run()` and `sys.exec()` settle after a timeout or an abort even when something the command started
140
+ keeps its output open. They used to wait for it.
141
+ - An async `onLog` hook that fails no longer stops the process.
142
+ - Deleting a watched folder on Windows sent events without end. The watcher now reports it once and stops.
143
+ - `http.download()` reports a connection cut in the middle as an `HttpError` with the code `ERR_NETWORK`.
144
+ - `str.truncate()` never returns more than the length asked for, even when the omission is longer.
145
+ - `emitter.off()` removes a listener added with `once()`.
146
+ - `http` keeps every `Set-Cookie` header and reads the status of an error response in all cases.
147
+ - Tables no longer fail on very large inputs, and progress bars print labels that contain `$`.
148
+
149
+ ### Documentation
150
+
151
+ - A new website, in English and in French, with a search, a page for every namespace generated from the
152
+ types, and a landing page whose examples are real files, run at every build.
153
+ - The old addresses (`/guide/logger.html`, `/api/str.html`) redirect to the new pages.
154
+ - `docs/API.md` is gone: the reference lives on the website, and in your editor.
155
+
7
156
  ## [2.0.0] - 2026-09-12
8
157
 
9
158
  node-comfort becomes a complete, zero-dependency standard library for Node.js: 23 namespaces and classes,
@@ -186,5 +335,6 @@ Each item explains what to change. Most projects only need the SQLite and Node.j
186
335
 
187
336
  - SQLite: the folder of the database was created in one place and the file opened in another.
188
337
 
338
+ [2.1.0]: https://github.com/ix-xs/node-comfort/compare/v2.0.0...v2.1.0
189
339
  [2.0.0]: https://github.com/ix-xs/node-comfort/compare/v1.2.0...v2.0.0
190
340
  [1.2.0]: https://github.com/ix-xs/node-comfort/releases/tag/v1.2.0
package/README.md CHANGED
@@ -15,9 +15,9 @@ One package, zero dependencies, documented right in your editor.
15
15
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
16
16
 
17
17
  [Documentation](https://ix-xs.github.io/node-comfort/) •
18
- [Getting started](https://ix-xs.github.io/node-comfort/guide/getting-started.html) •
19
- [API reference](https://ix-xs.github.io/node-comfort/api/index.html) •
20
- [Recipes](https://ix-xs.github.io/node-comfort/guide/recipes.html) •
18
+ [Getting started](https://ix-xs.github.io/node-comfort/start/getting-started/) •
19
+ [API reference](https://ix-xs.github.io/node-comfort/reference/) •
20
+ [Recipes](https://ix-xs.github.io/node-comfort/recipes/) •
21
21
  [Changelog](./CHANGELOG.md)
22
22
 
23
23
  </div>
@@ -57,7 +57,7 @@ Node.js 22.13 or newer. That's the first version where `node:sqlite` works witho
57
57
 
58
58
  - **Zero dependencies.** Built only on Node's own modules. No install scripts, nothing else to audit or keep up to date.
59
59
  - **Your editor already knows it.** Every function, parameter and option is typed and documented, with examples. Type `nc.` and look around. It works in plain JavaScript too.
60
- - **Fast to load.** Namespaces load the first time you use them. Requiring the package takes about 3 ms, and a script that only logs never loads the database or the HTTP client.
60
+ - **Fast to load.** Namespaces load the first time you use them. Requiring the package takes about 4 ms, and a script that only logs never loads the database or the HTTP client.
61
61
  - **Safe by default.** Prototype-pollution-proof objects, scrypt passwords, AES-256-GCM, constant-time comparisons, parameterized SQL, atomic file writes.
62
62
  - **One way of doing things.** Durations are always `"5m"` or milliseconds, options always come last, and every error has a stable `code`.
63
63
  - **Tested everywhere.** Linux, macOS and Windows, Node.js 22 and 24, TypeScript 5.9, 6 and 7.
@@ -66,29 +66,29 @@ Node.js 22.13 or newer. That's the first version where `node:sqlite` works witho
66
66
 
67
67
  | Namespace | What it's for | Often replaces |
68
68
  | --- | --- | --- |
69
- | [Logger](https://ix-xs.github.io/node-comfort/guide/logger.html) | Colorful logs, levels, JSON output, log files with rotation | `chalk`, `pino`, `winston` |
70
- | [`fs`](https://ix-xs.github.io/node-comfort/guide/fs.html) | Files and folders without try/catch, atomic writes, glob, watch | `fs-extra`, `glob`, `rimraf` |
71
- | [`checker`](https://ix-xs.github.io/node-comfort/guide/checker.html) | 60+ type guards and validators, `assert` | `is`, `validator` |
72
- | [`env`](https://ix-xs.github.io/node-comfort/guide/env.html) | `.env` loading, typed and validated configuration | `dotenv`, `envalid` |
73
- | [`schema`](https://ix-xs.github.io/node-comfort/guide/schema.html) | Data validation with TypeScript inference | `zod`, `yup`, `joi` |
74
- | [`http`](https://ix-xs.github.io/node-comfort/guide/http.html) | `fetch` with JSON, retries, timeouts, hooks, downloads | `axios`, `got`, `ky` |
75
- | [`SQLite`](https://ix-xs.github.io/node-comfort/guide/sqlite.html) | CRUD, filters, JSON columns, transactions, migrations | `better-sqlite3` and helpers |
76
- | [`time`](https://ix-xs.github.io/node-comfort/guide/time.html) | Formatting in any language and time zone, durations, date math, cron | `dayjs`, `ms`, `node-cron` |
77
- | [`str`](https://ix-xs.github.io/node-comfort/guide/str.html) | Case conversion, slugs, emoji-safe truncation, fuzzy matching, plurals | `lodash`, `slugify`, `leven` |
78
- | [`num`](https://ix-xs.github.io/node-comfort/guide/num.html) | Exact rounding, statistics, currencies, bytes | `numeral`, `pretty-bytes` |
79
- | [`arr`](https://ix-xs.github.io/node-comfort/guide/arr.html) | Chunk, group, multi-key sort, paginate, set operations | `lodash` |
80
- | [`obj`](https://ix-xs.github.io/node-comfort/guide/obj.html) | Deep clone, merge, equal and diff, typed dot paths | `lodash`, `deepmerge`, `dequal` |
81
- | [`func`](https://ix-xs.github.io/node-comfort/guide/func.html) | Debounce, throttle, memoize, retry with backoff, timeout | `p-retry`, `p-timeout` |
82
- | [`async`](https://ix-xs.github.io/node-comfort/guide/async.html) | Concurrency limits, queues, mutex, polling | `p-limit`, `p-map`, `p-queue` |
83
- | [`Cache`](https://ix-xs.github.io/node-comfort/guide/cache.html) | LRU cache with TTL, loaders and statistics | `lru-cache` |
84
- | [`Emitter`](https://ix-xs.github.io/node-comfort/guide/emitter.html) | Typed events, `waitFor`, async iteration | `mitt`, `emittery` |
85
- | [`id`](https://ix-xs.github.io/node-comfort/guide/id.html) | UUID v4 and v7, ULID, nanoid, tokens, Snowflakes | `uuid`, `ulid`, `nanoid` |
86
- | [`crypto`](https://ix-xs.github.io/node-comfort/guide/crypto.html) | Passwords, encryption, JWT, TOTP two-factor codes | `bcrypt`, `jsonwebtoken`, `otplib` |
87
- | [`cli`](https://ix-xs.github.io/node-comfort/guide/cli.html) | Typed arguments, prompts, menus, spinners, progress bars, tables | `commander`, `inquirer`, `ora` |
88
- | [`color`](https://ix-xs.github.io/node-comfort/guide/color.html) | Chainable terminal colors, truecolor, gradients, links | `chalk`, `picocolors` |
89
- | [`sys`](https://ix-xs.github.io/node-comfort/guide/sys.html) | Run commands, `which`, graceful shutdown, platform detection | `execa`, `which` |
90
- | [`utils`](https://ix-xs.github.io/node-comfort/guide/utils.html) | `wait`, safe JSON, crash guard | |
91
- | [`errors`](https://ix-xs.github.io/node-comfort/guide/errors.html) | Error classes with stable codes | |
69
+ | [Logger](https://ix-xs.github.io/node-comfort/essentials/logger/) | Colorful logs, levels, JSON output, log files with rotation | `chalk`, `pino`, `winston` |
70
+ | [`fs`](https://ix-xs.github.io/node-comfort/essentials/fs/) | Files and folders without try/catch, atomic writes, glob, watch | `fs-extra`, `glob`, `rimraf` |
71
+ | [`checker`](https://ix-xs.github.io/node-comfort/essentials/checker/) | 70+ type guards and validators, `assert` | `is`, `validator` |
72
+ | [`env`](https://ix-xs.github.io/node-comfort/essentials/env/) | `.env` loading, typed and validated configuration | `dotenv`, `envalid` |
73
+ | [`schema`](https://ix-xs.github.io/node-comfort/data/schema/) | Data validation with TypeScript inference | `zod`, `yup`, `joi` |
74
+ | [`http`](https://ix-xs.github.io/node-comfort/system/http/) | `fetch` with JSON, retries, timeouts, validated responses, hooks, downloads | `axios`, `got`, `ky` |
75
+ | [`SQLite`](https://ix-xs.github.io/node-comfort/system/sqlite/) | CRUD, filters, JSON columns, pagination, transactions, migrations | `better-sqlite3` and helpers |
76
+ | [`time`](https://ix-xs.github.io/node-comfort/data/time/) | Formatting in any language and time zone, durations, date math, cron | `dayjs`, `ms`, `node-cron` |
77
+ | [`str`](https://ix-xs.github.io/node-comfort/data/str/) | Case conversion, slugs, emoji-safe truncation, fuzzy matching, plurals | `lodash`, `slugify`, `leven` |
78
+ | [`num`](https://ix-xs.github.io/node-comfort/data/num/) | Exact rounding, statistics, currencies, bytes | `numeral`, `pretty-bytes` |
79
+ | [`arr`](https://ix-xs.github.io/node-comfort/data/arr/) | Chunk, group, multi-key sort, paginate, set operations | `lodash` |
80
+ | [`obj`](https://ix-xs.github.io/node-comfort/data/obj/) | Deep clone, merge, equal and diff, typed dot paths | `lodash`, `deepmerge`, `dequal` |
81
+ | [`func`](https://ix-xs.github.io/node-comfort/flow/func/) | Debounce, throttle, memoize, retry with backoff, timeout | `p-retry`, `p-timeout` |
82
+ | [`async`](https://ix-xs.github.io/node-comfort/flow/async/) | Concurrency limits, queues, mutex, polling | `p-limit`, `p-map`, `p-queue` |
83
+ | [`Cache`](https://ix-xs.github.io/node-comfort/flow/cache/) | LRU cache with TTL, loaders and statistics | `lru-cache` |
84
+ | [`Emitter`](https://ix-xs.github.io/node-comfort/flow/emitter/) | Typed events, `waitFor`, async iteration | `mitt`, `emittery` |
85
+ | [`id`](https://ix-xs.github.io/node-comfort/data/id/) | UUID v4, v5 and v7, ULID, nanoid, ObjectId, tokens, Snowflakes | `uuid`, `ulid`, `nanoid` |
86
+ | [`crypto`](https://ix-xs.github.io/node-comfort/system/crypto/) | Passwords, encryption, JWT, TOTP two-factor codes | `bcrypt`, `jsonwebtoken`, `otplib` |
87
+ | [`cli`](https://ix-xs.github.io/node-comfort/system/cli/) | Typed arguments and subcommands, prompts, menus, spinners, progress bars, tables, trees | `commander`, `inquirer`, `ora` |
88
+ | [`color`](https://ix-xs.github.io/node-comfort/system/color/) | Chainable terminal colors, truecolor, gradients, links | `chalk`, `picocolors` |
89
+ | [`sys`](https://ix-xs.github.io/node-comfort/system/sys/) | Run commands, `which`, graceful shutdown, platform detection | `execa`, `which` |
90
+ | [`utils`](https://ix-xs.github.io/node-comfort/essentials/utils/) | `wait`, safe JSON, crash guard | |
91
+ | [`errors`](https://ix-xs.github.io/node-comfort/essentials/errors/) | Error classes with stable codes | |
92
92
 
93
93
  The logger, `fs`, `checker` and `utils` helpers are also available at the top level: `nc.info()`, `nc.readJSON()`, `nc.isEmail()`, `nc.wait()`.
94
94
 
@@ -104,7 +104,7 @@ import nc from "@ix-xs/node-comfort";
104
104
  import { slugify } from "@ix-xs/node-comfort/str"; // loads only what it needs
105
105
  ```
106
106
 
107
- Every namespace has its own entry point (`@ix-xs/node-comfort/http`, `/sqlite`, `/schema`...). In an ES module, importing from these keeps startup lean. See [Performance](https://ix-xs.github.io/node-comfort/guide/performance.html).
107
+ Every namespace has its own entry point (`@ix-xs/node-comfort/http`, `/sqlite`, `/schema`...). In an ES module, importing from these keeps startup lean. See [Performance](https://ix-xs.github.io/node-comfort/start/performance/).
108
108
 
109
109
  TypeScript needs no setup: the types ship with the package.
110
110
 
@@ -188,7 +188,7 @@ const spinner = nc.cli.spinner(`Deploying to ${env}`).start();
188
188
  spinner.succeed("Deployed");
189
189
  ```
190
190
 
191
- That's a small part of it. The [guide](https://ix-xs.github.io/node-comfort/guide/introduction.html) walks through every namespace, and the [recipes](https://ix-xs.github.io/node-comfort/guide/recipes.html) show them working together: a small API server, a CLI, a scheduled job.
191
+ That's a small part of it. The [guide](https://ix-xs.github.io/node-comfort/start/introduction/) walks through every namespace, and the [recipes](https://ix-xs.github.io/node-comfort/recipes/) show them working together: a small API server, a CLI, a scheduled job.
192
192
 
193
193
  ## Coming from 1.x
194
194
 
@@ -199,7 +199,9 @@ That's a small part of it. The [guide](https://ix-xs.github.io/node-comfort/guid
199
199
  - `warn` and `error` write to stderr.
200
200
  - Deep imports (`@ix-xs/node-comfort/src/...`) are replaced by official entry points (`@ix-xs/node-comfort/str`).
201
201
 
202
- The [migration guide](https://ix-xs.github.io/node-comfort/guide/migration.html) lists every change with before and after examples.
202
+ The [migration guide](https://ix-xs.github.io/node-comfort/start/migration/) lists every change with before and after examples.
203
+
204
+ Coming from 2.0, there is nothing to change: 2.1 adds functions, makes the existing ones faster and corrects edge cases. The [changelog](./CHANGELOG.md) has the details.
203
205
 
204
206
  ## Contributing
205
207
 
package/index.js CHANGED
@@ -41,8 +41,8 @@ const modules = {
41
41
  // Helpers that are also available at the top level (nc.info, nc.readJSON...).
42
42
  const flat = {
43
43
  logger: ["log", "trace", "debug", "info", "success", "warn", "error", "fatal", "group", "groupEnd", "timeStart", "timeEnd", "table", "box", "divider", "setLevel", "getLevel", "isLevelEnabled", "configure", "setTimestamp", "setDelimiter", "createLogger"],
44
- fs: ["getEnv", "createPath", "getFolder", "getFile", "getFoldersIn", "getFilesIn", "glob", "find", "readFile", "readLines", "readJSON", "writeFile", "writeJSON", "appendFile", "createFile", "createFolder", "ensureFolder", "ensureFile", "touch", "deleteFolder", "deleteFile", "remove", "deleteFoldersIn", "deleteFilesIn", "emptyFolder", "copy", "move", "copyFoldersIn", "copyFolder", "copyFilesIn", "copyFile", "moveFoldersIn", "moveFolder", "moveFilesIn", "moveFile", "exists", "isFile", "isFolder", "stat", "fileSize", "folderSize", "hashFile", "tempFolder", "sanitizeFilename", "watch"],
45
- checker: ["isArray", "isNumber", "isFinite", "isInteger", "isSafeInteger", "isFloat", "isPositive", "isNegative", "isBoolean", "isString", "isSymbol", "isBigInt", "isUndefined", "isNull", "isNil", "isDefined", "isPrimitive", "isFunction", "isAsyncFunction", "isGeneratorFunction", "isGenerator", "isClass", "isObject", "isPlainObject", "isPromise", "isRegExp", "isDate", "isValidDate", "isMap", "isSet", "isWeakMap", "isWeakSet", "isIterable", "isAsyncIterable", "isBuffer", "isTypedArray", "isError", "isEmpty", "isBlank", "isArrayOf", "isOneOf", "isEmail", "isURL", "isUUID", "isJSON", "isNumeric", "isIP", "isIPv4", "isIPv6", "isPort", "isHex", "isHexColor", "isBase64", "isSemver", "isISODate", "isSlug", "isAlpha", "isAlphanumeric", "isCreditCard", "isJWT", "assert", "assertType"],
44
+ fs: ["getEnv", "createPath", "getFolder", "getFile", "getFoldersIn", "getFilesIn", "glob", "find", "findUp", "readFile", "readLines", "readJSON", "writeFile", "writeJSON", "appendFile", "createFile", "createFolder", "ensureFolder", "ensureFile", "touch", "deleteFolder", "deleteFile", "remove", "deleteFoldersIn", "deleteFilesIn", "emptyFolder", "copy", "move", "copyFoldersIn", "copyFolder", "copyFilesIn", "copyFile", "moveFoldersIn", "moveFolder", "moveFilesIn", "moveFile", "exists", "isFile", "isFolder", "stat", "fileSize", "folderSize", "hashFile", "tempFolder", "sanitizeFilename", "watch"],
45
+ checker: ["isArray", "isNumber", "isFinite", "isInteger", "isSafeInteger", "isFloat", "isPositive", "isNegative", "isBoolean", "isString", "isSymbol", "isBigInt", "isUndefined", "isNull", "isNil", "isDefined", "isPrimitive", "isFunction", "isAsyncFunction", "isGeneratorFunction", "isGenerator", "isClass", "isObject", "isPlainObject", "isPromise", "isRegExp", "isDate", "isValidDate", "isMap", "isSet", "isWeakMap", "isWeakSet", "isIterable", "isAsyncIterable", "isBuffer", "isTypedArray", "isError", "isEmpty", "isBlank", "isArrayOf", "isOneOf", "isEmail", "isURL", "isUUID", "isJSON", "isNumeric", "isIP", "isIPv4", "isIPv6", "isPort", "isHex", "isHexColor", "isBase64", "isSemver", "isISODate", "isSlug", "isAlpha", "isAlphanumeric", "isCreditCard", "isJWT", "isHostname", "isMACAddress", "isIBAN", "isE164", "isObjectId", "isULID", "isDataURL", "isMimeType", "isTimeZone", "isLocale", "isCron", "isASCII", "assert", "assertType"],
46
46
  utils: ["wait", "when", "dontCrash", "JSONString", "JSONParse"],
47
47
  };
48
48
 
@@ -81,4 +81,4 @@ exports.nodeComfort = exports;
81
81
 
82
82
  // Never runs. Node reads this line to know the named exports of the package
83
83
  // when it is imported from an ES module.
84
- 0 && (module.exports = { log, trace, debug, info, success, warn, error, fatal, group, groupEnd, timeStart, timeEnd, table, box, divider, setLevel, getLevel, isLevelEnabled, configure, setTimestamp, setDelimiter, createLogger, getEnv, createPath, getFolder, getFile, getFoldersIn, getFilesIn, glob, find, readFile, readLines, readJSON, writeFile, writeJSON, appendFile, createFile, createFolder, ensureFolder, ensureFile, touch, deleteFolder, deleteFile, remove, deleteFoldersIn, deleteFilesIn, emptyFolder, copy, move, copyFoldersIn, copyFolder, copyFilesIn, copyFile, moveFoldersIn, moveFolder, moveFilesIn, moveFile, exists, isFile, isFolder, stat, fileSize, folderSize, hashFile, tempFolder, sanitizeFilename, watch, isArray, isNumber, isFinite, isInteger, isSafeInteger, isFloat, isPositive, isNegative, isBoolean, isString, isSymbol, isBigInt, isUndefined, isNull, isNil, isDefined, isPrimitive, isFunction, isAsyncFunction, isGeneratorFunction, isGenerator, isClass, isObject, isPlainObject, isPromise, isRegExp, isDate, isValidDate, isMap, isSet, isWeakMap, isWeakSet, isIterable, isAsyncIterable, isBuffer, isTypedArray, isError, isEmpty, isBlank, isArrayOf, isOneOf, isEmail, isURL, isUUID, isJSON, isNumeric, isIP, isIPv4, isIPv6, isPort, isHex, isHexColor, isBase64, isSemver, isISODate, isSlug, isAlpha, isAlphanumeric, isCreditCard, isJWT, assert, assertType, wait, when, dontCrash, JSONString, JSONParse, logger, fs, checker, utils, str, num, arr, obj, func, time, id, crypto, color, cli, sys, async, schema, http, env, errors, SQLite, Cache, Emitter, nc, nodeComfort });
84
+ 0 && (module.exports = { log, trace, debug, info, success, warn, error, fatal, group, groupEnd, timeStart, timeEnd, table, box, divider, setLevel, getLevel, isLevelEnabled, configure, setTimestamp, setDelimiter, createLogger, getEnv, createPath, getFolder, getFile, getFoldersIn, getFilesIn, glob, find, findUp, readFile, readLines, readJSON, writeFile, writeJSON, appendFile, createFile, createFolder, ensureFolder, ensureFile, touch, deleteFolder, deleteFile, remove, deleteFoldersIn, deleteFilesIn, emptyFolder, copy, move, copyFoldersIn, copyFolder, copyFilesIn, copyFile, moveFoldersIn, moveFolder, moveFilesIn, moveFile, exists, isFile, isFolder, stat, fileSize, folderSize, hashFile, tempFolder, sanitizeFilename, watch, isArray, isNumber, isFinite, isInteger, isSafeInteger, isFloat, isPositive, isNegative, isBoolean, isString, isSymbol, isBigInt, isUndefined, isNull, isNil, isDefined, isPrimitive, isFunction, isAsyncFunction, isGeneratorFunction, isGenerator, isClass, isObject, isPlainObject, isPromise, isRegExp, isDate, isValidDate, isMap, isSet, isWeakMap, isWeakSet, isIterable, isAsyncIterable, isBuffer, isTypedArray, isError, isEmpty, isBlank, isArrayOf, isOneOf, isEmail, isURL, isUUID, isJSON, isNumeric, isIP, isIPv4, isIPv6, isPort, isHex, isHexColor, isBase64, isSemver, isISODate, isSlug, isAlpha, isAlphanumeric, isCreditCard, isJWT, isHostname, isMACAddress, isIBAN, isE164, isObjectId, isULID, isDataURL, isMimeType, isTimeZone, isLocale, isCron, isASCII, assert, assertType, wait, when, dontCrash, JSONString, JSONParse, logger, fs, checker, utils, str, num, arr, obj, func, time, id, crypto, color, cli, sys, async, schema, http, env, errors, SQLite, Cache, Emitter, nc, nodeComfort });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ix-xs/node-comfort",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "The zero-dependency standard library for Node.js: logger, filesystem, SQLite, schema validation, HTTP client, CLI toolkit, cache, env, async pools, colors, events, i18n dates, ids, crypto and hundreds of fully typed helpers.",
5
5
  "keywords": [
6
6
  "utils",
@@ -184,14 +184,15 @@
184
184
  "access": "public"
185
185
  },
186
186
  "scripts": {
187
- "build": "node scripts/build-types.js && node scripts/build-docs.js",
187
+ "build": "node scripts/build-types.js && node scripts/build-reference.js",
188
188
  "build:types": "node scripts/build-types.js",
189
- "build:docs": "node scripts/build-docs.js",
190
- "build:site": "node scripts/build-site.js",
191
- "site:serve": "node scripts/serve-site.js",
192
- "test": "node --test \"test/**/*.test.js\"",
189
+ "build:reference": "node scripts/build-reference.js",
190
+ "test": "node --test --test-reporter=spec --test-timeout=120000 \"test/**/*.test.js\"",
193
191
  "test:types": "node scripts/check-types.js",
194
- "check": "npm run build && npm run build:site && npm test && npm run test:types",
192
+ "docs:install": "npm ci --prefix docs",
193
+ "docs:dev": "npm run dev --prefix docs",
194
+ "docs:build": "npm run build --prefix docs && npm run check-links --prefix docs && npm run check-translation --prefix docs",
195
+ "check": "npm run build && npm test && npm run test:types",
195
196
  "prepublishOnly": "npm run check"
196
197
  },
197
198
  "devDependencies": {