@utilix-tech/sdk 0.68.0 → 0.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -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.70.0
6
+ - Add `generateHotp`, `generateTotp` (totp-hotp-generator): generate an HOTP code (RFC 4226) for a counter value, or the current TOTP code (RFC 6238) plus seconds until rotation, from a base32-encoded shared secret, supporting SHA-1/SHA-256/SHA-512 and 6-8 digit codes.
7
+ - Add `calculateTaxEquivalentYield` (tax-equivalent-yield-calculator): convert between a tax-free municipal bond yield and its taxable equivalent given a marginal federal (plus optional state) tax rate, in both directions.
8
+
9
+ ## 0.69.0
10
+ - Add `parseCommitTrailers` (git-commit-trailer-parser): parse a commit message's trailer block (Co-authored-by, Signed-off-by, Fixes, Reviewed-by, etc.) per git's RFC 822-style trailer convention, returning each trailer's key and value plus the body with the trailer block removed.
11
+ - Add `extractMarkdownFootnotes` (markdown-footnote-extractor): extract every Markdown-Extra-style footnote reference and definition from a document, flagging references with no matching definition and definitions that are never referenced.
12
+
5
13
  ## 0.68.0
6
14
  - Add `buildRobotsMetaTag`, `parseRobotsMetaTag` (robots-meta-tag-builder): build a `<meta name="robots" content="...">` tag from the same directive vocabulary as X-Robots-Tag, optionally scoped to a crawler via the name attribute, or parse an existing tag into the same shape.
7
15
  - Add `extractSvgSpriteSymbols` (svg-sprite-symbol-extractor): parse an SVG sprite sheet's `<symbol>` definitions and list each one's id, viewBox, width, and height, alongside a ready-to-paste `<use href="#id"></use>` usage snippet.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/sdk
2
2
 
