@utilix-tech/sdk 0.24.0 → 0.26.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 +8 -0
- package/README.md +22 -6
- package/dist/{api-Xl7OzIgq.d.cts → api-DmTNE4c1.d.cts} +29 -2
- package/dist/{api-Xl7OzIgq.d.ts → api-DmTNE4c1.d.ts} +29 -2
- package/dist/{chunk-Q3B3YWOA.js → chunk-52ZDKSIX.js} +45 -2
- package/dist/{chunk-2I4O5YCT.js → chunk-AFEZ6N4A.js} +43 -1
- package/dist/{chunk-HZIS2DMJ.js → chunk-HP6C4VBX.js} +95 -1
- package/dist/index.cjs +179 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/{text-DS70aMY5.d.cts → text-D1fySkCB.d.cts} +30 -2
- package/dist/{text-DS70aMY5.d.ts → text-D1fySkCB.d.ts} +30 -2
- package/dist/tools/api.cjs +43 -0
- package/dist/tools/api.d.cts +1 -1
- package/dist/tools/api.d.ts +1 -1
- package/dist/tools/api.js +1 -1
- package/dist/tools/text.cjs +42 -0
- package/dist/tools/text.d.cts +1 -1
- package/dist/tools/text.d.ts +1 -1
- package/dist/tools/text.js +1 -1
- package/dist/tools/units.cjs +94 -0
- package/dist/tools/units.d.cts +1 -1
- package/dist/tools/units.d.ts +1 -1
- package/dist/tools/units.js +1 -1
- package/dist/{units-DAoSM2g8.d.ts → units-D2wEimKG.d.cts} +76 -2
- package/dist/{units-DAoSM2g8.d.cts → units-D2wEimKG.d.ts} +76 -2
- 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.26.0
|
|
6
|
+
- Add `computeJwkThumbprint` (jwk-thumbprint): RFC 7638 canonical thumbprint of a single JWK, hashed with SHA-256/384/512.
|
|
7
|
+
- Add `calculateVideoBitrate` (video-bitrate-calculator): resulting file size from a video/audio bitrate and duration, or the required bitrate to hit a target file size.
|
|
8
|
+
|
|
9
|
+
## 0.25.0
|
|
10
|
+
- Add `calculateBreakEven` (break-even-calculator): break-even unit count and revenue from fixed costs, variable cost per unit, and price per unit, plus profit and margin of safety at an optional sales volume.
|
|
11
|
+
- Add `calculateStringDistance` (string-distance): Levenshtein edit distance and normalized similarity between two strings, with an optional Damerau (transposition) mode.
|
|
12
|
+
|
|
5
13
|
## 0.24.0
|
|
6
14
|
- Add `calculateDiscount` / `applySuccessiveDiscounts` (discount-calculator): solve a sale price, amount saved, or discount percent from any one of them, and stack discounts in sequence where 20% then 10% is an effective 28% off.
|
|
7
15
|
- Add `parseSubtitles`, `convertSubtitles`, `shiftSubtitles`, and their timestamp/format helpers (subtitle-converter): convert between SubRip and WebVTT and shift every cue by a fixed offset.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/sdk
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**576 developer utility functions for Node.js: runs locally, no API key required.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
6
6
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
@@ -137,7 +137,7 @@ generateHtpasswdFile([{ username: "alice", password: "secret" }]);
|
|
|
137
137
|
```ts
|
|
138
138
|
import { convertCase, slugify, countWords, generateWords, generateParagraphs,
|
|
139
139
|
escapeString, htmlToMarkdown, applyOps, detectPassiveVoice, scoreReadability,
|
|
140
|
-
detectFillerWords } from "@utilix-tech/sdk/text";
|
|
140
|
+
detectFillerWords, calculateStringDistance } from "@utilix-tech/sdk/text";
|
|
141
141
|
|
|
142
142
|
convertCase("hello world", "camelCase"); // "helloWorld"
|
|
143
143
|
convertCase("hello world", "PascalCase"); // "HelloWorld"
|
|
@@ -166,6 +166,10 @@ scoreReadability("The cat sat on the mat. It was a sunny day.");
|
|
|
166
166
|
// Flag filler words, hedge phrases, and clichés with counts and density
|
|
167
167
|
detectFillerWords("At the end of the day, I just really think we should circle back.");
|
|
168
168
|
// { totalMatches: 4, fillerCount: 2, clicheCount: 2, density: 28.6, matches: [...] }
|
|
169
|
+
|
|
170
|
+
// Levenshtein edit distance + similarity ratio; pass mode: "damerau" to count a transposition as 1 edit
|
|
171
|
+
calculateStringDistance("kitten", "sitting");
|
|
172
|
+
// { distance: 3, similarity: 0.5714, maxLength: 7, mode: "levenshtein" }
|
|
169
173
|
```
|
|
170
174
|
|
|
171
175
|
---
|
|
@@ -268,7 +272,7 @@ formatIso8601Duration(90061); // { iso: "P1DT1H1M1S", ... }
|
|
|
268
272
|
### `/units`: Conversions
|
|
269
273
|
|
|
270
274
|
```ts
|
|
271
|
-
import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts } from "@utilix-tech/sdk/units";
|
|
275
|
+
import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode, calculateTax, calculateCompoundInterest, validateIsbn, calculateTipSplit, calculateSimpleInterest, calculateTimeValue, calculatePercentageChange, convertAprApy, calculateMarginMarkup, calculateDiscount, applySuccessiveDiscounts, calculateBreakEven, calculateVideoBitrate } from "@utilix-tech/sdk/units";
|
|
272
276
|
|
|
273
277
|
// File sizes
|
|
274
278
|
convertBytes(1073741824, "GB"); // 1
|
|
@@ -346,6 +350,14 @@ calculateDiscount({ originalPrice: 80, discountPercent: 25 });
|
|
|
346
350
|
// Stacked discounts: 20% then a further 10% is 28% off, not 30%
|
|
347
351
|
applySuccessiveDiscounts(100, [20, 10]);
|
|
348
352
|
// { finalPrice: 72, totalSaved: 28, effectiveDiscountPercent: 28, sumOfDiscountPercents: 30, ... }
|
|
353
|
+
|
|
354
|
+
// Break-even point: fixed costs, variable cost/unit, price/unit
|
|
355
|
+
calculateBreakEven({ fixedCosts: 10000, variableCostPerUnit: 20, pricePerUnit: 50 });
|
|
356
|
+
// { breakEvenUnitsRounded: 334, breakEvenRevenue: 16666.6667, contributionMarginPerUnit: 30, ... }
|
|
357
|
+
|
|
358
|
+
// Video file size from a bitrate + duration, or the bitrate to hit a target size
|
|
359
|
+
calculateVideoBitrate({ mode: "size-from-bitrate", durationSeconds: 600, videoBitrateKbps: 5000, audioBitrateKbps: 192 });
|
|
360
|
+
// { totalBitrateKbps: 5192, fileSizeBytes: 389400000, fileSizeMB: 389.4, fileSizeMiB: 371.36, ... }
|
|
349
361
|
```
|
|
350
362
|
|
|
351
363
|
---
|
|
@@ -397,7 +409,7 @@ buildCacheControl({ visibility: "public", maxAge: 3600, mustRevalidate: true });
|
|
|
397
409
|
### `/api`: cURL, JWT, CORS, HTTP
|
|
398
410
|
|
|
399
411
|
```ts
|
|
400
|
-
import { buildCurl, parseCurlCommand, decodeJwt, signJwt, parseJwks,
|
|
412
|
+
import { buildCurl, parseCurlCommand, decodeJwt, signJwt, parseJwks, computeJwkThumbprint,
|
|
401
413
|
generateCors, generateCspHeader } from "@utilix-tech/sdk/api";
|
|
402
414
|
|
|
403
415
|
buildCurl({
|
|
@@ -421,6 +433,10 @@ decodeJwt("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...");
|
|
|
421
433
|
parseJwks('{"keys":[{"kty":"RSA","use":"sig","kid":"1","n":"...","e":"AQAB"}]}');
|
|
422
434
|
// { ok: true, keys: [{ kty: "RSA", kid: "1", keySize: 2048, ... }], count: 1, duplicateKids: [] }
|
|
423
435
|
|
|
436
|
+
// JWK thumbprint (RFC 7638): canonical fingerprint of a single JWK
|
|
437
|
+
computeJwkThumbprint('{"kty":"oct","k":"c2VjcmV0"}');
|
|
438
|
+
// { ok: true, kty: "oct", hashAlg: "SHA-256", thumbprint: "DWBh0SEIAPYh1x5uvot4z3AhaikHkxNJa3Ada2fT-Cg", ... }
|
|
439
|
+
|
|
424
440
|
// Generate CORS headers
|
|
425
441
|
generateCors({ origins: ["https://myapp.com"], methods: ["GET", "POST"] });
|
|
426
442
|
|
|
@@ -595,11 +611,11 @@ readIcoInfo(new Uint8Array(icoBytes));
|
|
|
595
611
|
| `@utilix-tech/sdk/json` | Format, minify, diff, validate, JSONPath, CSV↔JSON, YAML↔JSON, TS types |
|
|
596
612
|
| `@utilix-tech/sdk/encoding` | Base64, URL, HTML entities, Base32/Base58/Base62 encode/decode |
|
|
597
613
|
| `@utilix-tech/sdk/hashing` | MD5, SHA-1/256/512, bcrypt, HMAC, .htpasswd |
|
|
598
|
-
| `@utilix-tech/sdk/text` | Case convert, slugify, word count, lorem ipsum, line ops, HTML→Markdown |
|
|
614
|
+
| `@utilix-tech/sdk/text` | Case convert, slugify, word count, lorem ipsum, line ops, HTML→Markdown, Levenshtein/Damerau string distance |
|
|
599
615
|
| `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert, SRT/WebVTT subtitles |
|
|
600
616
|
| `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, fake data |
|
|
601
617
|
| `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
|
|
602
|
-
| `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode/ISBN validation, loan calculator, compound/simple interest calculators, VAT/sales tax calculator, tip/bill split calculator |
|
|
618
|
+
| `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode/ISBN validation, loan calculator, compound/simple interest calculators, VAT/sales tax calculator, tip/bill split calculator, break-even point calculator |
|
|
603
619
|
| `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing, User-Agent parsing |
|
|
604
620
|
| `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header |
|
|
605
621
|
| `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format, MIME type lookup, GitHub URL parsing |
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* - curl-to-code : parseCurlCommand, convertToCode
|
|
6
6
|
* - jwt-decoder : decodeJwt, formatJwtJson
|
|
7
7
|
* - jwk-viewer : parseJwks
|
|
8
|
+
* - jwk-thumbprint : computeJwkThumbprint
|
|
8
9
|
* - jwt-signer : base64urlEncode, base64urlDecode, signJwt
|
|
9
10
|
* - cors-builder : validateCorsConfig, generateCors
|
|
10
11
|
* - csp-builder : generateCspHeader, generateFullHeader, parseCspHeader, validateCspConfig
|
|
@@ -106,6 +107,27 @@ type JwksParseResult = JwksResult | JwksError;
|
|
|
106
107
|
* use the keys cryptographically: this is inspection only.
|
|
107
108
|
*/
|
|
108
109
|
declare function parseJwks(input: string): JwksParseResult;
|
|
110
|
+
type JwkThumbprintHash = 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
111
|
+
interface JwkThumbprintResult {
|
|
112
|
+
ok: true;
|
|
113
|
+
kty: string;
|
|
114
|
+
hashAlg: JwkThumbprintHash;
|
|
115
|
+
members: string[];
|
|
116
|
+
canonicalJson: string;
|
|
117
|
+
thumbprint: string;
|
|
118
|
+
}
|
|
119
|
+
interface JwkThumbprintErrorResult {
|
|
120
|
+
ok: false;
|
|
121
|
+
error: string;
|
|
122
|
+
}
|
|
123
|
+
type JwkThumbprintOutcome = JwkThumbprintResult | JwkThumbprintErrorResult;
|
|
124
|
+
/**
|
|
125
|
+
* Compute the RFC 7638 thumbprint of a single JWK: build the canonical JSON
|
|
126
|
+
* of its required members (lexicographic key order, no whitespace) and hash
|
|
127
|
+
* it. This is a fingerprint for identifying/matching a key, not a signature
|
|
128
|
+
* or verification, and it only accepts a bare JWK, not a JWKS set.
|
|
129
|
+
*/
|
|
130
|
+
declare function computeJwkThumbprint(input: string, hashAlg?: JwkThumbprintHash): JwkThumbprintOutcome;
|
|
109
131
|
type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512';
|
|
110
132
|
interface JwtSignOptions {
|
|
111
133
|
algorithm?: JwtAlgorithm;
|
|
@@ -284,6 +306,10 @@ declare const api_HTTP_METHODS: typeof HTTP_METHODS;
|
|
|
284
306
|
type api_Header = Header;
|
|
285
307
|
type api_HttpMethod = HttpMethod;
|
|
286
308
|
type api_JwkSummary = JwkSummary;
|
|
309
|
+
type api_JwkThumbprintErrorResult = JwkThumbprintErrorResult;
|
|
310
|
+
type api_JwkThumbprintHash = JwkThumbprintHash;
|
|
311
|
+
type api_JwkThumbprintOutcome = JwkThumbprintOutcome;
|
|
312
|
+
type api_JwkThumbprintResult = JwkThumbprintResult;
|
|
287
313
|
type api_JwksError = JwksError;
|
|
288
314
|
type api_JwksParseResult = JwksParseResult;
|
|
289
315
|
type api_JwksResult = JwksResult;
|
|
@@ -307,6 +333,7 @@ declare const api_base64urlEncode: typeof base64urlEncode;
|
|
|
307
333
|
declare const api_buildCurl: typeof buildCurl;
|
|
308
334
|
declare const api_buildCurlMultiline: typeof buildCurlMultiline;
|
|
309
335
|
declare const api_buildUrl: typeof buildUrl;
|
|
336
|
+
declare const api_computeJwkThumbprint: typeof computeJwkThumbprint;
|
|
310
337
|
declare const api_convertToCode: typeof convertToCode;
|
|
311
338
|
declare const api_decodeJwt: typeof decodeJwt;
|
|
312
339
|
declare const api_decodeUrlComponent: typeof decodeUrlComponent;
|
|
@@ -335,7 +362,7 @@ declare const api_validateCorsConfig: typeof validateCorsConfig;
|
|
|
335
362
|
declare const api_validateCspConfig: typeof validateCspConfig;
|
|
336
363
|
declare const api_validateOgTags: typeof validateOgTags;
|
|
337
364
|
declare namespace api {
|
|
338
|
-
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwkSummary as JwkSummary, type api_JwksError as JwksError, type api_JwksParseResult as JwksParseResult, type api_JwksResult as JwksResult, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseJwks as parseJwks, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
365
|
+
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwkSummary as JwkSummary, type api_JwkThumbprintErrorResult as JwkThumbprintErrorResult, type api_JwkThumbprintHash as JwkThumbprintHash, type api_JwkThumbprintOutcome as JwkThumbprintOutcome, type api_JwkThumbprintResult as JwkThumbprintResult, type api_JwksError as JwksError, type api_JwksParseResult as JwksParseResult, type api_JwksResult as JwksResult, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_computeJwkThumbprint as computeJwkThumbprint, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseJwks as parseJwks, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
339
366
|
}
|
|
340
367
|
|
|
341
|
-
export {
|
|
368
|
+
export { formatJwtJson as $, type JwtResult as A, type JwtSignOptions as B, COMMON_HEADERS as C, DEFAULT_CORS_CONFIG as D, type TwitterTags as E, type FormatResult as F, addParam as G, HTTP_METHODS as H, base64urlDecode as I, type JwkSummary as J, base64urlEncode as K, buildCurl as L, type MetaTags as M, buildCurlMultiline as N, type OgTags as O, type ParsedUrl as P, buildUrl as Q, type ResponseFormat as R, SUPPORTED_LANGUAGES as S, type TargetLanguage as T, computeJwkThumbprint as U, convertToCode as V, decodeJwt as W, decodeUrlComponent as X, detectFormat as Y, encodeUrlComponent as Z, extractJsonPaths as _, api as a, formatResponse as a0, generateCors as a1, generateCspHeader as a2, generateFullHeader as a3, generateMetaHtml as a4, getParam as a5, getStats as a6, isValidUrl as a7, normalizeUrl as a8, parseCspHeader as a9, parseCurl as aa, parseCurlCommand as ab, parseJwks as ac, parseMetaTags as ad, parseUrl as ae, removeParam as af, signJwt as ag, validateCorsConfig as ah, validateCspConfig as ai, validateOgTags as aj, COMMON_PRESETS as b, CORS_COMMON_HEADERS as c, type CorsConfig as d, type CorsOutput as e, type CspConfig as f, type CspDirective as g, type CspSource as h, type CurlCommand as i, type CurlConfig as j, DIRECTIVE_DESCRIPTIONS as k, type DirectiveConfig as l, type Header as m, type HttpMethod as n, type JwkThumbprintErrorResult as o, type JwkThumbprintHash as p, type JwkThumbprintOutcome as q, type JwkThumbprintResult as r, type JwksError as s, type JwksParseResult as t, type JwksResult as u, type JwtAlgorithm as v, type JwtDecodeError as w, type JwtDecodeResult as x, type JwtExpiry as y, type JwtPart as z };
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* - curl-to-code : parseCurlCommand, convertToCode
|
|
6
6
|
* - jwt-decoder : decodeJwt, formatJwtJson
|
|
7
7
|
* - jwk-viewer : parseJwks
|
|
8
|
+
* - jwk-thumbprint : computeJwkThumbprint
|
|
8
9
|
* - jwt-signer : base64urlEncode, base64urlDecode, signJwt
|
|
9
10
|
* - cors-builder : validateCorsConfig, generateCors
|
|
10
11
|
* - csp-builder : generateCspHeader, generateFullHeader, parseCspHeader, validateCspConfig
|
|
@@ -106,6 +107,27 @@ type JwksParseResult = JwksResult | JwksError;
|
|
|
106
107
|
* use the keys cryptographically: this is inspection only.
|
|
107
108
|
*/
|
|
108
109
|
declare function parseJwks(input: string): JwksParseResult;
|
|
110
|
+
type JwkThumbprintHash = 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
111
|
+
interface JwkThumbprintResult {
|
|
112
|
+
ok: true;
|
|
113
|
+
kty: string;
|
|
114
|
+
hashAlg: JwkThumbprintHash;
|
|
115
|
+
members: string[];
|
|
116
|
+
canonicalJson: string;
|
|
117
|
+
thumbprint: string;
|
|
118
|
+
}
|
|
119
|
+
interface JwkThumbprintErrorResult {
|
|
120
|
+
ok: false;
|
|
121
|
+
error: string;
|
|
122
|
+
}
|
|
123
|
+
type JwkThumbprintOutcome = JwkThumbprintResult | JwkThumbprintErrorResult;
|
|
124
|
+
/**
|
|
125
|
+
* Compute the RFC 7638 thumbprint of a single JWK: build the canonical JSON
|
|
126
|
+
* of its required members (lexicographic key order, no whitespace) and hash
|
|
127
|
+
* it. This is a fingerprint for identifying/matching a key, not a signature
|
|
128
|
+
* or verification, and it only accepts a bare JWK, not a JWKS set.
|
|
129
|
+
*/
|
|
130
|
+
declare function computeJwkThumbprint(input: string, hashAlg?: JwkThumbprintHash): JwkThumbprintOutcome;
|
|
109
131
|
type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512';
|
|
110
132
|
interface JwtSignOptions {
|
|
111
133
|
algorithm?: JwtAlgorithm;
|
|
@@ -284,6 +306,10 @@ declare const api_HTTP_METHODS: typeof HTTP_METHODS;
|
|
|
284
306
|
type api_Header = Header;
|
|
285
307
|
type api_HttpMethod = HttpMethod;
|
|
286
308
|
type api_JwkSummary = JwkSummary;
|
|
309
|
+
type api_JwkThumbprintErrorResult = JwkThumbprintErrorResult;
|
|
310
|
+
type api_JwkThumbprintHash = JwkThumbprintHash;
|
|
311
|
+
type api_JwkThumbprintOutcome = JwkThumbprintOutcome;
|
|
312
|
+
type api_JwkThumbprintResult = JwkThumbprintResult;
|
|
287
313
|
type api_JwksError = JwksError;
|
|
288
314
|
type api_JwksParseResult = JwksParseResult;
|
|
289
315
|
type api_JwksResult = JwksResult;
|
|
@@ -307,6 +333,7 @@ declare const api_base64urlEncode: typeof base64urlEncode;
|
|
|
307
333
|
declare const api_buildCurl: typeof buildCurl;
|
|
308
334
|
declare const api_buildCurlMultiline: typeof buildCurlMultiline;
|
|
309
335
|
declare const api_buildUrl: typeof buildUrl;
|
|
336
|
+
declare const api_computeJwkThumbprint: typeof computeJwkThumbprint;
|
|
310
337
|
declare const api_convertToCode: typeof convertToCode;
|
|
311
338
|
declare const api_decodeJwt: typeof decodeJwt;
|
|
312
339
|
declare const api_decodeUrlComponent: typeof decodeUrlComponent;
|
|
@@ -335,7 +362,7 @@ declare const api_validateCorsConfig: typeof validateCorsConfig;
|
|
|
335
362
|
declare const api_validateCspConfig: typeof validateCspConfig;
|
|
336
363
|
declare const api_validateOgTags: typeof validateOgTags;
|
|
337
364
|
declare namespace api {
|
|
338
|
-
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwkSummary as JwkSummary, type api_JwksError as JwksError, type api_JwksParseResult as JwksParseResult, type api_JwksResult as JwksResult, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseJwks as parseJwks, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
365
|
+
export { api_COMMON_HEADERS as COMMON_HEADERS, api_COMMON_PRESETS as COMMON_PRESETS, api_CORS_COMMON_HEADERS as CORS_COMMON_HEADERS, type api_CorsConfig as CorsConfig, type api_CorsOutput as CorsOutput, type api_CspConfig as CspConfig, type api_CspDirective as CspDirective, type api_CspSource as CspSource, type api_CurlCommand as CurlCommand, type api_CurlConfig as CurlConfig, api_DEFAULT_CORS_CONFIG as DEFAULT_CORS_CONFIG, api_DIRECTIVE_DESCRIPTIONS as DIRECTIVE_DESCRIPTIONS, type api_DirectiveConfig as DirectiveConfig, type api_FormatResult as FormatResult, api_HTTP_METHODS as HTTP_METHODS, type api_Header as Header, type api_HttpMethod as HttpMethod, type api_JwkSummary as JwkSummary, type api_JwkThumbprintErrorResult as JwkThumbprintErrorResult, type api_JwkThumbprintHash as JwkThumbprintHash, type api_JwkThumbprintOutcome as JwkThumbprintOutcome, type api_JwkThumbprintResult as JwkThumbprintResult, type api_JwksError as JwksError, type api_JwksParseResult as JwksParseResult, type api_JwksResult as JwksResult, type api_JwtAlgorithm as JwtAlgorithm, type api_JwtDecodeError as JwtDecodeError, type api_JwtDecodeResult as JwtDecodeResult, type api_JwtExpiry as JwtExpiry, type api_JwtPart as JwtPart, type api_JwtResult as JwtResult, type api_JwtSignOptions as JwtSignOptions, type api_MetaTags as MetaTags, type api_OgTags as OgTags, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TwitterTags as TwitterTags, api_addParam as addParam, api_base64urlDecode as base64urlDecode, api_base64urlEncode as base64urlEncode, api_buildCurl as buildCurl, api_buildCurlMultiline as buildCurlMultiline, api_buildUrl as buildUrl, api_computeJwkThumbprint as computeJwkThumbprint, api_convertToCode as convertToCode, api_decodeJwt as decodeJwt, api_decodeUrlComponent as decodeUrlComponent, api_detectFormat as detectFormat, api_encodeUrlComponent as encodeUrlComponent, api_extractJsonPaths as extractJsonPaths, api_formatJwtJson as formatJwtJson, api_formatResponse as formatResponse, api_generateCors as generateCors, api_generateCspHeader as generateCspHeader, api_generateFullHeader as generateFullHeader, api_generateMetaHtml as generateMetaHtml, api_getParam as getParam, api_getStats as getStats, api_isValidUrl as isValidUrl, api_normalizeUrl as normalizeUrl, api_parseCspHeader as parseCspHeader, api_parseCurl as parseCurl, api_parseCurlCommand as parseCurlCommand, api_parseJwks as parseJwks, api_parseMetaTags as parseMetaTags, api_parseUrl as parseUrl, api_removeParam as removeParam, api_signJwt as signJwt, api_validateCorsConfig as validateCorsConfig, api_validateCspConfig as validateCspConfig, api_validateOgTags as validateOgTags };
|
|
339
366
|
}
|
|
340
367
|
|
|
341
|
-
export {
|
|
368
|
+
export { formatJwtJson as $, type JwtResult as A, type JwtSignOptions as B, COMMON_HEADERS as C, DEFAULT_CORS_CONFIG as D, type TwitterTags as E, type FormatResult as F, addParam as G, HTTP_METHODS as H, base64urlDecode as I, type JwkSummary as J, base64urlEncode as K, buildCurl as L, type MetaTags as M, buildCurlMultiline as N, type OgTags as O, type ParsedUrl as P, buildUrl as Q, type ResponseFormat as R, SUPPORTED_LANGUAGES as S, type TargetLanguage as T, computeJwkThumbprint as U, convertToCode as V, decodeJwt as W, decodeUrlComponent as X, detectFormat as Y, encodeUrlComponent as Z, extractJsonPaths as _, api as a, formatResponse as a0, generateCors as a1, generateCspHeader as a2, generateFullHeader as a3, generateMetaHtml as a4, getParam as a5, getStats as a6, isValidUrl as a7, normalizeUrl as a8, parseCspHeader as a9, parseCurl as aa, parseCurlCommand as ab, parseJwks as ac, parseMetaTags as ad, parseUrl as ae, removeParam as af, signJwt as ag, validateCorsConfig as ah, validateCspConfig as ai, validateOgTags as aj, COMMON_PRESETS as b, CORS_COMMON_HEADERS as c, type CorsConfig as d, type CorsOutput as e, type CspConfig as f, type CspDirective as g, type CspSource as h, type CurlCommand as i, type CurlConfig as j, DIRECTIVE_DESCRIPTIONS as k, type DirectiveConfig as l, type Header as m, type HttpMethod as n, type JwkThumbprintErrorResult as o, type JwkThumbprintHash as p, type JwkThumbprintOutcome as q, type JwkThumbprintResult as r, type JwksError as s, type JwksParseResult as t, type JwksResult as u, type JwtAlgorithm as v, type JwtDecodeError as w, type JwtDecodeResult as x, type JwtExpiry as y, type JwtPart as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { __export } from './chunk-MLKGABMK.js';
|
|
2
|
-
import { createHmac } from 'crypto';
|
|
2
|
+
import { createHash, createHmac } from 'crypto';
|
|
3
3
|
|
|
4
4
|
// src/tools/api.ts
|
|
5
5
|
var api_exports = {};
|
|
@@ -17,6 +17,7 @@ __export(api_exports, {
|
|
|
17
17
|
buildCurl: () => buildCurl,
|
|
18
18
|
buildCurlMultiline: () => buildCurlMultiline,
|
|
19
19
|
buildUrl: () => buildUrl,
|
|
20
|
+
computeJwkThumbprint: () => computeJwkThumbprint,
|
|
20
21
|
convertToCode: () => convertToCode,
|
|
21
22
|
decodeJwt: () => decodeJwt,
|
|
22
23
|
decodeUrlComponent: () => decodeUrlComponent,
|
|
@@ -535,6 +536,48 @@ function parseJwks(input) {
|
|
|
535
536
|
const duplicateKids = [...kidCounts.entries()].filter(([, c]) => c > 1).map(([kid]) => kid);
|
|
536
537
|
return { ok: true, keys, count: keys.length, duplicateKids };
|
|
537
538
|
}
|
|
539
|
+
var JWK_THUMBPRINT_MEMBERS = {
|
|
540
|
+
oct: ["k", "kty"],
|
|
541
|
+
RSA: ["e", "kty", "n"],
|
|
542
|
+
EC: ["crv", "kty", "x", "y"],
|
|
543
|
+
OKP: ["crv", "kty", "x"]
|
|
544
|
+
};
|
|
545
|
+
var JWK_THUMBPRINT_NODE_HASH = {
|
|
546
|
+
"SHA-256": "sha256",
|
|
547
|
+
"SHA-384": "sha384",
|
|
548
|
+
"SHA-512": "sha512"
|
|
549
|
+
};
|
|
550
|
+
function computeJwkThumbprint(input, hashAlg = "SHA-256") {
|
|
551
|
+
const trimmed = input.trim();
|
|
552
|
+
if (!trimmed) return { ok: false, error: "No input provided" };
|
|
553
|
+
const nodeHash = JWK_THUMBPRINT_NODE_HASH[hashAlg];
|
|
554
|
+
if (!nodeHash) return { ok: false, error: 'hashAlg must be one of "SHA-256", "SHA-384", "SHA-512"' };
|
|
555
|
+
let jwk;
|
|
556
|
+
try {
|
|
557
|
+
jwk = JSON.parse(trimmed);
|
|
558
|
+
} catch (e) {
|
|
559
|
+
return { ok: false, error: `Invalid JSON: ${e instanceof Error ? e.message : String(e)}` };
|
|
560
|
+
}
|
|
561
|
+
if (jwk === null || typeof jwk !== "object" || Array.isArray(jwk)) {
|
|
562
|
+
return { ok: false, error: "Input must be a single JWK object, not a JWKS set or array" };
|
|
563
|
+
}
|
|
564
|
+
const obj = jwk;
|
|
565
|
+
const kty = obj.kty;
|
|
566
|
+
if (typeof kty !== "string") return { ok: false, error: 'JWK must have a "kty" (key type) member' };
|
|
567
|
+
const members = JWK_THUMBPRINT_MEMBERS[kty];
|
|
568
|
+
if (!members) return { ok: false, error: `Unsupported key type "${kty}": supported types are RSA, EC, oct, OKP` };
|
|
569
|
+
const canonical = {};
|
|
570
|
+
for (const m of members) {
|
|
571
|
+
const v = obj[m];
|
|
572
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
573
|
+
return { ok: false, error: `JWK is missing required member "${m}" for key type "${kty}"` };
|
|
574
|
+
}
|
|
575
|
+
canonical[m] = v;
|
|
576
|
+
}
|
|
577
|
+
const canonicalJson = "{" + members.map((m) => `${JSON.stringify(m)}:${JSON.stringify(canonical[m])}`).join(",") + "}";
|
|
578
|
+
const thumbprint = createHash(nodeHash).update(canonicalJson, "utf8").digest("base64url");
|
|
579
|
+
return { ok: true, kty, hashAlg, members, canonicalJson, thumbprint };
|
|
580
|
+
}
|
|
538
581
|
var ALG_TO_NODE_HASH = {
|
|
539
582
|
HS256: "sha256",
|
|
540
583
|
HS384: "sha384",
|
|
@@ -1266,4 +1309,4 @@ function generateMetaHtml(tags) {
|
|
|
1266
1309
|
return lines.join("\n");
|
|
1267
1310
|
}
|
|
1268
1311
|
|
|
1269
|
-
export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, api_exports, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags };
|
|
1312
|
+
export { COMMON_HEADERS, COMMON_PRESETS, CORS_COMMON_HEADERS, DEFAULT_CORS_CONFIG, DIRECTIVE_DESCRIPTIONS, HTTP_METHODS, SUPPORTED_LANGUAGES, addParam, api_exports, base64urlDecode, base64urlEncode, buildCurl, buildCurlMultiline, buildUrl, computeJwkThumbprint, convertToCode, decodeJwt, decodeUrlComponent, detectFormat, encodeUrlComponent, extractJsonPaths, formatJwtJson, formatResponse, generateCors, generateCspHeader, generateFullHeader, generateMetaHtml, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags };
|
|
@@ -13,6 +13,7 @@ __export(text_exports, {
|
|
|
13
13
|
analyzeText: () => analyzeText,
|
|
14
14
|
applyOp: () => applyOp,
|
|
15
15
|
applyOps: () => applyOps,
|
|
16
|
+
calculateStringDistance: () => calculateStringDistance,
|
|
16
17
|
centerText: () => centerText,
|
|
17
18
|
convertAll: () => convertAll,
|
|
18
19
|
convertCase: () => convertCase,
|
|
@@ -2556,5 +2557,46 @@ function detectFillerWords(text) {
|
|
|
2556
2557
|
const density = totalWords > 0 ? Math.round(totalMatches / totalWords * 1e3) / 10 : 0;
|
|
2557
2558
|
return { totalWords, totalMatches, fillerCount, hedgeCount, clicheCount, density, matches };
|
|
2558
2559
|
}
|
|
2560
|
+
var MAX_STRING_DISTANCE_LENGTH = 5e3;
|
|
2561
|
+
function calculateStringDistance(a, b, options) {
|
|
2562
|
+
if (typeof a !== "string" || typeof b !== "string") {
|
|
2563
|
+
return { error: "Both a and b must be strings" };
|
|
2564
|
+
}
|
|
2565
|
+
if (a.length > MAX_STRING_DISTANCE_LENGTH || b.length > MAX_STRING_DISTANCE_LENGTH) {
|
|
2566
|
+
return { error: `Strings must be at most ${MAX_STRING_DISTANCE_LENGTH} characters` };
|
|
2567
|
+
}
|
|
2568
|
+
const mode = options?.mode ?? "levenshtein";
|
|
2569
|
+
const caseSensitive = options?.caseSensitive ?? true;
|
|
2570
|
+
const s1 = caseSensitive ? a : a.toLowerCase();
|
|
2571
|
+
const s2 = caseSensitive ? b : b.toLowerCase();
|
|
2572
|
+
const m = s1.length;
|
|
2573
|
+
const n = s2.length;
|
|
2574
|
+
const maxLength = Math.max(m, n);
|
|
2575
|
+
if (m === 0 || n === 0) {
|
|
2576
|
+
return { a, b, distance: maxLength, similarity: maxLength === 0 ? 1 : 0, maxLength, mode };
|
|
2577
|
+
}
|
|
2578
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
2579
|
+
for (let i = 0; i <= m; i++) dp[i][0] = i;
|
|
2580
|
+
for (let j = 0; j <= n; j++) dp[0][j] = j;
|
|
2581
|
+
for (let i = 1; i <= m; i++) {
|
|
2582
|
+
for (let j = 1; j <= n; j++) {
|
|
2583
|
+
const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
|
|
2584
|
+
dp[i][j] = Math.min(
|
|
2585
|
+
dp[i - 1][j] + 1,
|
|
2586
|
+
// deletion
|
|
2587
|
+
dp[i][j - 1] + 1,
|
|
2588
|
+
// insertion
|
|
2589
|
+
dp[i - 1][j - 1] + cost
|
|
2590
|
+
// substitution
|
|
2591
|
+
);
|
|
2592
|
+
if (mode === "damerau" && i > 1 && j > 1 && s1[i - 1] === s2[j - 2] && s1[i - 2] === s2[j - 1]) {
|
|
2593
|
+
dp[i][j] = Math.min(dp[i][j], dp[i - 2][j - 2] + 1);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
const distance = dp[m][n];
|
|
2598
|
+
const similarity = maxLength === 0 ? 1 : Math.round((1 - distance / maxLength) * 1e4) / 1e4;
|
|
2599
|
+
return { a, b, distance, similarity, maxLength, mode };
|
|
2600
|
+
}
|
|
2559
2601
|
|
|
2560
|
-
export { CASE_FORMATS, DEFAULT_CONVERT_OPTIONS, ESCAPE_MODES, LINE_OPS, MORSE_CODE, addBorder, analyzeText, applyOp, applyOps, centerText, convertAll, convertCase, countWords, csvToHtml, csvToMarkdown, detectDelimiter, detectFillerWords, detectPassiveVoice, diffLines, diffLinesSimple, diffStats, escapeAll, escapeString, extractHeadings, formatReadingTime, generate, generateDiff, generateHtmlTable, generateMarkdownTable, generateParagraphs, generateSentences, generateWords, getAvailableFonts, getMorseForChar, getMorseTiming, htmlToMarkdown, isValidMorse, markdownToHtml, morseToText, numberToOrdinal, numberToRoman, numberToWords, ordinalWords, parseDiff, parseTableData, readabilityScore, renderMarkdown, romanToNumber, scoreReadability, sentenceCount, slugify, slugifyAll, syllableCount, textToAscii, textToMorse, text_exports, unescapeString, wordFrequency };
|
|
2602
|
+
export { CASE_FORMATS, DEFAULT_CONVERT_OPTIONS, ESCAPE_MODES, LINE_OPS, MORSE_CODE, addBorder, analyzeText, applyOp, applyOps, calculateStringDistance, centerText, convertAll, convertCase, countWords, csvToHtml, csvToMarkdown, detectDelimiter, detectFillerWords, detectPassiveVoice, diffLines, diffLinesSimple, diffStats, escapeAll, escapeString, extractHeadings, formatReadingTime, generate, generateDiff, generateHtmlTable, generateMarkdownTable, generateParagraphs, generateSentences, generateWords, getAvailableFonts, getMorseForChar, getMorseTiming, htmlToMarkdown, isValidMorse, markdownToHtml, morseToText, numberToOrdinal, numberToRoman, numberToWords, ordinalWords, parseDiff, parseTableData, readabilityScore, renderMarkdown, romanToNumber, scoreReadability, sentenceCount, slugify, slugifyAll, syllableCount, textToAscii, textToMorse, text_exports, unescapeString, wordFrequency };
|
|
@@ -19,6 +19,7 @@ __export(units_exports, {
|
|
|
19
19
|
bumpVersion: () => bumpVersion,
|
|
20
20
|
calcAspectRatio: () => calcAspectRatio,
|
|
21
21
|
calcSubnet: () => calcSubnet,
|
|
22
|
+
calculateBreakEven: () => calculateBreakEven,
|
|
22
23
|
calculateCompoundInterest: () => calculateCompoundInterest,
|
|
23
24
|
calculateDiscount: () => calculateDiscount,
|
|
24
25
|
calculateLoan: () => calculateLoan,
|
|
@@ -28,6 +29,7 @@ __export(units_exports, {
|
|
|
28
29
|
calculateTax: () => calculateTax,
|
|
29
30
|
calculateTimeValue: () => calculateTimeValue,
|
|
30
31
|
calculateTipSplit: () => calculateTipSplit,
|
|
32
|
+
calculateVideoBitrate: () => calculateVideoBitrate,
|
|
31
33
|
compareSemver: () => compareSemver,
|
|
32
34
|
convert: () => convert,
|
|
33
35
|
convertAprApy: () => convertAprApy,
|
|
@@ -1548,5 +1550,97 @@ function applySuccessiveDiscounts(originalPrice, discountPercents) {
|
|
|
1548
1550
|
steps
|
|
1549
1551
|
};
|
|
1550
1552
|
}
|
|
1553
|
+
function calculateBreakEven(input) {
|
|
1554
|
+
const { fixedCosts, variableCostPerUnit, pricePerUnit, salesVolume } = input;
|
|
1555
|
+
if (!Number.isFinite(fixedCosts)) return { error: "fixedCosts must be a finite number" };
|
|
1556
|
+
if (!Number.isFinite(variableCostPerUnit)) return { error: "variableCostPerUnit must be a finite number" };
|
|
1557
|
+
if (!Number.isFinite(pricePerUnit)) return { error: "pricePerUnit must be a finite number" };
|
|
1558
|
+
if (fixedCosts < 0) return { error: "fixedCosts cannot be negative" };
|
|
1559
|
+
if (variableCostPerUnit < 0) return { error: "variableCostPerUnit cannot be negative" };
|
|
1560
|
+
if (pricePerUnit <= 0) return { error: "pricePerUnit must be greater than zero" };
|
|
1561
|
+
if (pricePerUnit <= variableCostPerUnit) {
|
|
1562
|
+
return { error: "pricePerUnit must be greater than variableCostPerUnit, otherwise every unit sold loses money and break-even is never reached" };
|
|
1563
|
+
}
|
|
1564
|
+
const round4 = (n) => Math.round(n * 1e4) / 1e4;
|
|
1565
|
+
const contributionMarginPerUnit = pricePerUnit - variableCostPerUnit;
|
|
1566
|
+
const contributionMarginRatio = contributionMarginPerUnit / pricePerUnit * 100;
|
|
1567
|
+
const breakEvenUnits = fixedCosts / contributionMarginPerUnit;
|
|
1568
|
+
const breakEvenUnitsRounded = Math.ceil(breakEvenUnits);
|
|
1569
|
+
const breakEvenRevenue = breakEvenUnits * pricePerUnit;
|
|
1570
|
+
const result = {
|
|
1571
|
+
fixedCosts: round4(fixedCosts),
|
|
1572
|
+
variableCostPerUnit: round4(variableCostPerUnit),
|
|
1573
|
+
pricePerUnit: round4(pricePerUnit),
|
|
1574
|
+
contributionMarginPerUnit: round4(contributionMarginPerUnit),
|
|
1575
|
+
contributionMarginRatio: round4(contributionMarginRatio),
|
|
1576
|
+
breakEvenUnits: round4(breakEvenUnits),
|
|
1577
|
+
breakEvenUnitsRounded,
|
|
1578
|
+
breakEvenRevenue: round4(breakEvenRevenue)
|
|
1579
|
+
};
|
|
1580
|
+
if (typeof salesVolume === "number" && Number.isFinite(salesVolume)) {
|
|
1581
|
+
if (salesVolume < 0) return { error: "salesVolume cannot be negative" };
|
|
1582
|
+
const revenueAtSalesVolume = salesVolume * pricePerUnit;
|
|
1583
|
+
const profitAtSalesVolume = salesVolume * contributionMarginPerUnit - fixedCosts;
|
|
1584
|
+
const marginOfSafetyUnits = salesVolume - breakEvenUnits;
|
|
1585
|
+
result.salesVolume = round4(salesVolume);
|
|
1586
|
+
result.revenueAtSalesVolume = round4(revenueAtSalesVolume);
|
|
1587
|
+
result.profitAtSalesVolume = round4(profitAtSalesVolume);
|
|
1588
|
+
result.marginOfSafetyUnits = round4(marginOfSafetyUnits);
|
|
1589
|
+
result.marginOfSafetyPercent = salesVolume > 0 ? round4(marginOfSafetyUnits / salesVolume * 100) : 0;
|
|
1590
|
+
}
|
|
1591
|
+
return result;
|
|
1592
|
+
}
|
|
1593
|
+
function calculateVideoBitrate(input) {
|
|
1594
|
+
const { mode, durationSeconds, videoBitrateKbps, targetSizeMB } = input;
|
|
1595
|
+
const audioBitrateKbps = input.audioBitrateKbps ?? 0;
|
|
1596
|
+
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) {
|
|
1597
|
+
return { error: "durationSeconds must be a positive number" };
|
|
1598
|
+
}
|
|
1599
|
+
if (!Number.isFinite(audioBitrateKbps) || audioBitrateKbps < 0) {
|
|
1600
|
+
return { error: "audioBitrateKbps must be zero or a positive number" };
|
|
1601
|
+
}
|
|
1602
|
+
const round22 = (n) => Math.round(n * 100) / 100;
|
|
1603
|
+
if (mode === "size-from-bitrate") {
|
|
1604
|
+
if (typeof videoBitrateKbps !== "number" || !Number.isFinite(videoBitrateKbps) || videoBitrateKbps <= 0) {
|
|
1605
|
+
return { error: 'videoBitrateKbps must be a positive number for mode "size-from-bitrate"' };
|
|
1606
|
+
}
|
|
1607
|
+
const totalBitrateKbps = videoBitrateKbps + audioBitrateKbps;
|
|
1608
|
+
const fileSizeBytes = totalBitrateKbps * 1e3 * durationSeconds / 8;
|
|
1609
|
+
return {
|
|
1610
|
+
mode,
|
|
1611
|
+
durationSeconds,
|
|
1612
|
+
videoBitrateKbps: round22(videoBitrateKbps),
|
|
1613
|
+
audioBitrateKbps: round22(audioBitrateKbps),
|
|
1614
|
+
totalBitrateKbps: round22(totalBitrateKbps),
|
|
1615
|
+
fileSizeBytes: Math.round(fileSizeBytes),
|
|
1616
|
+
fileSizeMB: round22(fileSizeBytes / 1e6),
|
|
1617
|
+
fileSizeMiB: round22(fileSizeBytes / 1048576)
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
if (mode === "bitrate-from-size") {
|
|
1621
|
+
if (typeof targetSizeMB !== "number" || !Number.isFinite(targetSizeMB) || targetSizeMB <= 0) {
|
|
1622
|
+
return { error: 'targetSizeMB must be a positive number for mode "bitrate-from-size"' };
|
|
1623
|
+
}
|
|
1624
|
+
const fileSizeBytes = targetSizeMB * 1e6;
|
|
1625
|
+
const totalBitrateKbps = fileSizeBytes * 8 / (1e3 * durationSeconds);
|
|
1626
|
+
const videoKbps = totalBitrateKbps - audioBitrateKbps;
|
|
1627
|
+
if (videoKbps <= 0) {
|
|
1628
|
+
return {
|
|
1629
|
+
error: "audioBitrateKbps exceeds the total bitrate available at this target size and duration; lower the audio bitrate or raise the target size"
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
return {
|
|
1633
|
+
mode,
|
|
1634
|
+
durationSeconds,
|
|
1635
|
+
videoBitrateKbps: round22(videoKbps),
|
|
1636
|
+
audioBitrateKbps: round22(audioBitrateKbps),
|
|
1637
|
+
totalBitrateKbps: round22(totalBitrateKbps),
|
|
1638
|
+
fileSizeBytes: Math.round(fileSizeBytes),
|
|
1639
|
+
fileSizeMB: round22(targetSizeMB),
|
|
1640
|
+
fileSizeMiB: round22(fileSizeBytes / 1048576)
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
return { error: 'mode must be "size-from-bitrate" or "bitrate-from-size"' };
|
|
1644
|
+
}
|
|
1551
1645
|
|
|
1552
|
-
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, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateCompoundInterest, calculateDiscount, calculateLoan, calculateMarginMarkup, calculatePercentageChange, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, compareSemver, 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 };
|
|
1646
|
+
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, applySuccessiveDiscounts, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateBreakEven, calculateCompoundInterest, calculateDiscount, calculateLoan, calculateMarginMarkup, calculatePercentageChange, calculateSimpleInterest, calculateTax, calculateTimeValue, calculateTipSplit, calculateVideoBitrate, compareSemver, 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 };
|