@utilix-tech/sdk 0.55.0 → 0.57.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 (35) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +16 -7
  3. package/dist/{chunk-WVEKRKGU.js → chunk-34C6GXCC.js} +34 -1
  4. package/dist/{chunk-3TYWIX3B.js → chunk-422ICOZX.js} +16 -1
  5. package/dist/{chunk-LI63MAZU.js → chunk-MRIGQRTU.js} +41 -1
  6. package/dist/{chunk-DEBIH7QS.js → chunk-TVSQ53TZ.js} +55 -1
  7. package/dist/{generators-Du8cBesn.d.cts → generators-DAXXrMvG.d.cts} +23 -2
  8. package/dist/{generators-Du8cBesn.d.ts → generators-DAXXrMvG.d.ts} +23 -2
  9. package/dist/index.cjs +142 -0
  10. package/dist/index.d.cts +4 -4
  11. package/dist/index.d.ts +4 -4
  12. package/dist/index.js +4 -4
  13. package/dist/{json-Ta9JykSB.d.ts → json-CaiYsGDQ.d.cts} +24 -2
  14. package/dist/{json-Ta9JykSB.d.cts → json-CaiYsGDQ.d.ts} +24 -2
  15. package/dist/{network-C6IcHeMB.d.cts → network-CoGf7_Op.d.cts} +37 -2
  16. package/dist/{network-C6IcHeMB.d.ts → network-CoGf7_Op.d.ts} +37 -2
  17. package/dist/tools/generators.cjs +15 -0
  18. package/dist/tools/generators.d.cts +1 -1
  19. package/dist/tools/generators.d.ts +1 -1
  20. package/dist/tools/generators.js +1 -1
  21. package/dist/tools/json.cjs +33 -0
  22. package/dist/tools/json.d.cts +1 -1
  23. package/dist/tools/json.d.ts +1 -1
  24. package/dist/tools/json.js +1 -1
  25. package/dist/tools/network.cjs +54 -0
  26. package/dist/tools/network.d.cts +1 -1
  27. package/dist/tools/network.d.ts +1 -1
  28. package/dist/tools/network.js +1 -1
  29. package/dist/tools/units.cjs +40 -0
  30. package/dist/tools/units.d.cts +1 -1
  31. package/dist/tools/units.d.ts +1 -1
  32. package/dist/tools/units.js +1 -1
  33. package/dist/{units-BM1l5LG9.d.cts → units-BM9GkUZW.d.cts} +36 -2
  34. package/dist/{units-BM1l5LG9.d.ts → units-BM9GkUZW.d.ts} +36 -2
  35. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  Full release notes for all Utilix surfaces (browser tools, REST API, SDKs, MCP server) live at [utilix.tech/changelog](https://utilix.tech/changelog). This file tracks just this package.
4
4
 
5
+ ## 0.57.0
6
+ - Add `mergeJsonPatch`, `applyJsonMergePatch` (json-merge-patch): apply an RFC 7396 JSON Merge Patch document to a target JSON document, with null-valued patch keys removing the matching target key.
7
+ - Add `generateCspNonce` (csp-nonce-generator): generate a cryptographically random, base64-encoded Content-Security-Policy nonce with ready-to-paste header directive and script/style tag snippets.
8
+
9
+ ## 0.56.0
10
+ - Add `buildAcceptLanguage`, `parseAcceptLanguage` (accept-language-parser): build an Accept-Language request-header value from locale/quality pairs sorted by descending preference, or parse an existing one into its ranked entries.
11
+ - Add `calculateBlendedLoanRate` (blended-loan-rate-calculator): compute the single weighted-average interest rate across a list of loan balances, plus combined monthly and annual interest accrual.
12
+
5
13
  ## 0.55.0
6
14
  - Add `calculateDebtToIncomeRatio` (debt-to-income-ratio-calculator): compute the debt-to-income ratio (total monthly debt payments / gross monthly income) from one or more monthly debts, plus a qualitative tier matching common mortgage-lending guidance.
7
15
  - Add `inferCsvColumnTypes` (csv-column-type-inferencer): parse CSV/TSV data and infer each column's data type (integer, float, boolean, ISO 8601 date, or string), flagging nullable columns and empty-cell counts.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/sdk
2
2
 
3
- **648 developer utility functions for Node.js: runs locally, no API key required.**
3
+ **659 developer utility functions for Node.js: runs locally, no API key required.**
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@utilix-tech/sdk?style=flat-square&color=cb3837)](https://www.npmjs.com/package/@utilix-tech/sdk)
6
6
  [![npm downloads](https://img.shields.io/npm/dm/@utilix-tech/sdk?style=flat-square)](https://www.npmjs.com/package/@utilix-tech/sdk)
@@ -66,7 +66,7 @@ const { formatJson } = require("@utilix-tech/sdk/json");
66
66
 
67
67
  ```ts
68
68
  import { formatJson, minifyJson, diffJson, jsonToTypescript, jsonSchemaToTypescript, validateJson,
69
- evaluateJsonPath, resolveJsonPointer, jsonToCsv, yamlToJson, jsonToYaml, getJsonStats } from "@utilix-tech/sdk/json";
69
+ evaluateJsonPath, resolveJsonPointer, applyJsonMergePatch, jsonToCsv, yamlToJson, jsonToYaml, getJsonStats } from "@utilix-tech/sdk/json";
70
70
 
71
71
  // Format with 2-space indent
72
72
  formatJson('{"name":"alice","age":30}', { indent: 2 });
@@ -87,6 +87,10 @@ evaluateJsonPath(obj, "$.users[*].name");
87
87
  resolveJsonPointer('{"users":[{"name":"Alice"}]}', "/users/0/name");
88
88
  // { found: true, value: "Alice", tokens: ["users", "0", "name"] }
89
89
 
90
+ // Apply an RFC 7396 JSON Merge Patch
91
+ applyJsonMergePatch('{"a":"b","c":{"d":"e","f":"g"}}', '{"a":"z","c":{"f":null}}');
92
+ // { result: { a: "z", c: { d: "e" } } }
93
+
90
94
  // Convert JSON to CSV
91
95
  jsonToCsv('[{"a":1,"b":2}]');
92
96
 
@@ -278,7 +282,7 @@ inferCsvColumnTypes("id,price,active\n1,9.99,true\n2,5,false");
278
282
 
279
283
  ```ts
280
284
  import { generateUuid, generateV4, generateV7, generateUlid,
281
- generatePassword, checkStrength, estimatePasswordEntropy, generateData } from "@utilix-tech/sdk/generators";
285
+ generatePassword, checkStrength, estimatePasswordEntropy, generateData, generateCspNonce } from "@utilix-tech/sdk/generators";
282
286
 
283
287
  generateUuid(); // "f47ac10b-58cc-4372-a567-0e02b2c3d479" (v4)
284
288
  generateV7(); // time-ordered UUID v7
@@ -296,6 +300,10 @@ generateData([
296
300
  { name: "email", type: "email" },
297
301
  { name: "age", type: "number" },
298
302
  ], 10); // 10 rows
303
+
304
+ // Cryptographically random CSP nonce, plus ready-to-paste snippets
305
+ generateCspNonce(16);
306
+ // { nonce: "...", scriptSrcDirective: "script-src 'nonce-...'", scriptTag: '<script nonce="...">' }
299
307
  ```
300
308
 
301
309
  ---
@@ -331,7 +339,7 @@ formatIso8601Duration(90061); // { iso: "P1DT1H1M1S", ... }
331
339
  ### `/units`: Conversions
332
340
 
333
341
  ```ts
334
- import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate, calculateRuleOf72, calculateEmi, calculateRoi, compareUnitPrices, calculatePaybackPeriod, calculateCdMaturity, calculateDepreciationSchedule, calculateCashRounding, calculateMovingAverages, calculateGpa, calculateCreditUtilization, calculateDebtToIncomeRatio } from "@utilix-tech/sdk/units";
342
+ import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate, calculateRuleOf72, calculateEmi, calculateRoi, compareUnitPrices, calculatePaybackPeriod, calculateCdMaturity, calculateDepreciationSchedule, calculateCashRounding, calculateMovingAverages, calculateGpa, calculateCreditUtilization, calculateDebtToIncomeRatio, calculateBlendedLoanRate } from "@utilix-tech/sdk/units";
335
343
 