3
- **686 developer utility functions for Node.js: runs locally, no API key required.**
3
+ **691 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)
@@ -796,6 +796,16 @@ auditDependencyRanges(JSON.stringify({ dependencies: { lodash: "^4.17.21", "left
796
796
  import { extractSvgSpriteSymbols } from "@utilix-tech/sdk/code";
797
797
  extractSvgSpriteSymbols('<svg><symbol id="icon-home" viewBox="0 0 24 24"></symbol></svg>');
798
798
  // { symbolCount: 1, symbols: [{ id: "icon-home", viewBox: "0 0 24 24", width: null, height: null, usageSnippet: '<svg><use href="#icon-home"></use></svg>' }], skippedCount: 0 }
799
+
800
+ // Parse a commit message's trailer block (Co-authored-by, Signed-off-by, Fixes, etc.) into key/value pairs plus the remaining body
801
+ import { parseCommitTrailers } from "@utilix-tech/sdk/code";
802
+ parseCommitTrailers("Fix bug\n\nSigned-off-by: A <a@example.com>");
803
+ // { trailers: [{ key: "Signed-off-by", value: "A <a@example.com>" }], body: "Fix bug", hasTrailers: true }
804
+
805
+ // Extract Markdown footnote references and definitions, flagging unresolved references and unused definitions
806
+ import { extractMarkdownFootnotes } from "@utilix-tech/sdk/code";
807
+ extractMarkdownFootnotes("A claim[^1].\n\n[^1]: The source.");
808
+ // { definitionCount: 1, referenceCount: 1, definitions: [{ label: "1", text: "The source." }], unresolvedReferences: [], unusedDefinitions: [] }
799
809
  ```
800
810
 
801
811
  ---
@@ -952,9 +962,9 @@ inspectGifFrames(new Uint8Array(gifBytes));
952
962
  | `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert, NDJSON record deduplicator, SRT/WebVTT subtitles, Markdown front matter parser, YAML anchor/alias resolver, CSV column type inferencer, Markdown table column aligner |
953
963
  | `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, entropy estimator, fake data, CSP nonce generator |
954
964
  | `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
955
- | `@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, freelancer hourly rate calculator, debt snowball/avalanche payoff planner |
965
+ | `@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, freelancer hourly rate calculator, debt snowball/avalanche payoff planner, tax-equivalent yield calculator |
956
966
  | `@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, Prefer header builder/parser (RFC 7240), Retry-After header builder/parser (RFC 9110), Priority header builder/parser (RFC 9218), WebSocket close code reference/lookup, Strict-Transport-Security (HSTS) header builder/parser, X-Robots-Tag header builder/parser, WebSocket frame opcode reference/lookup, robots meta tag builder/parser |
957
- | `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header |
967
+ | `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header, TOTP/HOTP code generator |
958
968
  | `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format, MIME type lookup, GitHub URL parsing, regex ReDoS detector, Conventional Commits linter, package.json exports field validator, package.json dependency range auditor, regex capture group/backreference visualizer, SVG sprite symbol extractor |
959
969
  | `@utilix-tech/sdk/color` | Hex/RGB/HSL/HSV/CMYK convert, palette generation, contrast check |
960
970
  | `@utilix-tech/sdk/css` | CSS gradient, box-shadow, border-radius, keyframe animation generators |
@@ -13,6 +13,7 @@
13
13
  * - url-parser : parseUrl, buildUrl, addParam, removeParam, getParam,
14
14
  * encodeUrlComponent, decodeUrlComponent, isValidUrl, normalizeUrl
15
15
  * - og-meta : parseMetaTags, validateOgTags, generateMetaHtml
16
+ * - totp-hotp-generator : generateHotp, generateTotp
16
17
  *
17
18
  * Node 18+ only. All crypto uses node:crypto; no browser-only APIs.
18
19
  */
@@ -287,6 +288,51 @@ declare function validateOgTags(tags: OgTags): {
287
288
  missing: string[];
288
289
  };
289
290
  declare function generateMetaHtml(tags: Partial<OgTags & TwitterTags>): string;
291
+ type OtpAlgorithm = 'SHA1' | 'SHA256' | 'SHA512';
292
+ interface OtpOptions {
293
+ digits?: number;
294
+ algorithm?: OtpAlgorithm;
295
+ }
296
+ interface HotpResult {
297
+ code: string;
298
+ counter: number;
299
+ digits: number;
300
+ algorithm: OtpAlgorithm;
301
+ }
302
+ /**
303
+ * Generates an HOTP code (RFC 4226) for a given counter value from a
304
+ * base32-encoded shared secret. Supports 6-8 digit codes and
305
+ * SHA-1/SHA-256/SHA-512 (SHA-1 is the default per the RFC and what most
306
+ * authenticator apps expect). The secret is never stored, only used for
307
+ * this one HMAC computation.
308
+ */
309
+ declare function generateHotp(secret: string, counter: number, options?: OtpOptions): HotpResult | {
310
+ error: string;
311
+ };
312
+ interface TotpOptions extends OtpOptions {
313
+ periodSeconds?: number;
314
+ /** Unix timestamp in seconds. Defaults to the current time; pass an
315
+ * explicit value for deterministic/testable output. */
316
+ timestamp?: number;
317
+ }
318
+ interface TotpResult {
319
+ code: string;
320
+ counter: number;
321
+ digits: number;
322
+ algorithm: OtpAlgorithm;
323
+ periodSeconds: number;
324
+ secondsRemaining: number;
325
+ }
326
+ /**
327
+ * Generates the current TOTP code (RFC 6238) from a base32-encoded shared
328
+ * secret, plus how many seconds remain before it rotates. TOTP is HOTP
329
+ * where the counter is the number of `periodSeconds` windows elapsed since
330
+ * the Unix epoch. Defaults (30s period, 6 digits, SHA-1) match what
331
+ * Google Authenticator and most other authenticator apps use.
332
+ */
333
+ declare function generateTotp(secret: string, options?: TotpOptions): TotpResult | {
334
+ error: string;
335
+ };
290
336
 
291
337
  declare const api_COMMON_HEADERS: typeof COMMON_HEADERS;
292
338
  declare const api_COMMON_PRESETS: typeof COMMON_PRESETS;
@@ -304,6 +350,7 @@ type api_DirectiveConfig = DirectiveConfig;
304
350
  type api_FormatResult = FormatResult;
305
351
  declare const api_HTTP_METHODS: typeof HTTP_METHODS;
306
352
  type api_Header = Header;
353
+ type api_HotpResult = HotpResult;
307
354
  type api_HttpMethod = HttpMethod;
308
355
  type api_JwkSummary = JwkSummary;
309
356
  type api_JwkThumbprintErrorResult = JwkThumbprintErrorResult;
@@ -322,10 +369,14 @@ type api_JwtResult = JwtResult;
322
369
  type api_JwtSignOptions = JwtSignOptions;
323
370
  type api_MetaTags = MetaTags;
324
371
  type api_OgTags = OgTags;
372
+ type api_OtpAlgorithm = OtpAlgorithm;
373
+ type api_OtpOptions = OtpOptions;
325
374
  type api_ParsedUrl = ParsedUrl;
326
375
  type api_ResponseFormat = ResponseFormat;
327
376
  declare const api_SUPPORTED_LANGUAGES: typeof SUPPORTED_LANGUAGES;
328
377
  type api_TargetLanguage = TargetLanguage;
378
+ type api_TotpOptions = TotpOptions;
379
+ type api_TotpResult = TotpResult;
329
380
  type api_TwitterTags = TwitterTags;
330
381
  declare const api_addParam: typeof addParam;
331
382
  declare const api_base64urlDecode: typeof base64urlDecode;
@@ -345,7 +396,9 @@ declare const api_formatResponse: typeof formatResponse;
345
396
  declare const api_generateCors: typeof generateCors;
346
397
  declare const api_generateCspHeader: typeof generateCspHeader;
347
398
  declare const api_generateFullHeader: typeof generateFullHeader;
399
+ declare const api_generateHotp: typeof generateHotp;
348
400
  declare const api_generateMetaHtml: typeof generateMetaHtml;
401
+ declare const api_generateTotp: typeof generateTotp;
349
402
  declare const api_getParam: typeof getParam;
350
403
  declare const api_getStats: typeof getStats;
351
404
  declare const api_isValidUrl: typeof isValidUrl;
@@ -362,7 +415,7 @@ declare const api_validateCorsConfig: typeof validateCorsConfig;
362
415
  declare const api_validateCspConfig: typeof validateCspConfig;
363
416
  declare const api_validateOgTags: typeof validateOgTags;
364
417
  declare namespace api {
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 };
418
+ 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_HotpResult as HotpResult, 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_OtpAlgorithm as OtpAlgorithm, type api_OtpOptions as OtpOptions, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TotpOptions as TotpOptions, type api_TotpResult as TotpResult, 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_generateHotp as generateHotp, api_generateMetaHtml as generateMetaHtml, api_generateTotp as generateTotp, 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 };
366
419
  }
367
420
 
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 };
421
+ export { decodeJwt as $, type JwtPart as A, type JwtResult as B, COMMON_HEADERS as C, DEFAULT_CORS_CONFIG as D, type JwtSignOptions as E, type FormatResult as F, type OtpAlgorithm as G, HTTP_METHODS as H, type OtpOptions as I, type JwkSummary as J, type TotpOptions as K, type TotpResult as L, type MetaTags as M, type TwitterTags as N, type OgTags as O, type ParsedUrl as P, addParam as Q, type ResponseFormat as R, SUPPORTED_LANGUAGES as S, type TargetLanguage as T, base64urlDecode as U, base64urlEncode as V, buildCurl as W, buildCurlMultiline as X, buildUrl as Y, computeJwkThumbprint as Z, convertToCode as _, api as a, decodeUrlComponent as a0, detectFormat as a1, encodeUrlComponent as a2, extractJsonPaths as a3, formatJwtJson as a4, formatResponse as a5, generateCors as a6, generateCspHeader as a7, generateFullHeader as a8, generateHotp as a9, generateMetaHtml as aa, generateTotp as ab, getParam as ac, getStats as ad, isValidUrl as ae, normalizeUrl as af, parseCspHeader as ag, parseCurl as ah, parseCurlCommand as ai, parseJwks as aj, parseMetaTags as ak, parseUrl as al, removeParam as am, signJwt as an, validateCorsConfig as ao, validateCspConfig as ap, validateOgTags as aq, 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 HotpResult as n, type HttpMethod as o, type JwkThumbprintErrorResult as p, type JwkThumbprintHash as q, type JwkThumbprintOutcome as r, type JwkThumbprintResult as s, type JwksError as t, type JwksParseResult as u, type JwksResult as v, type JwtAlgorithm as w, type JwtDecodeError as x, type JwtDecodeResult as y, type JwtExpiry as z };
@@ -13,6 +13,7 @@
13
13
  * - url-parser : parseUrl, buildUrl, addParam, removeParam, getParam,
14
14
  * encodeUrlComponent, decodeUrlComponent, isValidUrl, normalizeUrl
15
15
  * - og-meta : parseMetaTags, validateOgTags, generateMetaHtml
16
+ * - totp-hotp-generator : generateHotp, generateTotp
16
17
  *
17
18
  * Node 18+ only. All crypto uses node:crypto; no browser-only APIs.
18
19
  */
@@ -287,6 +288,51 @@ declare function validateOgTags(tags: OgTags): {
287
288
  missing: string[];
288
289
  };
289
290
  declare function generateMetaHtml(tags: Partial<OgTags & TwitterTags>): string;
291
+ type OtpAlgorithm = 'SHA1' | 'SHA256' | 'SHA512';
292
+ interface OtpOptions {
293
+ digits?: number;
294
+ algorithm?: OtpAlgorithm;
295
+ }
296
+ interface HotpResult {
297
+ code: string;
298
+ counter: number;
299
+ digits: number;
300
+ algorithm: OtpAlgorithm;
301
+ }
302
+ /**
303
+ * Generates an HOTP code (RFC 4226) for a given counter value from a
304
+ * base32-encoded shared secret. Supports 6-8 digit codes and
305
+ * SHA-1/SHA-256/SHA-512 (SHA-1 is the default per the RFC and what most
306
+ * authenticator apps expect). The secret is never stored, only used for
307
+ * this one HMAC computation.
308
+ */
309
+ declare function generateHotp(secret: string, counter: number, options?: OtpOptions): HotpResult | {
310
+ error: string;
311
+ };
312
+ interface TotpOptions extends OtpOptions {
313
+ periodSeconds?: number;
314
+ /** Unix timestamp in seconds. Defaults to the current time; pass an
315
+ * explicit value for deterministic/testable output. */
316
+ timestamp?: number;
317
+ }
318
+ interface TotpResult {
319
+ code: string;
320
+ counter: number;
321
+ digits: number;
322
+ algorithm: OtpAlgorithm;
323
+ periodSeconds: number;
324
+ secondsRemaining: number;
325
+ }
326
+ /**
327
+ * Generates the current TOTP code (RFC 6238) from a base32-encoded shared
328
+ * secret, plus how many seconds remain before it rotates. TOTP is HOTP
329
+ * where the counter is the number of `periodSeconds` windows elapsed since
330
+ * the Unix epoch. Defaults (30s period, 6 digits, SHA-1) match what
331
+ * Google Authenticator and most other authenticator apps use.
332
+ */
333
+ declare function generateTotp(secret: string, options?: TotpOptions): TotpResult | {
334
+ error: string;
335
+ };
290
336
 
291
337
  declare const api_COMMON_HEADERS: typeof COMMON_HEADERS;
292
338
  declare const api_COMMON_PRESETS: typeof COMMON_PRESETS;
@@ -304,6 +350,7 @@ type api_DirectiveConfig = DirectiveConfig;
304
350
  type api_FormatResult = FormatResult;
305
351
  declare const api_HTTP_METHODS: typeof HTTP_METHODS;
306
352
  type api_Header = Header;
353
+ type api_HotpResult = HotpResult;
307
354
  type api_HttpMethod = HttpMethod;
308
355
  type api_JwkSummary = JwkSummary;
309
356
  type api_JwkThumbprintErrorResult = JwkThumbprintErrorResult;
@@ -322,10 +369,14 @@ type api_JwtResult = JwtResult;
322
369
  type api_JwtSignOptions = JwtSignOptions;
323
370
  type api_MetaTags = MetaTags;
324
371
  type api_OgTags = OgTags;
372
+ type api_OtpAlgorithm = OtpAlgorithm;
373
+ type api_OtpOptions = OtpOptions;
325
374
  type api_ParsedUrl = ParsedUrl;
326
375
  type api_ResponseFormat = ResponseFormat;
327
376
  declare const api_SUPPORTED_LANGUAGES: typeof SUPPORTED_LANGUAGES;
328
377
  type api_TargetLanguage = TargetLanguage;
378
+ type api_TotpOptions = TotpOptions;
379
+ type api_TotpResult = TotpResult;
329
380
  type api_TwitterTags = TwitterTags;
330
381
  declare const api_addParam: typeof addParam;
331
382
  declare const api_base64urlDecode: typeof base64urlDecode;
@@ -345,7 +396,9 @@ declare const api_formatResponse: typeof formatResponse;
345
396
  declare const api_generateCors: typeof generateCors;
346
397
  declare const api_generateCspHeader: typeof generateCspHeader;
347
398
  declare const api_generateFullHeader: typeof generateFullHeader;
399
+ declare const api_generateHotp: typeof generateHotp;
348
400
  declare const api_generateMetaHtml: typeof generateMetaHtml;
401
+ declare const api_generateTotp: typeof generateTotp;
349
402
  declare const api_getParam: typeof getParam;
350
403
  declare const api_getStats: typeof getStats;
351
404
  declare const api_isValidUrl: typeof isValidUrl;
@@ -362,7 +415,7 @@ declare const api_validateCorsConfig: typeof validateCorsConfig;
362
415
  declare const api_validateCspConfig: typeof validateCspConfig;
363
416
  declare const api_validateOgTags: typeof validateOgTags;
364
417
  declare namespace api {
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 };
418
+ 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_HotpResult as HotpResult, 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_OtpAlgorithm as OtpAlgorithm, type api_OtpOptions as OtpOptions, type api_ParsedUrl as ParsedUrl, type api_ResponseFormat as ResponseFormat, api_SUPPORTED_LANGUAGES as SUPPORTED_LANGUAGES, type api_TargetLanguage as TargetLanguage, type api_TotpOptions as TotpOptions, type api_TotpResult as TotpResult, 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_generateHotp as generateHotp, api_generateMetaHtml as generateMetaHtml, api_generateTotp as generateTotp, 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 };
366
419
  }
