@ppabari/strio 1.0.2 → 1.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,48 @@ This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ---
8
8
 
9
+ ## [1.1.0] — 2026-07-07
10
+
11
+ ### Added
12
+
13
+ **String-utility toolkit** — new `@ppabari/strio/str` subpath export (~60 pure, tree-shakeable functions):
14
+
15
+ - **Manipulation** — `capitalize`, `capitalizeWords`, `reverse`, `truncate`, `truncateWords`, `trim`, `insert`, `mask`
16
+ - **Case conversion** — `camelize`, `pascalize`, `dasherize`, `underscore`
17
+ - **Validation** — `isEmpty`, `isBlank`, `isString`, `isAlpha`, `isNumeric`, `isAlphaNumeric`, `isUpperCase`, `isLowerCase`
18
+ - **Searching** — `contains`, `containsAll`, `containsAny`, `count`, `between`, `betweenAll`
19
+ - **Formatting** — `humanize`, `titleCase`, `slugify`, `ordinalize`, `pluralize`
20
+ - **Utilities** — `words`, `wordCount`, `join`, `template`, `random`, `randomAlpha`, `randomNumeric`, `randomAlphanumeric`, `similarity`, `transliterate`
21
+ - **Padding & indentation** — `padLeft`, `padRight`, `padCenter`, `indent`, `dedent`
22
+ - **Security** — `escapeHtml`, `unescapeHtml`, `escapeRegExp`, `stripTags`, `collapseWhitespace`, `stripPrefix`, `stripSuffix`
23
+ - **Ensuring** — `ensureLeft`, `ensureRight`
24
+
25
+ > The `random*` helpers reuse the same bias-free Web-Crypto engine as the core library, so they are cryptographically secure.
26
+
27
+ **Compatibility checks** (main export)
28
+
29
+ - `checkCompatibility()` — inspect the runtime (Web Crypto availability, detected runtime, Node version) without throwing
30
+ - `assertCompatible()` — throw a descriptive error on an unsupported runtime
31
+ - `MIN_NODE_VERSION` constant and `CompatibilityResult` / `Runtime` types
32
+ - CLI: new `--check` (alias `--compat`) flag prints a compatibility report
33
+
34
+ **Docs**
35
+
36
+ - New VitePress documentation site with a categorized API reference
37
+
38
+ ### Maintenance
39
+
40
+ - Upgraded the entire dev toolchain to latest — `vitest` & `@vitest/coverage-v8` v4, `vitepress` v2, `typescript` v6, `@types/node` v26, `zod` v4 (dev/test only) — resolving **all** `npm audit` findings (6 → 0, including the vite dev-server high/critical advisories). All were dev-only and never affected the published package.
41
+ - Pinned transitive `esbuild` to a safe `0.27.2` via `overrides`.
42
+ - Added `"ignoreDeprecations": "6.0"` to `tsconfig.json` for TypeScript 6 compatibility.
43
+ - Note: building/testing the package now requires Node ≥ 20 (per vitest 4). The published library's **runtime** support is unchanged — still Node ≥ 18, browsers, Deno, Bun, and edge runtimes.
44
+
45
+ ### Notes
46
+
47
+ - Fully backward compatible — no changes to the existing `.` or `/zod` surface. String utilities are isolated under `/str`, so names that overlap conceptually with the core API (`random`, `mask`) do not collide.
48
+
49
+ ---
50
+
9
51
  ## [1.0.0] — 2025
10
52
 
11
53
  ### Added
package/README.md CHANGED
@@ -1,11 +1,13 @@
1
1
  # @ppabari/strio
2
2
 
3
- Cryptographically secure string generation for Node.js and browsers.
4
- Tokens · IDs · Passphrases · Patterns · Expiring tokens — bias-free, zero dependencies, fully typed.
3
+ Cryptographically secure string generation **and** a general-purpose string-utility toolkit for Node.js and browsers.
4
+ Tokens · IDs · Passphrases · Patterns · Expiring tokens · 60+ string helpers — bias-free, zero dependencies, fully typed.
5
5
 