336
344
  // File sizes
337
345
  convertBytes(1073741824, "GB"); // 1
@@ -487,7 +495,8 @@ import { getStatusCode, isValidIp, isValidIpv4, isValidIpv6,
487
495
  buildRangeHeader, parseContentRangeHeader, buildVaryHeader, parseVaryHeader, validateManifest,
488
496
  buildPermissionsPolicy, parsePermissionsPolicy, buildClientHints, parseClientHintHeaders,
489
497
  buildContentDisposition, parseContentDisposition,
490
- buildXContentTypeOptionsHeader, parseXContentTypeOptionsHeader, assessContentTypeRisk } from "@utilix-tech/sdk/network";
498
+ buildXContentTypeOptionsHeader, parseXContentTypeOptionsHeader, assessContentTypeRisk,
499
+ buildAcceptLanguage, parseAcceptLanguage } from "@utilix-tech/sdk/network";
491
500
 
492
501
  getStatusCode(404);
493
502
  // { code: 404, text: "Not Found", description: "...", category: "Client Error" }
@@ -855,12 +864,12 @@ inspectGifFrames(new Uint8Array(gifBytes));
855
864
 
856
865
  | Import | What it does |
857
866
  |---|---|
858
- | `@utilix-tech/sdk/json` | Format, minify, diff, validate, JSONPath, CSV↔JSON, YAML↔JSON, TS types from data or from a JSON Schema |
867
+ | `@utilix-tech/sdk/json` | Format, minify, diff, validate, JSONPath, JSON Pointer, RFC 7396 merge patch, CSV↔JSON, YAML↔JSON, TS types from data or from a JSON Schema |
859
868
  | `@utilix-tech/sdk/encoding` | Base64, URL, HTML entities, Base32/Base58/Base62 encode/decode |
860
869
  | `@utilix-tech/sdk/hashing` | MD5, SHA-1/256/512, bcrypt, HMAC, .htpasswd, SRI hashes, content-hash ETag generation |
861
870
  | `@utilix-tech/sdk/text` | Case convert, slugify, word count, lorem ipsum, line ops, HTML→Markdown, Levenshtein/Damerau string distance, readability scoring, sentence length distribution, emoji lookup |
862
871
  | `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert, SRT/WebVTT subtitles, Markdown front matter parser, YAML anchor/alias resolver, CSV column type inferencer |
863
- | `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, entropy estimator, fake data |
872
+ | `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, entropy estimator, fake data, CSP nonce generator |
864
873
  | `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
865
874
  | `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode/ISBN validation, loan calculator, EMI calculator, compound/simple interest calculators, VAT/sales tax calculator, tip/bill split calculator, break-even point calculator, Rule of 72 calculator, savings goal calculator, ROI calculator, cash denomination/till calculator, payback period calculator, CD maturity calculator, debt-to-income ratio calculator |
866
875
  | `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing, User-Agent parsing, IPv6 address compress/expand, Permissions-Policy header builder, Client Hints header builder/parser, Content-Disposition header builder/parser, X-Content-Type-Options header builder/risk assessor, sitemap.xml validator, sitemap index splitter |
@@ -4,6 +4,7 @@ import * as yaml from 'js-yaml';
4
4
  // src/tools/json.ts
5
5
  var json_exports = {};