367
420
 
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 };
421
+ export { decodeJwt as $, type JwtPart as A, type JwtResult as B, COMMON_HEADERS as C, DEFAULT_CORS_CONFIG as D, type JwtSignOptions as E, type FormatResult as F, type OtpAlgorithm as G, HTTP_METHODS as H, type OtpOptions as I, type JwkSummary as J, type TotpOptions as K, type TotpResult as L, type MetaTags as M, type TwitterTags as N, type OgTags as O, type ParsedUrl as P, addParam as Q, type ResponseFormat as R, SUPPORTED_LANGUAGES as S, type TargetLanguage as T, base64urlDecode as U, base64urlEncode as V, buildCurl as W, buildCurlMultiline as X, buildUrl as Y, computeJwkThumbprint as Z, convertToCode as _, api as a, decodeUrlComponent as a0, detectFormat as a1, encodeUrlComponent as a2, extractJsonPaths as a3, formatJwtJson as a4, formatResponse as a5, generateCors as a6, generateCspHeader as a7, generateFullHeader as a8, generateHotp as a9, generateMetaHtml as aa, generateTotp as ab, getParam as ac, getStats as ad, isValidUrl as ae, normalizeUrl as af, parseCspHeader as ag, parseCurl as ah, parseCurlCommand as ai, parseJwks as aj, parseMetaTags as ak, parseUrl as al, removeParam as am, signJwt as an, validateCorsConfig as ao, validateCspConfig as ap, validateOgTags as aq, 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 HotpResult as n, type HttpMethod as o, type JwkThumbprintErrorResult as p, type JwkThumbprintHash as q, type JwkThumbprintOutcome as r, type JwkThumbprintResult as s, type JwksError as t, type JwksParseResult as u, type JwksResult as v, type JwtAlgorithm as w, type JwtDecodeError as x, type JwtDecodeResult as y, type JwtExpiry as z };
@@ -29,7 +29,9 @@ __export(api_exports, {
29
29
  generateCors: () => generateCors,
30
30
  generateCspHeader: () => generateCspHeader,
31
31
  generateFullHeader: () => generateFullHeader,
32
+ generateHotp: () => generateHotp,
32
33
  generateMetaHtml: () => generateMetaHtml,
34
+ generateTotp: () => generateTotp,
33
35
  getParam: () => getParam,
34
36
  getStats: () => getStats,
35
37
  isValidUrl: () => isValidUrl,
@@ -1308,5 +1310,74 @@ function generateMetaHtml(tags) {
1308
1310
  }
1309
1311
  return lines.join("\n");
1310
1312
  }
1313
+ var OTP_ALG_TO_NODE_HASH = {
1314
+ SHA1: "sha1",
1315
+ SHA256: "sha256",
1316
+ SHA512: "sha512"
1317
+ };
1318
+ function decodeBase32Secret(secret) {
1319
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
1320
+ const cleaned = secret.toUpperCase().replace(/[\s=]/g, "");
1321
+ if (!cleaned) {
1322
+ return { error: "Secret must not be empty" };
1323
+ }
1324
+ const bytes = [];
1325
+ let buffer = 0;
1326
+ let bitsLeft = 0;
1327
+ for (const char of cleaned) {
1328
+ const val = alphabet.indexOf(char);
1329
+ if (val === -1) {
1330
+ return { error: `Invalid base32 character '${char}' in secret` };
1331
+ }
1332
+ buffer = buffer << 5 | val;
1333
+ bitsLeft += 5;
1334
+ if (bitsLeft >= 8) {
1335
+ bitsLeft -= 8;
1336
+ bytes.push(buffer >> bitsLeft & 255);
1337
+ }
1338
+ }
1339
+ return Buffer.from(bytes);
1340
+ }
1341
+ function hotpFromCounter(keyBytes, counter, digits, algorithm) {
1342
+ const counterBuffer = Buffer.alloc(8);
1343
+ counterBuffer.writeUInt32BE(Math.floor(counter / 4294967296), 0);
1344
+ counterBuffer.writeUInt32BE(counter % 4294967296, 4);
1345
+ const hmac = createHmac(OTP_ALG_TO_NODE_HASH[algorithm], keyBytes).update(counterBuffer).digest();
1346
+ const offset = hmac[hmac.length - 1] & 15;
1347
+ const binCode = (hmac[offset] & 127) << 24 | (hmac[offset + 1] & 255) << 16 | (hmac[offset + 2] & 255) << 8 | hmac[offset + 3] & 255;
1348
+ const code = (binCode % 10 ** digits).toString().padStart(digits, "0");
1349
+ return code;
1350
+ }
1351
+ function generateHotp(secret, counter, options = {}) {
1352
+ const digits = options.digits ?? 6;
1353
+ const algorithm = options.algorithm ?? "SHA1";
1354
+ if (!Number.isInteger(counter) || counter < 0) {
1355
+ return { error: "Counter must be a non-negative whole number" };
1356
+ }
1357
+ if (!Number.isInteger(digits) || digits < 6 || digits > 8) {
1358
+ return { error: "Digits must be an integer between 6 and 8" };
1359
+ }
1360
+ if (!(algorithm in OTP_ALG_TO_NODE_HASH)) {
1361
+ return { error: "Algorithm must be one of SHA1, SHA256, SHA512" };
1362
+ }
1363
+ const keyBytes = decodeBase32Secret(secret);
1364
+ if ("error" in keyBytes) return keyBytes;
1365
+ return { code: hotpFromCounter(keyBytes, counter, digits, algorithm), counter, digits, algorithm };
1366
+ }
1367
+ function generateTotp(secret, options = {}) {
1368
+ const periodSeconds = options.periodSeconds ?? 30;
1369
+ const timestamp = options.timestamp ?? Math.floor(Date.now() / 1e3);
1370
+ if (!Number.isFinite(periodSeconds) || periodSeconds <= 0) {
1371
+ return { error: "Period must be a positive number of seconds" };
1372
+ }
1373
+ if (!Number.isFinite(timestamp) || timestamp < 0) {
1374
+ return { error: "Timestamp must be a non-negative number of seconds" };
1375
+ }
1376
+ const counter = Math.floor(timestamp / periodSeconds);
1377
+ const hotp = generateHotp(secret, counter, options);
1378
+ if ("error" in hotp) return hotp;
1379
+ const secondsRemaining = periodSeconds - timestamp % periodSeconds;
1380
+ return { ...hotp, periodSeconds, secondsRemaining };
1381
+ }
1311
1382
 
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 };
1383
+ 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, generateHotp, generateMetaHtml, generateTotp, getParam, getStats, isValidUrl, normalizeUrl, parseCspHeader, parseCurl, parseCurlCommand, parseJwks, parseMetaTags, parseUrl, removeParam, signJwt, validateCorsConfig, validateCspConfig, validateOgTags };
@@ -47,6 +47,7 @@ __export(units_exports, {
47
47
  calculateSavingsGoal: () => calculateSavingsGoal,
48
48
  calculateSimpleInterest: () => calculateSimpleInterest,
49
49
  calculateTax: () => calculateTax,
50
+ calculateTaxEquivalentYield: () => calculateTaxEquivalentYield,
50
51
  calculateTimeValue: () => calculateTimeValue,
51
52
  calculateTipSplit: () => calculateTipSplit,
52
53
  calculateVideoBitrate: () => calculateVideoBitrate,
@@ -2503,5 +2504,44 @@ function calculateLoanRefinance(currentBalance, currentRatePercent, currentRemai
2503
2504
  totalInterestSavings: round2(current.totalInterest - refinanced.totalInterest)
2504
2505
  };
2505
2506
  }
2507
+ function calculateTaxEquivalentYield(inputYieldPercent, federalTaxRatePercent, stateTaxRatePercent = 0, direction) {
2508
+ if (!Number.isFinite(inputYieldPercent) || inputYieldPercent < 0) {
2509
+ return { error: "Yield must be zero or a positive number" };
2510
+ }
2511
+ if (!Number.isFinite(federalTaxRatePercent) || federalTaxRatePercent < 0 || federalTaxRatePercent >= 100) {
2512
+ return { error: "Federal tax rate must be a percentage between 0 and 100 (exclusive of 100)" };
2513
+ }
2514
+ if (!Number.isFinite(stateTaxRatePercent) || stateTaxRatePercent < 0 || stateTaxRatePercent >= 100) {
2515
+ return { error: "State tax rate must be a percentage between 0 and 100 (exclusive of 100)" };
2516
+ }
2517
+ if (direction !== "tax-free-to-taxable" && direction !== "taxable-to-tax-free") {
2518
+ return { error: 'Direction must be "tax-free-to-taxable" or "taxable-to-tax-free"' };
2519
+ }
2520
+ const combinedTaxRatePercent = federalTaxRatePercent + stateTaxRatePercent;
2521
+ if (combinedTaxRatePercent >= 100) {
2522
+ return { error: "Combined federal and state tax rate must be less than 100%" };
2523
+ }
2524
+ const round6 = (n) => Math.round(n * 1e6) / 1e6;
2525
+ const combinedRateDecimal = combinedTaxRatePercent / 100;
2526
+ let taxFreeYield;
2527
+ let taxableYield;
2528
+ if (direction === "tax-free-to-taxable") {
2529
+ taxFreeYield = inputYieldPercent;
2530
+ taxableYield = taxFreeYield / (1 - combinedRateDecimal);
2531
+ } else {
2532
+ taxableYield = inputYieldPercent;
2533
+ taxFreeYield = taxableYield * (1 - combinedRateDecimal);
2534
+ }
2535
+ return {
2536
+ direction,
2537
+ inputYield: round6(inputYieldPercent),
2538
+ federalTaxRatePercent: round6(federalTaxRatePercent),
2539
+ stateTaxRatePercent: round6(stateTaxRatePercent),
2540
+ combinedTaxRatePercent: round6(combinedTaxRatePercent),
2541
+ taxFreeYield: round6(taxFreeYield),
2542
+ taxableYield: round6(taxableYield),
2543
+ yieldDifference: round6(taxableYield - taxFreeYield)
2544
+ };
2545
+ }
2506
2546
 
2507
- 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, calculateExtraPaymentPayoff, calculateFreelancerRate, calculateGpa, calculateLoan, calculateLoanRefinance, 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, planDebtPayoff, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx };
2547
+ 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, calculateExtraPaymentPayoff, calculateFreelancerRate, calculateGpa, calculateLoan, calculateLoanRefinance, calculateMarginMarkup, calculateMovingAverages, calculatePaybackPeriod, calculatePercentageChange, calculateRoi, calculateRuleOf72, calculateSavingsGoal, calculateSimpleInterest, calculateTax, calculateTaxEquivalentYield, 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, planDebtPayoff, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, validateIsbn, viewportToPx };
@@ -24,6 +24,7 @@ __export(code_exports, {
24
24
  detectRedos: () => detectRedos,
25
25
  envToExport: () => envToExport,
26
26
  envToJson: () => envToJson,
27
+ extractMarkdownFootnotes: () => extractMarkdownFootnotes,
27
28
  extractSvgSpriteSymbols: () => extractSvgSpriteSymbols,
28
29
  formatCss: () => formatCss,
29
30
  formatGql: () => formatGql,
@@ -42,6 +43,7 @@ __export(code_exports, {
42
43
  minifyJs: () => minifyJs,
43
44
  minifySql: () => minifySql,
44
45
  normalizeRef: () => normalizeRef,
46
+ parseCommitTrailers: () => parseCommitTrailers,
45
47
  parseDockerImage: () => parseDockerImage,
46
48
  parseEnv: () => parseEnv,
47
49
  parseGitCommand: () => parseGitCommand,
@@ -3625,5 +3627,92 @@ function extractSvgSpriteSymbols(svg) {
3625
3627
  }
3626
3628
  return { symbolCount: symbols.length, symbols, skippedCount };
3627
3629
  }
3630
+ var TRAILER_LINE_REGEX = /^([A-Za-z][A-Za-z0-9-]*): (.+)$/;
3631
+ var TRAILER_CONTINUATION_REGEX = /^[ \t]+\S/;
3632
+ function parseCommitTrailers(message) {
3633
+ const lines = message.replace(/\r\n/g, "\n").split("\n");
3634
+ while (lines.length > 0 && lines[lines.length - 1].trim() === "") lines.pop();
3635
+ if (lines.length === 0) return { error: "Empty input" };
3636
+ let start = 0;
3637
+ for (let i = lines.length - 1; i >= 0; i--) {
3638
+ if (lines[i].trim() === "") {
3639
+ start = i + 1;
3640
+ break;
3641
+ }
3642
+ }
3643
+ const paragraph = lines.slice(start);
3644
+ const trailers = [];
3645
+ let valid = true;
3646
+ for (const line of paragraph) {
3647
+ const m = line.match(TRAILER_LINE_REGEX);
3648
+ if (m) {
3649
+ trailers.push({ key: m[1], value: m[2].trim() });
3650
+ } else if (TRAILER_CONTINUATION_REGEX.test(line) && trailers.length > 0) {
3651
+ trailers[trailers.length - 1].value += " " + line.trim();
3652
+ } else {
3653
+ valid = false;
3654
+ break;
3655
+ }
3656
+ }
3657
+ if (!valid || trailers.length === 0) {
3658
+ return { trailers: [], body: lines.join("\n").trim(), hasTrailers: false };
3659
+ }
3660
+ const body = lines.slice(0, start).join("\n").trim();
3661
+ return { trailers, body, hasTrailers: true };
3662
+ }
3663
+ var FOOTNOTE_DEFINITION_LINE_REGEX = /^\[\^([^\]]+)\]:\s?(.*)$/;
3664
+ var FOOTNOTE_CONTINUATION_REGEX = /^(?: {4}|\t)/;
3665
+ var FOOTNOTE_REFERENCE_REGEX = /\[\^([^\]]+)\]/g;
3666
+ function extractMarkdownFootnotes(markdown) {
3667
+ const trimmed = markdown.trim();
3668
+ if (!trimmed) return { error: "Empty input" };
3669
+ if (!trimmed.includes("[^")) return { error: "No footnote references or definitions found" };
3670
+ const lines = markdown.replace(/\r\n/g, "\n").split("\n");
3671
+ const definitions = [];
3672
+ const definedLabels = /* @__PURE__ */ new Set();
3673
+ const consumed = new Array(lines.length).fill(false);
3674
+ let i = 0;
3675
+ while (i < lines.length) {
3676
+ const match = lines[i].match(FOOTNOTE_DEFINITION_LINE_REGEX);
3677
+ if (!match) {
3678
+ i++;
3679
+ continue;
3680
+ }
3681
+ const label = match[1];
3682
+ const textLines = [match[2]];
3683
+ consumed[i] = true;
3684
+ let j = i + 1;
3685
+ while (j < lines.length && (FOOTNOTE_CONTINUATION_REGEX.test(lines[j]) || lines[j].trim() === "" && j + 1 < lines.length && FOOTNOTE_CONTINUATION_REGEX.test(lines[j + 1]))) {
3686
+ textLines.push(lines[j].trim() === "" ? "" : lines[j].replace(FOOTNOTE_CONTINUATION_REGEX, ""));
3687
+ consumed[j] = true;
3688
+ j++;
3689
+ }
3690
+ if (!definedLabels.has(label)) {
3691
+ definedLabels.add(label);
3692
+ definitions.push({ label, text: textLines.join("\n").trim() });
3693
+ }
3694
+ i = j;
3695
+ }
3696
+ const referenceScanText = lines.filter((_, idx) => !consumed[idx]).join("\n");
3697
+ const refOrder = [];
3698
+ const refCounts = /* @__PURE__ */ new Map();
3699
+ for (const m of referenceScanText.matchAll(FOOTNOTE_REFERENCE_REGEX)) {
3700
+ const label = m[1];
3701
+ if (!refCounts.has(label)) {
3702
+ refCounts.set(label, 0);
3703
+ refOrder.push(label);
3704
+ }
3705
+ refCounts.set(label, (refCounts.get(label) ?? 0) + 1);
3706
+ }
3707
+ const references = refOrder.map((label) => ({ label, count: refCounts.get(label) ?? 0 }));
3708
+ const referencedSet = new Set(refOrder);
3709
+ const unresolvedReferences = refOrder.filter((label) => !definedLabels.has(label));
3710
+ const unusedDefinitions = definitions.filter((d) => !referencedSet.has(d.label)).map((d) => d.label);
3711
+ const referenceCount = refOrder.reduce((sum, label) => sum + (refCounts.get(label) ?? 0), 0);
3712
+ if (definitions.length === 0 && references.length === 0) {
3713
+ return { error: "No footnote references or definitions found" };
3714
+ }
3715
+ return { definitionCount: definitions.length, referenceCount, definitions, references, unresolvedReferences, unusedDefinitions };
3716
+ }
3628
3717
 
3629
- export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, analyzeRegexGroups, auditDependencyRanges, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, detectDialect, detectOperationType, detectRedos, envToExport, envToJson, extractSvgSpriteSymbols, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, lintConventionalCommit, lookupMime, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseDockerImage, parseEnv, parseGitCommand, parseGithubUrl, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testGitignorePatterns, testPattern, testRegex, validateEditorConfig, validateEnvKey, validatePackageExports, validateTsconfig };
3718
+ export { ALL_FLAGS, CHEATSHEET, DEFAULT_COMMIT_TYPES, MIME_TABLE, OPERATIONS, SQL_DEFAULT_OPTIONS, analyzeRegexGroups, auditDependencyRanges, buildDockerPull, buildDockerRun, buildGitCommand, code_exports, collapseHtmlWhitespace, collapseJsWhitespace, countProperties, countRules, detectDialect, detectOperationType, detectRedos, envToExport, envToJson, extractMarkdownFootnotes, extractSvgSpriteSymbols, formatCss, formatGql, formatHtml, formatSql, getEndpointsByTag, getHtmlStats, getJsStats, getMethodColor, isValidTag, lintConventionalCommit, lookupMime, minifyCss, minifyGql, minifyHtml, minifyJs, minifySql, normalizeRef, parseCommitTrailers, parseDockerImage, parseEnv, parseGitCommand, parseGithubUrl, parseSpec, removeConsoleCalls, removeEmptyAttributes, removeHtmlComments, removeJsComments, removeRedundantAttributes, searchCheatsheet, searchEndpoints, splitStatements, testGitignorePatterns, testPattern, testRegex, validateEditorConfig, validateEnvKey, validatePackageExports, validateTsconfig };