6
6
  [![npm](https://img.shields.io/npm/v/@ppabari/strio)](https://www.npmjs.com/package/@ppabari/strio)
7
7
  [![license](https://img.shields.io/npm/l/@ppabari/strio)](./LICENSE)
8
- [![tests](https://img.shields.io/github/actions/workflow/status/ppabari/strio/ci.yml?label=tests)](https://github.com/ppabari/strio/actions)
8
+ [![tests](https://img.shields.io/github/actions/workflow/status/parthpabari/strio/ci.yml?label=tests)](https://github.com/parthpabari/strio/actions)
9
+
10
+ 📖 **[Documentation](https://parthpabari.github.io/strio/)** · [API Reference](https://parthpabari.github.io/strio/api/overview)
9
11
 
10
12
  ---
11
13
 
@@ -61,11 +63,63 @@ npx @ppabari/strio --passphrase --words 5 --capitalize
61
63
  npx @ppabari/strio --id --prefix usr
62
64
  npx @ppabari/strio --expiring --ttl 900
63
65
  npx @ppabari/strio --entropy --preset PASSWORD
66
+ npx @ppabari/strio --check # runtime compatibility report
64
67
  npx @ppabari/strio --help
65
68
  ```
66
69
 
67
70
  ---
68
71
 
72
+ ## String Utility Toolkit
73
+
74
+ Beyond secure generation, strio ships **60+ general-purpose string helpers** from the tree-shakeable `@ppabari/strio/str` subpath. Every function is a pure named export.
75
+
76
+ ```ts
77
+ import { slugify, camelize, truncate, pluralize } from '@ppabari/strio/str';
78
+
79
+ slugify('Héllo, World!'); // → 'hello-world'
80
+ camelize('foo-bar_baz'); // → 'fooBarBaz'
81
+ truncate('The quick brown fox', 12); // → 'The quick b…'
82
+ pluralize('child'); // → 'children'
83
+ ```
84
+
85
+ | Category | Functions |
86
+ | --- | --- |
87
+ | **Manipulation** | `capitalize` `capitalizeWords` `reverse` `truncate` `truncateWords` `trim` `insert` `mask` |
88
+ | **Case Conversion** | `camelize` `pascalize` `dasherize` `underscore` |
89
+ | **Validation** | `isEmpty` `isBlank` `isString` `isAlpha` `isNumeric` `isAlphaNumeric` `isUpperCase` `isLowerCase` |
90
+ | **Searching** | `contains` `containsAll` `containsAny` `count` `between` `betweenAll` |
91
+ | **Formatting** | `humanize` `titleCase` `slugify` `ordinalize` `pluralize` |
92
+ | **Utilities** | `words` `wordCount` `join` `template` `random` `randomAlpha` `randomNumeric` `randomAlphanumeric` `similarity` `transliterate` |
93
+ | **Padding & Indentation** | `padLeft` `padRight` `padCenter` `indent` `dedent` |
94
+ | **Security** | `escapeHtml` `unescapeHtml` `escapeRegExp` `stripTags` `collapseWhitespace` `stripPrefix` `stripSuffix` |
95
+ | **Ensuring** | `ensureLeft` `ensureRight` |
96
+
97
+ > The `random*` helpers reuse the same bias-free Web-Crypto engine as the core library — they are cryptographically secure, not `Math.random`.
98
+
99
+ Full signatures and examples: **[API Reference →](https://parthpabari.github.io/strio/api/overview)**
100
+
101
+ ---
102
+
103
+ ## Compatibility Check
104
+
105
+ ```ts
106
+ import { checkCompatibility, assertCompatible } from '@ppabari/strio';
107
+
108
+ const report = checkCompatibility();
109
+ // { ok: true, cryptoAvailable: true, runtime: 'node', nodeVersion: '20.11.0', warnings: [] }
110
+
111
+ assertCompatible(); // throws on an unsupported runtime
112
+ ```
113
+
114
+ | Environment | Supported |
115
+ | --- | --- |
116
+ | Node.js | ✅ ≥ 18 |
117
+ | Browsers (modern) | ✅ |
118
+ | Deno · Bun · Cloudflare Workers | ✅ |
119
+ | TypeScript | ✅ ≥ 5.0 |
120
+
121
+ ---
122
+
69
123
  ## Core API
70
124
 
71
125
  ### `generateRandomString(options?)`
package/dist/bin/strio.js CHANGED
@@ -1218,6 +1218,47 @@ function approximateCombinations(charsetSize, length) {
1218
1218
  return Math.round(Math.pow(charsetSize, length)).toString();
1219
1219
  }
1220
1220
 
1221
+ // src/compat.ts
1222
+ var MIN_NODE_VERSION = 18;
1223
+ function detectRuntime() {
1224
+ const g = globalThis;
1225
+ if (typeof g.Deno !== "undefined") return { runtime: "deno" };
1226
+ if (typeof g.Bun !== "undefined") return { runtime: "bun" };
1227
+ if (typeof g.process !== "undefined" && g.process?.versions?.node) {
1228
+ return { runtime: "node", nodeVersion: String(g.process.versions.node) };
1229
+ }
1230
+ if (typeof g.WebSocketPair !== "undefined") return { runtime: "workerd" };
1231
+ if (typeof g.window !== "undefined" || typeof g.document !== "undefined") {
1232
+ return { runtime: "browser" };
1233
+ }
1234
+ return { runtime: "unknown" };
1235
+ }
1236
+ function checkCompatibility() {
1237
+ const warnings = [];
1238
+ const { runtime, nodeVersion } = detectRuntime();
1239
+ const cryptoAvailable = typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.getRandomValues === "function";
1240
+ if (!cryptoAvailable) {
1241
+ warnings.push(
1242
+ "Web Crypto API (crypto.getRandomValues) is unavailable. Secure generation will fail. On Node.js, upgrade to v18 or newer."
1243
+ );
1244
+ }
1245
+ if (runtime === "node" && nodeVersion) {
1246
+ const major = parseInt(nodeVersion.split(".")[0] ?? "0", 10);
1247
+ if (major < MIN_NODE_VERSION) {
1248
+ warnings.push(
1249
+ `Node.js ${nodeVersion} is below the supported minimum (v${MIN_NODE_VERSION}). Please upgrade.`
1250
+ );
1251
+ }
1252
+ }
1253
+ return {
1254
+ ok: cryptoAvailable && warnings.length === 0,
1255
+ cryptoAvailable,
1256
+ runtime,
1257
+ ...nodeVersion ? { nodeVersion } : {},
1258
+ warnings
1259
+ };
1260
+ }
1261
+
1221
1262
  // src/presets.ts
1222
1263
  var PRESETS = {
1223
1264
  /**
@@ -1380,6 +1421,7 @@ if (hasFlag("help") || hasFlag("h")) {
1380
1421
  --payload <n> Payload length (default: 24)
1381
1422
 
1382
1423
  --entropy Show entropy estimate only (no string generated)
1424
+ --check Check runtime compatibility and exit
1383
1425
 
1384
1426
  PRESETS
1385
1427
  TOKEN 32-char alphanumeric API token
@@ -1406,6 +1448,17 @@ if (hasFlag("help") || hasFlag("h")) {
1406
1448
  `);
1407
1449
  process.exit(0);
1408
1450
  }
1451
+ if (hasFlag("check") || hasFlag("compat")) {
1452
+ const report = checkCompatibility();
1453
+ console.log(`Runtime : ${report.runtime}${report.nodeVersion ? ` (Node ${report.nodeVersion})` : ""}`);
1454
+ console.log(`Web Crypto : ${report.cryptoAvailable ? "available" : "MISSING"}`);
1455
+ console.log(`Compatible : ${report.ok ? "yes" : "no"}`);
1456
+ if (report.warnings.length > 0) {
1457
+ console.log("Warnings :");
1458
+ report.warnings.forEach((w) => console.log(` - ${w}`));
1459
+ }
1460
+ process.exit(report.ok ? 0 : 1);
1461
+ }
1409
1462
  if (hasFlag("passphrase")) {
1410
1463
  const words = parseInt(getFlag("words") ?? "4", 10);
1411
1464
  const separator = getFlag("separator") ?? "-";
package/dist/index.cjs CHANGED
@@ -1431,6 +1431,54 @@ function validatePattern(str, pattern) {
1431
1431
  return errors;
1432
1432
  }
1433
1433
 
1434
+ // src/compat.ts
1435
+ var MIN_NODE_VERSION = 18;
1436
+ function detectRuntime() {
1437
+ const g = globalThis;
1438
+ if (typeof g.Deno !== "undefined") return { runtime: "deno" };
1439
+ if (typeof g.Bun !== "undefined") return { runtime: "bun" };
1440
+ if (typeof g.process !== "undefined" && g.process?.versions?.node) {
1441
+ return { runtime: "node", nodeVersion: String(g.process.versions.node) };
1442
+ }
1443
+ if (typeof g.WebSocketPair !== "undefined") return { runtime: "workerd" };
1444
+ if (typeof g.window !== "undefined" || typeof g.document !== "undefined") {
1445
+ return { runtime: "browser" };
1446
+ }
1447
+ return { runtime: "unknown" };
1448
+ }
1449
+ function checkCompatibility() {
1450
+ const warnings = [];
1451
+ const { runtime, nodeVersion } = detectRuntime();
1452
+ const cryptoAvailable = typeof globalThis.crypto !== "undefined" && typeof globalThis.crypto.getRandomValues === "function";
1453
+ if (!cryptoAvailable) {
1454
+ warnings.push(
1455
+ "Web Crypto API (crypto.getRandomValues) is unavailable. Secure generation will fail. On Node.js, upgrade to v18 or newer."
1456
+ );
1457
+ }
1458
+ if (runtime === "node" && nodeVersion) {
1459
+ const major = parseInt(nodeVersion.split(".")[0] ?? "0", 10);
1460
+ if (major < MIN_NODE_VERSION) {
1461
+ warnings.push(
1462
+ `Node.js ${nodeVersion} is below the supported minimum (v${MIN_NODE_VERSION}). Please upgrade.`
1463
+ );
1464
+ }
1465
+ }
1466
+ return {
1467
+ ok: cryptoAvailable && warnings.length === 0,
1468
+ cryptoAvailable,
1469
+ runtime,
1470
+ ...nodeVersion ? { nodeVersion } : {},
1471
+ warnings
1472
+ };
1473
+ }
1474
+ function assertCompatible() {
1475
+ const report = checkCompatibility();
1476
+ if (!report.ok) {
1477
+ throw new Error(`@ppabari/strio: incompatible runtime.
1478
+ - ${report.warnings.join("\n- ")}`);
1479
+ }
1480
+ }
1481
+
1434
1482
  // src/presets.ts
1435
1483
  var PRESETS = {
1436
1484
  /**
@@ -1880,7 +1928,10 @@ async function generateRandomStringAsync(options = {}) {
1880
1928
 
1881
1929
  exports.BUILT_IN_WORD_LIST = WORD_LIST;
1882
1930
  exports.CHARSET_ALIASES = CHARSET_ALIASES;
1931
+ exports.MIN_NODE_VERSION = MIN_NODE_VERSION;
1883
1932
  exports.PRESETS = PRESETS;
1933
+ exports.assertCompatible = assertCompatible;
1934
+ exports.checkCompatibility = checkCompatibility;
1884
1935
  exports.estimateEntropy = estimateEntropy;
1885
1936
  exports.generateAesKey = generateAesKey;
1886
1937
  exports.generateApiKey = generateApiKey;