6
6
  __export(json_exports, {
7
+ applyJsonMergePatch: () => applyJsonMergePatch,
7
8
  csvToJson: () => csvToJson,
8
9
  detectFormat: () => detectFormat,
9
10
  diffJson: () => diffJson,
@@ -22,6 +23,7 @@ __export(json_exports, {
22
23
  jsonToTypescript: () => jsonToTypescript,
23
24
  jsonToYaml: () => jsonToYaml,
24
25
  jsonToZod: () => jsonToZod,
26
+ mergeJsonPatch: () => mergeJsonPatch,
25
27
  minifyJson: () => minifyJson,
26
28
  parseJson: () => parseJson,
27
29
  parseStructs: () => parseStructs,
@@ -1402,5 +1404,36 @@ function jsonSchemaToTypescript(schemaJson, options) {
1402
1404
  }
1403
1405
  return parts.join("\n\n");
1404
1406
  }
1407
+ function _isMergePatchObject(value) {
1408
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1409
+ }
1410
+ function mergeJsonPatch(target, patch) {
1411
+ if (!_isMergePatchObject(patch)) return patch;
1412
+ const result = _isMergePatchObject(target) ? { ...target } : {};
1413
+ for (const key of Object.keys(patch)) {
1414
+ const value = patch[key];
1415
+ if (value === null) {
1416
+ delete result[key];
1417
+ } else {
1418
+ result[key] = mergeJsonPatch(result[key], value);
1419
+ }
1420
+ }
1421
+ return result;
1422
+ }
1423
+ function applyJsonMergePatch(targetJson, patchJson) {
1424
+ let target;
1425
+ try {
1426
+ target = JSON.parse(targetJson);
1427
+ } catch {
1428
+ return { error: "Target is not valid JSON" };
1429
+ }
1430
+ let patch;
1431
+ try {
1432
+ patch = JSON.parse(patchJson);
1433
+ } catch {
1434
+ return { error: "Patch is not valid JSON" };
1435
+ }
1436
+ return { result: mergeJsonPatch(target, patch) };
1437
+ }
1405
1438
 
1406
- export { csvToJson, detectFormat, diffJson, evaluateJsonPath, formatDiffLine, formatJson, generateExample, getJsonStats, inferGoType, inferPythonType, inferType, jsonSchemaToTypescript, jsonToCsv, jsonToGo, jsonToPython, jsonToTypescript, jsonToYaml, jsonToZod, json_exports, minifyJson, parseJson, parseStructs, resolveJsonPointer, toPascalCase, toSnakeCase, validateJson, validateJsonPath, validateJsonString, yamlToJson };
1439
+ export { applyJsonMergePatch, csvToJson, detectFormat, diffJson, evaluateJsonPath, formatDiffLine, formatJson, generateExample, getJsonStats, inferGoType, inferPythonType, inferType, jsonSchemaToTypescript, jsonToCsv, jsonToGo, jsonToPython, jsonToTypescript, jsonToYaml, jsonToZod, json_exports, mergeJsonPatch, minifyJson, parseJson, parseStructs, resolveJsonPointer, toPascalCase, toSnakeCase, validateJson, validateJsonPath, validateJsonString, yamlToJson };
@@ -16,6 +16,7 @@ __export(generators_exports, {
16
16
  generateBulk: () => generateBulk,
17
17
  generateBulkPasswords: () => generateBulkPasswords,
18
18
  generateBulkUlids: () => generateBulkUlids,
19
+ generateCspNonce: () => generateCspNonce,
19
20
  generateData: () => generateData,
20
21
  generatePassword: () => generatePassword,
21
22
  generateQrDataUrl: () => generateQrDataUrl,
@@ -622,5 +623,19 @@ async function generateQrDataUrl(text, options) {
622
623
  }
623
624
  });
624
625
  }
626
+ function generateCspNonce(byteLength = 16) {
627
+ if (!Number.isInteger(byteLength) || byteLength < 8 || byteLength > 64) {
628
+ return { error: "Byte length must be a whole number between 8 and 64" };
629
+ }
630
+ const nonce = randomBytes(byteLength).toString("base64");
631
+ return {
632
+ nonce,
633
+ byteLength,
634
+ scriptSrcDirective: `script-src 'nonce-${nonce}'`,
635
+ styleSrcDirective: `style-src 'nonce-${nonce}'`,
636
+ scriptTag: `<script nonce="${nonce}">`,
637
+ styleTag: `<style nonce="${nonce}">`
638
+ };
639
+ }
625
640
 
626
- export { AMBIGUOUS_CHARS, DATA_TYPES, DEFAULT_OPTIONS, DEFAULT_QR_OPTIONS, SYMBOL_CHARS, ULID_REGEX, checkStrength, estimatePasswordEntropy, generateBulk, generateBulkPasswords, generateBulkUlids, generateData, generatePassword, generateQrDataUrl, generateQrSvg, generateSingle, generateUlid, generateUuid, generateV4, generateV7, generators_exports, isValidUlid, isValidUuid, parseUlid, parseUuidVersion };
641
+ export { AMBIGUOUS_CHARS, DATA_TYPES, DEFAULT_OPTIONS, DEFAULT_QR_OPTIONS, SYMBOL_CHARS, ULID_REGEX, checkStrength, estimatePasswordEntropy, generateBulk, generateBulkPasswords, generateBulkUlids, generateCspNonce, generateData, generatePassword, generateQrDataUrl, generateQrSvg, generateSingle, generateUlid, generateUuid, generateV4, generateV7, generators_exports, isValidUlid, isValidUuid, parseUlid, parseUuidVersion };
@@ -21,6 +21,7 @@ __export(units_exports, {
21
21
  bumpVersion: () => bumpVersion,
22
22
  calcAspectRatio: () => calcAspectRatio,
23
23
  calcSubnet: () => calcSubnet,
24
+ calculateBlendedLoanRate: () => calculateBlendedLoanRate,
24
25
  calculateBreakEven: () => calculateBreakEven,
25
26
  calculateCashBreakdown: () => calculateCashBreakdown,
26
27
  calculateCashRounding: () => calculateCashRounding,
@@ -2271,5 +2272,44 @@ function calculateDebtToIncomeRatio(debts, grossMonthlyIncome) {
2271
2272
  tier: _classifyDti(dtiPercent)
2272
2273
  };
2273
2274
  }
2275
+ function calculateBlendedLoanRate(loans) {
2276
+ if (!Array.isArray(loans) || loans.length === 0) {
2277
+ return { error: "loans must be a non-empty array" };
2278
+ }
2279
+ const round22 = (n) => Math.round(n * 100) / 100;
2280
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
2281
+ let totalBalance = 0;
2282
+ for (let i = 0; i < loans.length; i++) {
2283
+ const loan = loans[i];
2284
+ if (typeof loan.balance !== "number" || !Number.isFinite(loan.balance) || loan.balance <= 0) {
2285
+ return { error: `loan ${i + 1}: balance must be a finite number greater than zero` };
2286
+ }
2287
+ if (typeof loan.ratePercent !== "number" || !Number.isFinite(loan.ratePercent) || loan.ratePercent < 0) {
2288
+ return { error: `loan ${i + 1}: ratePercent must be a finite, non-negative number` };
2289
+ }
2290
+ totalBalance += loan.balance;
2291
+ }
2292
+ let totalMonthlyInterest = 0;
2293
+ let weightedRateSum = 0;
2294
+ const results = loans.map((loan, i) => {
2295
+ const monthlyInterest = round22(loan.balance * loan.ratePercent / 100 / 12);
2296
+ totalMonthlyInterest += monthlyInterest;
2297
+ weightedRateSum += loan.balance * loan.ratePercent;
2298
+ return {
2299
+ label: loan.label?.trim() || `Loan ${i + 1}`,
2300
+ balance: loan.balance,
2301
+ ratePercent: loan.ratePercent,
2302
+ monthlyInterest,
2303
+ shareOfTotalPercent: round22(loan.balance / totalBalance * 100)
2304
+ };
2305
+ });
2306
+ return {
2307
+ loans: results,
2308
+ totalBalance: round22(totalBalance),
2309
+ weightedAverageRatePercent: round4(weightedRateSum / totalBalance),
2310
+ totalMonthlyInterest: round22(totalMonthlyInterest),
2311
+ totalAnnualInterest: round22(totalMonthlyInterest * 12)
2312
+ };
2313
+ }
2274
2314
 
2275
- export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_TAX_RATES, COMMON_TIP_PERCENTAGES, COMMON_VIEWPORTS, GPA_GRADE_POINTS, USD_DENOMINATIONS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCashBreakdown, calculateCashRounding, calculateCdMaturity, calculateChange, calculateCompoundInterest, calculateCreditUtilization, calculateDebtToIncomeRatio, calculateDepreciationSchedule, calculateDiscount, calculateEmi, calculateGpa, calculateLoan, calculateMarginMarkup, calculateMovingAverages, calculatePaybackPeriod, calculatePercentageChange, calculateRoi, calculateRuleOf72, calculateSavingsGoal, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, compareUnitPrices, convert, convertAprApy, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, marginToMarkup, markupToMargin, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx };
2315
+ export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_TAX_RATES, COMMON_TIP_PERCENTAGES, COMMON_VIEWPORTS, GPA_GRADE_POINTS, USD_DENOMINATIONS, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBlendedLoanRate, calculateBreakEven, calculateCashBreakdown, calculateCashRounding, calculateCdMaturity, calculateChange, calculateCompoundInterest, calculateCreditUtilization, calculateDebtToIncomeRatio, calculateDepreciationSchedule, calculateDiscount, calculateEmi, calculateGpa, calculateLoan, calculateMarginMarkup, calculateMovingAverages, calculatePaybackPeriod, calculatePercentageChange, calculateRoi, calculateRuleOf72, calculateSavingsGoal, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, compareUnitPrices, convert, convertAprApy, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, marginToMarkup, markupToMargin, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx };
@@ -13,6 +13,7 @@ __export(network_exports, {
13
13
  X_CONTENT_TYPE_OPTIONS_HEADER: () => X_CONTENT_TYPE_OPTIONS_HEADER,
14
14
  analyzeEmailHeaders: () => analyzeEmailHeaders,
15
15
  assessContentTypeRisk: () => assessContentTypeRisk,
16
+ buildAcceptLanguage: () => buildAcceptLanguage,
16
17
  buildCacheControl: () => buildCacheControl,
17
18
  buildClientHints: () => buildClientHints,
18
19
  buildContentDisposition: () => buildContentDisposition,
@@ -40,6 +41,7 @@ __export(network_exports, {
40
41
  isValidIp: () => isValidIp,
41
42
  isValidIpv4: () => isValidIpv4,
42
43
  isValidIpv6: () => isValidIpv6,
44
+ parseAcceptLanguage: () => parseAcceptLanguage,
43
45
  parseClientHintHeaders: () => parseClientHintHeaders,
44
46
  parseContentDisposition: () => parseContentDisposition,
45
47
  parseContentRangeHeader: () => parseContentRangeHeader,
@@ -2832,5 +2834,57 @@ function assessContentTypeRisk(contentType) {
2832
2834
  reason: "Not a well-known type in this tool's lookup table. Treat any response type as sniffable unless you've confirmed the serving browser trusts it, and set nosniff regardless of type as a baseline defense."
2833
2835
  };
2834
2836
  }
2837
+ function formatAcceptLanguageQuality(q) {
2838
+ let s = q.toFixed(3);
2839
+ s = s.replace(/0+$/, "");
2840
+ s = s.replace(/\.$/, "");
2841
+ return s;
2842
+ }
2843
+ function formatAcceptLanguageEntries(entries) {
2844
+ return entries.map((e) => e.quality === 1 ? e.locale : `${e.locale};q=${formatAcceptLanguageQuality(e.quality)}`).join(", ");
2845
+ }
2846
+ function sortAcceptLanguageEntries(entries) {
2847
+ return entries.map((e, i) => ({ e, i })).sort((a, b) => b.e.quality - a.e.quality || a.i - b.i).map((x) => x.e);
2848
+ }
2849
+ function buildAcceptLanguage(locales) {
2850
+ if (!Array.isArray(locales) || locales.length === 0) return { error: "At least one locale is required" };
2851
+ const entries = [];
2852
+ for (let i = 0; i < locales.length; i++) {
2853
+ const { locale, quality } = locales[i];
2854
+ if (typeof locale !== "string" || locale.trim() === "") return { error: `locale ${i + 1}: locale is required` };
2855
+ const q = quality === void 0 ? 1 : quality;
2856
+ if (typeof q !== "number" || !Number.isFinite(q) || q < 0 || q > 1) {
2857
+ return { error: `locale ${i + 1}: quality must be between 0 and 1` };
2858
+ }
2859
+ entries.push({ locale: locale.trim(), quality: Math.round(q * 1e3) / 1e3 });
2860
+ }
2861
+ const sorted = sortAcceptLanguageEntries(entries);
2862
+ const headerValue = formatAcceptLanguageEntries(sorted);
2863
+ return { header: `Accept-Language: ${headerValue}`, headerValue, entries: sorted };
2864
+ }
2865
+ function parseAcceptLanguage(raw) {
2866
+ if (!raw || raw.trim() === "") return { error: "Input is empty" };
2867
+ const withoutLabel = raw.trim().replace(/^accept-language:\s*/i, "");
2868
+ const parts = withoutLabel.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
2869
+ if (parts.length === 0) return { error: "Input is empty" };
2870
+ const entries = [];
2871
+ for (const part of parts) {
2872
+ const [localeRaw, ...paramsRaw] = part.split(";").map((s) => s.trim());
2873
+ if (!localeRaw) return { error: `Invalid entry: "${part}"` };
2874
+ let quality = 1;
2875
+ for (const param of paramsRaw) {
2876
+ const m = /^q=([\d.]+)$/i.exec(param);
2877
+ if (!m) return { error: `Invalid parameter in "${part}"` };
2878
+ quality = Number(m[1]);
2879
+ if (!Number.isFinite(quality) || quality < 0 || quality > 1) {
2880
+ return { error: `q value must be between 0 and 1 in "${part}"` };
2881
+ }
2882
+ }
2883
+ entries.push({ locale: localeRaw, quality: Math.round(quality * 1e3) / 1e3 });
2884
+ }
2885
+ const sorted = sortAcceptLanguageEntries(entries);
2886
+ const headerValue = formatAcceptLanguageEntries(sorted);
2887
+ return { header: `Accept-Language: ${headerValue}`, headerValue, entries: sorted };
2888
+ }
2835
2889
 
2836
- export { CLIENT_HINTS, DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, PERMISSIONS_POLICY_FEATURES, REFERRER_POLICY_VALUES, STATUS_CODES, X_CONTENT_TYPE_OPTIONS_HEADER, analyzeEmailHeaders, assessContentTypeRisk, buildCacheControl, buildClientHints, buildContentDisposition, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildPermissionsPolicy, buildRangeHeader, buildReferrerPolicy, buildVaryHeader, buildXContentTypeOptionsHeader, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, network_exports, parseClientHintHeaders, parseContentDisposition, parseContentRangeHeader, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parsePermissionsPolicy, parseUserAgent, parseVaryHeader, parseXContentTypeOptionsHeader, searchHeaders, searchStatusCodes, splitSitemap, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateManifest, validateRobotsTxt, validateSitemap };
2890
+ export { CLIENT_HINTS, DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, PERMISSIONS_POLICY_FEATURES, REFERRER_POLICY_VALUES, STATUS_CODES, X_CONTENT_TYPE_OPTIONS_HEADER, analyzeEmailHeaders, assessContentTypeRisk, buildAcceptLanguage, buildCacheControl, buildClientHints, buildContentDisposition, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildPermissionsPolicy, buildRangeHeader, buildReferrerPolicy, buildVaryHeader, buildXContentTypeOptionsHeader, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, network_exports, parseAcceptLanguage, parseClientHintHeaders, parseContentDisposition, parseContentRangeHeader, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parsePermissionsPolicy, parseUserAgent, parseVaryHeader, parseXContentTypeOptionsHeader, searchHeaders, searchStatusCodes, splitSitemap, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateManifest, validateRobotsTxt, validateSitemap };
@@ -10,6 +10,7 @@
10
10
  * - password-entropy-estimator : estimatePasswordEntropy
11
11
  * - random-data : generateSingle, generateData
12
12
  * - qr-code : generateQrSvg, generateQrDataUrl
13
+ * - csp-nonce-generator : generateCspNonce
13
14
  */
14
15
  type UuidVersion = 'v4' | 'v7';
15
16
  interface GeneratedUuid {
@@ -117,8 +118,27 @@ interface QrOptions {
117
118
  declare const DEFAULT_QR_OPTIONS: QrOptions;
118
119
  declare function generateQrSvg(text: string, options?: QrOptions): Promise<string>;
119
120
  declare function generateQrDataUrl(text: string, options?: QrOptions): Promise<string>;
121
+ interface CspNonceResult {
122
+ nonce: string;
123
+ byteLength: number;
124
+ scriptSrcDirective: string;
125
+ styleSrcDirective: string;
126
+ scriptTag: string;
127
+ styleTag: string;
128
+ }
129
+ /**
130
+ * Generate a cryptographically random, base64-encoded nonce for a
131
+ * Content-Security-Policy script-src/style-src directive, along with
132
+ * ready-to-paste header directive and <script>/<style nonce="..."> tag
133
+ * snippets. Generates a fresh value on every call; the same value must be
134
+ * reused for both the header and the markup within a single request.
135
+ */
136
+ declare function generateCspNonce(byteLength?: number): CspNonceResult | {
137
+ error: string;
138
+ };
120
139
 
121
140
  declare const generators_AMBIGUOUS_CHARS: typeof AMBIGUOUS_CHARS;
141
+ type generators_CspNonceResult = CspNonceResult;
122
142
  declare const generators_DATA_TYPES: typeof DATA_TYPES;
123
143
  declare const generators_DEFAULT_OPTIONS: typeof DEFAULT_OPTIONS;
124
144
  declare const generators_DEFAULT_QR_OPTIONS: typeof DEFAULT_QR_OPTIONS;
@@ -141,6 +161,7 @@ declare const generators_estimatePasswordEntropy: typeof estimatePasswordEntropy
141
161
  declare const generators_generateBulk: typeof generateBulk;
142
162
  declare const generators_generateBulkPasswords: typeof generateBulkPasswords;
143
163
  declare const generators_generateBulkUlids: typeof generateBulkUlids;
164
+ declare const generators_generateCspNonce: typeof generateCspNonce;
144
165
  declare const generators_generateData: typeof generateData;
145
166
  declare const generators_generatePassword: typeof generatePassword;
146
167
  declare const generators_generateQrDataUrl: typeof generateQrDataUrl;
@@ -155,7 +176,7 @@ declare const generators_isValidUuid: typeof isValidUuid;
155
176
  declare const generators_parseUlid: typeof parseUlid;
156
177
  declare const generators_parseUuidVersion: typeof parseUuidVersion;
157
178
  declare namespace generators {
158
- export { generators_AMBIGUOUS_CHARS as AMBIGUOUS_CHARS, generators_DATA_TYPES as DATA_TYPES, generators_DEFAULT_OPTIONS as DEFAULT_OPTIONS, generators_DEFAULT_QR_OPTIONS as DEFAULT_QR_OPTIONS, type generators_DataType as DataType, type generators_GeneratedUuid as GeneratedUuid, type generators_PasswordCharsetInfo as PasswordCharsetInfo, type generators_PasswordCrackTimeEstimate as PasswordCrackTimeEstimate, type generators_PasswordEntropyResult as PasswordEntropyResult, type generators_PasswordEntropyStrength as PasswordEntropyStrength, type generators_PasswordOptions as PasswordOptions, type generators_QrErrorLevel as QrErrorLevel, type generators_QrOptions as QrOptions, type generators_QrOutputFormat as QrOutputFormat, type generators_RandomConfig as RandomConfig, generators_SYMBOL_CHARS as SYMBOL_CHARS, generators_ULID_REGEX as ULID_REGEX, type generators_UuidVersion as UuidVersion, generators_checkStrength as checkStrength, generators_estimatePasswordEntropy as estimatePasswordEntropy, generators_generateBulk as generateBulk, generators_generateBulkPasswords as generateBulkPasswords, generators_generateBulkUlids as generateBulkUlids, generators_generateData as generateData, generators_generatePassword as generatePassword, generators_generateQrDataUrl as generateQrDataUrl, generators_generateQrSvg as generateQrSvg, generators_generateSingle as generateSingle, generators_generateUlid as generateUlid, generators_generateUuid as generateUuid, generators_generateV4 as generateV4, generators_generateV7 as generateV7, generators_isValidUlid as isValidUlid, generators_isValidUuid as isValidUuid, generators_parseUlid as parseUlid, generators_parseUuidVersion as parseUuidVersion };
179
+ export { generators_AMBIGUOUS_CHARS as AMBIGUOUS_CHARS, type generators_CspNonceResult as CspNonceResult, generators_DATA_TYPES as DATA_TYPES, generators_DEFAULT_OPTIONS as DEFAULT_OPTIONS, generators_DEFAULT_QR_OPTIONS as DEFAULT_QR_OPTIONS, type generators_DataType as DataType, type generators_GeneratedUuid as GeneratedUuid, type generators_PasswordCharsetInfo as PasswordCharsetInfo, type generators_PasswordCrackTimeEstimate as PasswordCrackTimeEstimate, type generators_PasswordEntropyResult as PasswordEntropyResult, type generators_PasswordEntropyStrength as PasswordEntropyStrength, type generators_PasswordOptions as PasswordOptions, type generators_QrErrorLevel as QrErrorLevel, type generators_QrOptions as QrOptions, type generators_QrOutputFormat as QrOutputFormat, type generators_RandomConfig as RandomConfig, generators_SYMBOL_CHARS as SYMBOL_CHARS, generators_ULID_REGEX as ULID_REGEX, type generators_UuidVersion as UuidVersion, generators_checkStrength as checkStrength, generators_estimatePasswordEntropy as estimatePasswordEntropy, generators_generateBulk as generateBulk, generators_generateBulkPasswords as generateBulkPasswords, generators_generateBulkUlids as generateBulkUlids, generators_generateCspNonce as generateCspNonce, generators_generateData as generateData, generators_generatePassword as generatePassword, generators_generateQrDataUrl as generateQrDataUrl, generators_generateQrSvg as generateQrSvg, generators_generateSingle as generateSingle, generators_generateUlid as generateUlid, generators_generateUuid as generateUuid, generators_generateV4 as generateV4, generators_generateV7 as generateV7, generators_isValidUlid as isValidUlid, generators_isValidUuid as isValidUuid, generators_parseUlid as parseUlid, generators_parseUuidVersion as parseUuidVersion };
159
180
  }
160
181
 
161
- export { AMBIGUOUS_CHARS as A, isValidUuid as B, parseUlid as C, DATA_TYPES as D, parseUuidVersion as E, type GeneratedUuid as G, type PasswordCharsetInfo as P, type QrErrorLevel as Q, type RandomConfig as R, SYMBOL_CHARS as S, ULID_REGEX as U, DEFAULT_OPTIONS as a, DEFAULT_QR_OPTIONS as b, type DataType as c, type PasswordCrackTimeEstimate as d, type PasswordEntropyResult as e, type PasswordEntropyStrength as f, generators as g, type PasswordOptions as h, type QrOptions as i, type QrOutputFormat as j, type UuidVersion as k, checkStrength as l, estimatePasswordEntropy as m, generateBulk as n, generateBulkPasswords as o, generateBulkUlids as p, generateData as q, generatePassword as r, generateQrDataUrl as s, generateQrSvg as t, generateSingle as u, generateUlid as v, generateUuid as w, generateV4 as x, generateV7 as y, isValidUlid as z };
182
+ export { AMBIGUOUS_CHARS as A, isValidUlid as B, type CspNonceResult as C, DATA_TYPES as D, isValidUuid as E, parseUlid as F, type GeneratedUuid as G, parseUuidVersion as H, type PasswordCharsetInfo as P, type QrErrorLevel as Q, type RandomConfig as R, SYMBOL_CHARS as S, ULID_REGEX as U, DEFAULT_OPTIONS as a, DEFAULT_QR_OPTIONS as b, type DataType as c, type PasswordCrackTimeEstimate as d, type PasswordEntropyResult as e, type PasswordEntropyStrength as f, generators as g, type PasswordOptions as h, type QrOptions as i, type QrOutputFormat as j, type UuidVersion as k, checkStrength as l, estimatePasswordEntropy as m, generateBulk as n, generateBulkPasswords as o, generateBulkUlids as p, generateCspNonce as q, generateData as r, generatePassword as s, generateQrDataUrl as t, generateQrSvg as u, generateSingle as v, generateUlid as w, generateUuid as x, generateV4 as y, generateV7 as z };
@@ -10,6 +10,7 @@
10
10
  * - password-entropy-estimator : estimatePasswordEntropy
11
11
  * - random-data : generateSingle, generateData
12
12
  * - qr-code : generateQrSvg, generateQrDataUrl
13
+ * - csp-nonce-generator : generateCspNonce
13
14
  */
14
15
  type UuidVersion = 'v4' | 'v7';
15
16
  interface GeneratedUuid {
@@ -117,8 +118,27 @@ interface QrOptions {
117
118
  declare const DEFAULT_QR_OPTIONS: QrOptions;
118
119
  declare function generateQrSvg(text: string, options?: QrOptions): Promise<string>;
119
120
  declare function generateQrDataUrl(text: string, options?: QrOptions): Promise<string>;
121
+ interface CspNonceResult {
122
+ nonce: string;
123
+ byteLength: number;
124
+ scriptSrcDirective: string;
125
+ styleSrcDirective: string;
126
+ scriptTag: string;
127
+ styleTag: string;
128
+ }
129
+ /**
130
+ * Generate a cryptographically random, base64-encoded nonce for a
131
+ * Content-Security-Policy script-src/style-src directive, along with
132
+ * ready-to-paste header directive and <script>/<style nonce="..."> tag
133
+ * snippets. Generates a fresh value on every call; the same value must be
134
+ * reused for both the header and the markup within a single request.
135
+ */
136
+ declare function generateCspNonce(byteLength?: number): CspNonceResult | {
137
+ error: string;
138
+ };
120
139
 
121
140
  declare const generators_AMBIGUOUS_CHARS: typeof AMBIGUOUS_CHARS;
141
+ type generators_CspNonceResult = CspNonceResult;
122
142
  declare const generators_DATA_TYPES: typeof DATA_TYPES;
123
143
  declare const generators_DEFAULT_OPTIONS: typeof DEFAULT_OPTIONS;
124
144
  declare const generators_DEFAULT_QR_OPTIONS: typeof DEFAULT_QR_OPTIONS;
@@ -141,6 +161,7 @@ declare const generators_estimatePasswordEntropy: typeof estimatePasswordEntropy
141
161
  declare const generators_generateBulk: typeof generateBulk;
142
162
  declare const generators_generateBulkPasswords: typeof generateBulkPasswords;
143
163
  declare const generators_generateBulkUlids: typeof generateBulkUlids;
164
+ declare const generators_generateCspNonce: typeof generateCspNonce;
144
165
  declare const generators_generateData: typeof generateData;
145
166
  declare const generators_generatePassword: typeof generatePassword;
146
167
  declare const generators_generateQrDataUrl: typeof generateQrDataUrl;
@@ -155,7 +176,7 @@ declare const generators_isValidUuid: typeof isValidUuid;
155
176
  declare const generators_parseUlid: typeof parseUlid;
156
177
  declare const generators_parseUuidVersion: typeof parseUuidVersion;
157
178
  declare namespace generators {
158
- export { generators_AMBIGUOUS_CHARS as AMBIGUOUS_CHARS, generators_DATA_TYPES as DATA_TYPES, generators_DEFAULT_OPTIONS as DEFAULT_OPTIONS, generators_DEFAULT_QR_OPTIONS as DEFAULT_QR_OPTIONS, type generators_DataType as DataType, type generators_GeneratedUuid as GeneratedUuid, type generators_PasswordCharsetInfo as PasswordCharsetInfo, type generators_PasswordCrackTimeEstimate as PasswordCrackTimeEstimate, type generators_PasswordEntropyResult as PasswordEntropyResult, type generators_PasswordEntropyStrength as PasswordEntropyStrength, type generators_PasswordOptions as PasswordOptions, type generators_QrErrorLevel as QrErrorLevel, type generators_QrOptions as QrOptions, type generators_QrOutputFormat as QrOutputFormat, type generators_RandomConfig as RandomConfig, generators_SYMBOL_CHARS as SYMBOL_CHARS, generators_ULID_REGEX as ULID_REGEX, type generators_UuidVersion as UuidVersion, generators_checkStrength as checkStrength, generators_estimatePasswordEntropy as estimatePasswordEntropy, generators_generateBulk as generateBulk, generators_generateBulkPasswords as generateBulkPasswords, generators_generateBulkUlids as generateBulkUlids, generators_generateData as generateData, generators_generatePassword as generatePassword, generators_generateQrDataUrl as generateQrDataUrl, generators_generateQrSvg as generateQrSvg, generators_generateSingle as generateSingle, generators_generateUlid as generateUlid, generators_generateUuid as generateUuid, generators_generateV4 as generateV4, generators_generateV7 as generateV7, generators_isValidUlid as isValidUlid, generators_isValidUuid as isValidUuid, generators_parseUlid as parseUlid, generators_parseUuidVersion as parseUuidVersion };
179
+ export { generators_AMBIGUOUS_CHARS as AMBIGUOUS_CHARS, type generators_CspNonceResult as CspNonceResult, generators_DATA_TYPES as DATA_TYPES, generators_DEFAULT_OPTIONS as DEFAULT_OPTIONS, generators_DEFAULT_QR_OPTIONS as DEFAULT_QR_OPTIONS, type generators_DataType as DataType, type generators_GeneratedUuid as GeneratedUuid, type generators_PasswordCharsetInfo as PasswordCharsetInfo, type generators_PasswordCrackTimeEstimate as PasswordCrackTimeEstimate, type generators_PasswordEntropyResult as PasswordEntropyResult, type generators_PasswordEntropyStrength as PasswordEntropyStrength, type generators_PasswordOptions as PasswordOptions, type generators_QrErrorLevel as QrErrorLevel, type generators_QrOptions as QrOptions, type generators_QrOutputFormat as QrOutputFormat, type generators_RandomConfig as RandomConfig, generators_SYMBOL_CHARS as SYMBOL_CHARS, generators_ULID_REGEX as ULID_REGEX, type generators_UuidVersion as UuidVersion, generators_checkStrength as checkStrength, generators_estimatePasswordEntropy as estimatePasswordEntropy, generators_generateBulk as generateBulk, generators_generateBulkPasswords as generateBulkPasswords, generators_generateBulkUlids as generateBulkUlids, generators_generateCspNonce as generateCspNonce, generators_generateData as generateData, generators_generatePassword as generatePassword, generators_generateQrDataUrl as generateQrDataUrl, generators_generateQrSvg as generateQrSvg, generators_generateSingle as generateSingle, generators_generateUlid as generateUlid, generators_generateUuid as generateUuid, generators_generateV4 as generateV4, generators_generateV7 as generateV7, generators_isValidUlid as isValidUlid, generators_isValidUuid as isValidUuid, generators_parseUlid as parseUlid, generators_parseUuidVersion as parseUuidVersion };
159
180
  }
160
181
 
161
- export { AMBIGUOUS_CHARS as A, isValidUuid as B, parseUlid as C, DATA_TYPES as D, parseUuidVersion as E, type GeneratedUuid as G, type PasswordCharsetInfo as P, type QrErrorLevel as Q, type RandomConfig as R, SYMBOL_CHARS as S, ULID_REGEX as U, DEFAULT_OPTIONS as a, DEFAULT_QR_OPTIONS as b, type DataType as c, type PasswordCrackTimeEstimate as d, type PasswordEntropyResult as e, type PasswordEntropyStrength as f, generators as g, type PasswordOptions as h, type QrOptions as i, type QrOutputFormat as j, type UuidVersion as k, checkStrength as l, estimatePasswordEntropy as m, generateBulk as n, generateBulkPasswords as o, generateBulkUlids as p, generateData as q, generatePassword as r, generateQrDataUrl as s, generateQrSvg as t, generateSingle as u, generateUlid as v, generateUuid as w, generateV4 as x, generateV7 as y, isValidUlid as z };
182
+ export { AMBIGUOUS_CHARS as A, isValidUlid as B, type CspNonceResult as C, DATA_TYPES as D, isValidUuid as E, parseUlid as F, type GeneratedUuid as G, parseUuidVersion as H, type PasswordCharsetInfo as P, type QrErrorLevel as Q, type RandomConfig as R, SYMBOL_CHARS as S, ULID_REGEX as U, DEFAULT_OPTIONS as a, DEFAULT_QR_OPTIONS as b, type DataType as c, type PasswordCrackTimeEstimate as d, type PasswordEntropyResult as e, type PasswordEntropyStrength as f, generators as g, type PasswordOptions as h, type QrOptions as i, type QrOutputFormat as j, type UuidVersion as k, checkStrength as l, estimatePasswordEntropy as m, generateBulk as n, generateBulkPasswords as o, generateBulkUlids as p, generateCspNonce as q, generateData as r, generatePassword as s, generateQrDataUrl as t, generateQrSvg as u, generateSingle as v, generateUlid as w, generateUuid as x, generateV4 as y, generateV7 as z };
package/dist/index.cjs CHANGED
@@ -42,6 +42,7 @@ var __export = (target, all) => {
42
42
  // src/tools/json.ts
43
43
  var json_exports = {};
44
44
  __export(json_exports, {
45
+ applyJsonMergePatch: () => applyJsonMergePatch,
45
46
  csvToJson: () => csvToJson,
46
47
  detectFormat: () => detectFormat,
47
48
  diffJson: () => diffJson,
@@ -60,6 +61,7 @@ __export(json_exports, {
60
61
  jsonToTypescript: () => jsonToTypescript,
61
62
  jsonToYaml: () => jsonToYaml,
62
63
  jsonToZod: () => jsonToZod,
64
+ mergeJsonPatch: () => mergeJsonPatch,
63
65
  minifyJson: () => minifyJson,
64
66
  parseJson: () => parseJson,
65
67
  parseStructs: () => parseStructs,
@@ -1440,6 +1442,37 @@ function jsonSchemaToTypescript(schemaJson, options) {
1440
1442
  }
1441
1443
  return parts.join("\n\n");
1442
1444
  }
1445
+ function _isMergePatchObject(value) {
1446
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1447
+ }
1448
+ function mergeJsonPatch(target, patch) {
1449
+ if (!_isMergePatchObject(patch)) return patch;
1450
+ const result = _isMergePatchObject(target) ? { ...target } : {};
1451
+ for (const key of Object.keys(patch)) {
1452
+ const value = patch[key];
1453
+ if (value === null) {
1454
+ delete result[key];
1455
+ } else {
1456
+ result[key] = mergeJsonPatch(result[key], value);
1457
+ }
1458
+ }
1459
+ return result;
1460
+ }
1461
+ function applyJsonMergePatch(targetJson, patchJson) {
1462
+ let target;
1463
+ try {
1464
+ target = JSON.parse(targetJson);
1465
+ } catch {
1466
+ return { error: "Target is not valid JSON" };
1467
+ }
1468
+ let patch;
1469
+ try {
1470
+ patch = JSON.parse(patchJson);
1471
+ } catch {
1472
+ return { error: "Patch is not valid JSON" };
1473
+ }
1474
+ return { result: mergeJsonPatch(target, patch) };
1475
+ }
1443
1476
 
1444
1477
  // src/tools/encoding.ts
1445
1478
  var encoding_exports = {};
@@ -6935,6 +6968,7 @@ __export(generators_exports, {
6935
6968
  generateBulk: () => generateBulk,
6936
6969
  generateBulkPasswords: () => generateBulkPasswords,
6937
6970
  generateBulkUlids: () => generateBulkUlids,
6971
+ generateCspNonce: () => generateCspNonce,
6938
6972
  generateData: () => generateData,
6939
6973
  generatePassword: () => generatePassword,
6940
6974
  generateQrDataUrl: () => generateQrDataUrl,
@@ -7541,6 +7575,20 @@ async function generateQrDataUrl(text, options) {
7541
7575
  }
7542
7576
  });
7543
7577
  }
7578
+ function generateCspNonce(byteLength = 16) {
7579
+ if (!Number.isInteger(byteLength) || byteLength < 8 || byteLength > 64) {
7580
+ return { error: "Byte length must be a whole number between 8 and 64" };
7581
+ }
7582
+ const nonce = crypto.randomBytes(byteLength).toString("base64");
7583
+ return {
7584
+ nonce,
7585
+ byteLength,
7586
+ scriptSrcDirective: `script-src 'nonce-${nonce}'`,
7587
+ styleSrcDirective: `style-src 'nonce-${nonce}'`,
7588
+ scriptTag: `<script nonce="${nonce}">`,
7589
+ styleTag: `<style nonce="${nonce}">`
7590
+ };
7591
+ }
7544
7592
 
7545
7593
  // src/tools/time.ts
7546
7594
  var time_exports = {};
@@ -8338,6 +8386,7 @@ __export(units_exports, {
8338
8386
  bumpVersion: () => bumpVersion,
8339
8387
  calcAspectRatio: () => calcAspectRatio,
8340
8388
  calcSubnet: () => calcSubnet,
8389
+ calculateBlendedLoanRate: () => calculateBlendedLoanRate,
8341
8390
  calculateBreakEven: () => calculateBreakEven,
8342
8391
  calculateCashBreakdown: () => calculateCashBreakdown,
8343
8392
  calculateCashRounding: () => calculateCashRounding,
@@ -10588,6 +10637,45 @@ function calculateDebtToIncomeRatio(debts, grossMonthlyIncome) {
10588
10637
  tier: _classifyDti(dtiPercent)
10589
10638
  };
10590
10639
  }
10640
+ function calculateBlendedLoanRate(loans) {
10641
+ if (!Array.isArray(loans) || loans.length === 0) {
10642
+ return { error: "loans must be a non-empty array" };
10643
+ }
10644
+ const round23 = (n) => Math.round(n * 100) / 100;
10645
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
10646
+ let totalBalance = 0;
10647
+ for (let i = 0; i < loans.length; i++) {
10648
+ const loan = loans[i];
10649
+ if (typeof loan.balance !== "number" || !Number.isFinite(loan.balance) || loan.balance <= 0) {
10650
+ return { error: `loan ${i + 1}: balance must be a finite number greater than zero` };
10651
+ }
10652
+ if (typeof loan.ratePercent !== "number" || !Number.isFinite(loan.ratePercent) || loan.ratePercent < 0) {
10653
+ return { error: `loan ${i + 1}: ratePercent must be a finite, non-negative number` };
10654
+ }
10655
+ totalBalance += loan.balance;
10656
+ }
10657
+ let totalMonthlyInterest = 0;
10658
+ let weightedRateSum = 0;
10659
+ const results = loans.map((loan, i) => {
10660
+ const monthlyInterest = round23(loan.balance * loan.ratePercent / 100 / 12);
10661
+ totalMonthlyInterest += monthlyInterest;
10662
+ weightedRateSum += loan.balance * loan.ratePercent;
10663
+ return {
10664
+ label: loan.label?.trim() || `Loan ${i + 1}`,
10665
+ balance: loan.balance,
10666
+ ratePercent: loan.ratePercent,
10667
+ monthlyInterest,
10668
+ shareOfTotalPercent: round23(loan.balance / totalBalance * 100)
10669
+ };
10670
+ });
10671
+ return {
10672
+ loans: results,
10673
+ totalBalance: round23(totalBalance),
10674
+ weightedAverageRatePercent: round4(weightedRateSum / totalBalance),
10675
+ totalMonthlyInterest: round23(totalMonthlyInterest),
10676
+ totalAnnualInterest: round23(totalMonthlyInterest * 12)
10677
+ };
10678
+ }
10591
10679
 
10592
10680
  // src/tools/network.ts
10593
10681
  var network_exports = {};
@@ -10602,6 +10690,7 @@ __export(network_exports, {
10602
10690
  X_CONTENT_TYPE_OPTIONS_HEADER: () => X_CONTENT_TYPE_OPTIONS_HEADER,
10603
10691
  analyzeEmailHeaders: () => analyzeEmailHeaders,
10604
10692
  assessContentTypeRisk: () => assessContentTypeRisk,
10693
+ buildAcceptLanguage: () => buildAcceptLanguage,
10605
10694
  buildCacheControl: () => buildCacheControl,
10606
10695
  buildClientHints: () => buildClientHints,
10607
10696
  buildContentDisposition: () => buildContentDisposition,
@@ -10629,6 +10718,7 @@ __export(network_exports, {
10629
10718
  isValidIp: () => isValidIp2,
10630
10719
  isValidIpv4: () => isValidIpv42,
10631
10720
  isValidIpv6: () => isValidIpv6,
10721
+ parseAcceptLanguage: () => parseAcceptLanguage,
10632
10722
  parseClientHintHeaders: () => parseClientHintHeaders,
10633
10723
  parseContentDisposition: () => parseContentDisposition,
10634
10724
  parseContentRangeHeader: () => parseContentRangeHeader,
@@ -13421,6 +13511,58 @@ function assessContentTypeRisk(contentType) {
13421
13511
  reason: "Not a well-known type in this tool's lookup table. Treat any response type as sniffable unless you've confirmed the serving browser trusts it, and set nosniff regardless of type as a baseline defense."
13422
13512
  };
13423
13513
  }
13514
+ function formatAcceptLanguageQuality(q) {
13515
+ let s = q.toFixed(3);
13516
+ s = s.replace(/0+$/, "");
13517
+ s = s.replace(/\.$/, "");
13518
+ return s;
13519
+ }
13520
+ function formatAcceptLanguageEntries(entries) {
13521
+ return entries.map((e) => e.quality === 1 ? e.locale : `${e.locale};q=${formatAcceptLanguageQuality(e.quality)}`).join(", ");
13522
+ }
13523
+ function sortAcceptLanguageEntries(entries) {
13524
+ return entries.map((e, i) => ({ e, i })).sort((a, b) => b.e.quality - a.e.quality || a.i - b.i).map((x) => x.e);
13525
+ }
13526
+ function buildAcceptLanguage(locales) {
13527
+ if (!Array.isArray(locales) || locales.length === 0) return { error: "At least one locale is required" };
13528
+ const entries = [];
13529
+ for (let i = 0; i < locales.length; i++) {
13530
+ const { locale, quality } = locales[i];
13531
+ if (typeof locale !== "string" || locale.trim() === "") return { error: `locale ${i + 1}: locale is required` };
13532
+ const q = quality === void 0 ? 1 : quality;
13533
+ if (typeof q !== "number" || !Number.isFinite(q) || q < 0 || q > 1) {
13534
+ return { error: `locale ${i + 1}: quality must be between 0 and 1` };
13535
+ }
13536
+ entries.push({ locale: locale.trim(), quality: Math.round(q * 1e3) / 1e3 });
13537
+ }
13538
+ const sorted = sortAcceptLanguageEntries(entries);
13539
+ const headerValue = formatAcceptLanguageEntries(sorted);
13540
+ return { header: `Accept-Language: ${headerValue}`, headerValue, entries: sorted };
13541
+ }
13542
+ function parseAcceptLanguage(raw) {
13543
+ if (!raw || raw.trim() === "") return { error: "Input is empty" };
13544
+ const withoutLabel = raw.trim().replace(/^accept-language:\s*/i, "");
13545
+ const parts = withoutLabel.split(",").map((p) => p.trim()).filter((p) => p.length > 0);
13546
+ if (parts.length === 0) return { error: "Input is empty" };
13547
+ const entries = [];
13548
+ for (const part of parts) {
13549
+ const [localeRaw, ...paramsRaw] = part.split(";").map((s) => s.trim());
13550
+ if (!localeRaw) return { error: `Invalid entry: "${part}"` };
13551
+ let quality = 1;
13552
+ for (const param of paramsRaw) {
13553
+ const m = /^q=([\d.]+)$/i.exec(param);
13554
+ if (!m) return { error: `Invalid parameter in "${part}"` };
13555
+ quality = Number(m[1]);
13556
+ if (!Number.isFinite(quality) || quality < 0 || quality > 1) {
13557
+ return { error: `q value must be between 0 and 1 in "${part}"` };
13558
+ }
13559
+ }
13560
+ entries.push({ locale: localeRaw, quality: Math.round(quality * 1e3) / 1e3 });
13561
+ }
13562
+ const sorted = sortAcceptLanguageEntries(entries);
13563
+ const headerValue = formatAcceptLanguageEntries(sorted);
13564
+ return { header: `Accept-Language: ${headerValue}`, headerValue, entries: sorted };
13565
+ }
13424
13566
 
13425
13567
  // src/tools/api.ts
13426
13568
  var api_exports = {};