@utilix-tech/sdk 0.97.0 → 0.99.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.
@@ -9,6 +9,7 @@
9
9
  * generateHtpasswdFile, validateUsername
10
10
  * - sri-hash-generator: generateSri, generateSriAll (SHA-256/384/512 Subresource Integrity hashes)
11
11
  * - etag-generator : generateEtag (MD5/SHA-1/SHA-256 content-hash ETag header values)
12
+ * - ssh-known-hosts-fingerprint-checker: checkKnownHostsFingerprints
12
13
  */
13
14
  type HashAlgorithm = 'MD5' | 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
14
15
  declare const HASH_ALGORITHMS: HashAlgorithm[];
@@ -88,6 +89,32 @@ interface EtagResult {
88
89
  declare function generateEtag(content: string, algorithm?: EtagAlgorithm, weak?: boolean): EtagResult | {
89
90
  error: string;
90
91
  };
92
+ interface KnownHostsEntry {
93
+ host: string;
94
+ keyType: string;
95
+ fingerprintSha256: string;
96
+ fingerprintMd5: string;
97
+ bits?: number;
98
+ weak: boolean;
99
+ weakReason?: string;
100
+ }
101
+ interface KnownHostsCheckResult {
102
+ entries: KnownHostsEntry[];
103
+ }
104
+ /**
105
+ * Parse an ssh_known_hosts file (or a single `host keytype base64key
106
+ * [comment]` line) and compute each entry's SHA256 and MD5 fingerprint the
107
+ * same way `ssh-keygen -lf` does: SHA256 is the base64 (no padding) of the
108
+ * SHA-256 digest of the decoded key blob, MD5 is the colon-separated hex of
109
+ * the MD5 digest. Also decodes the key type and, for RSA, the modulus bit
110
+ * length, flagging a weak RSA key (<2048 bits) or a deprecated ssh-dss
111
+ * (DSA) key. `@cert-authority`/`@revoked` markers are skipped. Operates
112
+ * only on public key material already present in the file; never touches a
113
+ * private key.
114
+ */
115
+ declare function checkKnownHostsFingerprints(input: string): KnownHostsCheckResult | {
116
+ error: string;
117
+ };
91
118
 
92
119
  type hashing_BcryptResult = BcryptResult;
93
120
  declare const hashing_ETAG_ALGORITHMS: typeof ETAG_ALGORITHMS;
@@ -99,10 +126,13 @@ type hashing_HashAlgorithm = HashAlgorithm;
99
126
  type hashing_HashResult = HashResult;
100
127
  type hashing_HtpasswdAlgorithm = HtpasswdAlgorithm;
101
128
  type hashing_HtpasswdEntry = HtpasswdEntry;
129
+ type hashing_KnownHostsCheckResult = KnownHostsCheckResult;
130
+ type hashing_KnownHostsEntry = KnownHostsEntry;
102
131
  declare const hashing_ROUND_OPTIONS: typeof ROUND_OPTIONS;
103
132
  declare const hashing_SRI_ALGORITHMS: typeof SRI_ALGORITHMS;
104
133
  type hashing_SriAlgorithm = SriAlgorithm;
105
134
  type hashing_SriResult = SriResult;
135
+ declare const hashing_checkKnownHostsFingerprints: typeof checkKnownHostsFingerprints;
106
136
  declare const hashing_createEntry: typeof createEntry;
107
137
  declare const hashing_generateBcryptHash: typeof generateBcryptHash;
108
138
  declare const hashing_generateEtag: typeof generateEtag;
@@ -121,7 +151,7 @@ declare const hashing_validateRounds: typeof validateRounds;
121
151
  declare const hashing_validateUsername: typeof validateUsername;
122
152
  declare const hashing_verifyPassword: typeof verifyPassword;
123
153
  declare namespace hashing {
124
- export { type hashing_BcryptResult as BcryptResult, hashing_ETAG_ALGORITHMS as ETAG_ALGORITHMS, type hashing_EtagAlgorithm as EtagAlgorithm, type hashing_EtagResult as EtagResult, hashing_HASH_ALGORITHMS as HASH_ALGORITHMS, hashing_HASH_BITS as HASH_BITS, type hashing_HashAlgorithm as HashAlgorithm, type hashing_HashResult as HashResult, type hashing_HtpasswdAlgorithm as HtpasswdAlgorithm, type hashing_HtpasswdEntry as HtpasswdEntry, hashing_ROUND_OPTIONS as ROUND_OPTIONS, hashing_SRI_ALGORITHMS as SRI_ALGORITHMS, type hashing_SriAlgorithm as SriAlgorithm, type hashing_SriResult as SriResult, hashing_createEntry as createEntry, hashing_generateBcryptHash as generateBcryptHash, hashing_generateEtag as generateEtag, hashing_generateHtpasswdFile as generateHtpasswdFile, hashing_generateMd5Hash as generateMd5Hash, hashing_generatePlain as generatePlain, hashing_generateSha1Hash as generateSha1Hash, hashing_generateSri as generateSri, hashing_generateSriAll as generateSriAll, hashing_hashAll as hashAll, hashing_hashOne as hashOne, hashing_hashPassword as hashPassword, hashing_hashWithTiming as hashWithTiming, hashing_parseHtpasswdFile as parseHtpasswdFile, hashing_validateRounds as validateRounds, hashing_validateUsername as validateUsername, hashing_verifyPassword as verifyPassword };
154
+ export { type hashing_BcryptResult as BcryptResult, hashing_ETAG_ALGORITHMS as ETAG_ALGORITHMS, type hashing_EtagAlgorithm as EtagAlgorithm, type hashing_EtagResult as EtagResult, hashing_HASH_ALGORITHMS as HASH_ALGORITHMS, hashing_HASH_BITS as HASH_BITS, type hashing_HashAlgorithm as HashAlgorithm, type hashing_HashResult as HashResult, type hashing_HtpasswdAlgorithm as HtpasswdAlgorithm, type hashing_HtpasswdEntry as HtpasswdEntry, type hashing_KnownHostsCheckResult as KnownHostsCheckResult, type hashing_KnownHostsEntry as KnownHostsEntry, hashing_ROUND_OPTIONS as ROUND_OPTIONS, hashing_SRI_ALGORITHMS as SRI_ALGORITHMS, type hashing_SriAlgorithm as SriAlgorithm, type hashing_SriResult as SriResult, hashing_checkKnownHostsFingerprints as checkKnownHostsFingerprints, hashing_createEntry as createEntry, hashing_generateBcryptHash as generateBcryptHash, hashing_generateEtag as generateEtag, hashing_generateHtpasswdFile as generateHtpasswdFile, hashing_generateMd5Hash as generateMd5Hash, hashing_generatePlain as generatePlain, hashing_generateSha1Hash as generateSha1Hash, hashing_generateSri as generateSri, hashing_generateSriAll as generateSriAll, hashing_hashAll as hashAll, hashing_hashOne as hashOne, hashing_hashPassword as hashPassword, hashing_hashWithTiming as hashWithTiming, hashing_parseHtpasswdFile as parseHtpasswdFile, hashing_validateRounds as validateRounds, hashing_validateUsername as validateUsername, hashing_verifyPassword as verifyPassword };
125
155
  }
126
156
 
127
- export { verifyPassword as A, type BcryptResult as B, ETAG_ALGORITHMS as E, HASH_ALGORITHMS as H, ROUND_OPTIONS as R, SRI_ALGORITHMS as S, type EtagAlgorithm as a, type EtagResult as b, HASH_BITS as c, type HashAlgorithm as d, type HashResult as e, type HtpasswdAlgorithm as f, type HtpasswdEntry as g, hashing as h, type SriAlgorithm as i, type SriResult as j, createEntry as k, generateBcryptHash as l, generateEtag as m, generateHtpasswdFile as n, generateMd5Hash as o, generatePlain as p, generateSha1Hash as q, generateSri as r, generateSriAll as s, hashAll as t, hashOne as u, hashPassword as v, hashWithTiming as w, parseHtpasswdFile as x, validateRounds as y, validateUsername as z };
157
+ export { validateRounds as A, type BcryptResult as B, validateUsername as C, verifyPassword as D, ETAG_ALGORITHMS as E, HASH_ALGORITHMS as H, type KnownHostsCheckResult as K, ROUND_OPTIONS as R, SRI_ALGORITHMS as S, type EtagAlgorithm as a, type EtagResult as b, HASH_BITS as c, type HashAlgorithm as d, type HashResult as e, type HtpasswdAlgorithm as f, type HtpasswdEntry as g, hashing as h, type KnownHostsEntry as i, type SriAlgorithm as j, type SriResult as k, checkKnownHostsFingerprints as l, createEntry as m, generateBcryptHash as n, generateEtag as o, generateHtpasswdFile as p, generateMd5Hash as q, generatePlain as r, generateSha1Hash as s, generateSri as t, generateSriAll as u, hashAll as v, hashOne as w, hashPassword as x, hashWithTiming as y, parseHtpasswdFile as z };
package/dist/index.cjs CHANGED
@@ -71,6 +71,7 @@ __export(json_exports, {
71
71
  resolveJsonPointer: () => resolveJsonPointer,
72
72
  toPascalCase: () => toPascalCase,
73
73
  toSnakeCase: () => toSnakeCase,
74
+ validateGeoJson: () => validateGeoJson,
74
75
  validateJson: () => validateJson,
75
76
  validateJsonPath: () => validateJsonPath,
76
77
  validateJsonString: () => validateJsonString,
@@ -1689,6 +1690,171 @@ function generateJsonPatch(aJson, bJson) {
1689
1690
  }
1690
1691
  return { patch: diffJsonPatch(a, b) };
1691
1692
  }
1693
+ var GEOJSON_GEOMETRY_TYPES = /* @__PURE__ */ new Set([
1694
+ "Point",
1695
+ "MultiPoint",
1696
+ "LineString",
1697
+ "MultiLineString",
1698
+ "Polygon",
1699
+ "MultiPolygon",
1700
+ "GeometryCollection"
1701
+ ]);
1702
+ function _isGeoJsonNumber(v) {
1703
+ return typeof v === "number" && Number.isFinite(v);
1704
+ }
1705
+ function _isGeoJsonPosition(v) {
1706
+ return Array.isArray(v) && (v.length === 2 || v.length === 3) && v.every(_isGeoJsonNumber);
1707
+ }
1708
+ function _geoJsonPositionsEqual(a, b) {
1709
+ return a.length === b.length && a.every((v, i) => v === b[i]);
1710
+ }
1711
+ function _geoJsonRingSignedArea(ring) {
1712
+ let sum = 0;
1713
+ for (let i = 0; i < ring.length - 1; i++) {
1714
+ const [x1, y1] = ring[i];
1715
+ const [x2, y2] = ring[i + 1];
1716
+ sum += x1 * y2 - x2 * y1;
1717
+ }
1718
+ return sum / 2;
1719
+ }
1720
+ function _validateGeoJsonPolygonCoords(coords, path, errors, warnings) {
1721
+ if (!Array.isArray(coords) || coords.length === 0) {
1722
+ errors.push({ path, message: "Polygon coordinates must be a non-empty array of linear rings" });
1723
+ return;
1724
+ }
1725
+ coords.forEach((ring, i) => {
1726
+ const ringPath = `${path}[${i}]`;
1727
+ if (!Array.isArray(ring) || ring.length < 4 || !ring.every(_isGeoJsonPosition)) {
1728
+ errors.push({ path: ringPath, message: "each linear ring must have at least 4 positions" });
1729
+ return;
1730
+ }
1731
+ const first = ring[0];
1732
+ const last = ring[ring.length - 1];
1733
+ if (!_geoJsonPositionsEqual(first, last)) {
1734
+ errors.push({ path: ringPath, message: "the first and last positions of a linear ring must be identical (the ring must be closed)" });
1735
+ return;
1736
+ }
1737
+ const area = _geoJsonRingSignedArea(ring);
1738
+ const isExterior = i === 0;
1739
+ if (isExterior && area < 0) {
1740
+ warnings.push({ path: ringPath, message: "exterior ring winds clockwise; RFC 7946 recommends counterclockwise for exterior rings (right-hand rule)" });
1741
+ } else if (!isExterior && area > 0) {
1742
+ warnings.push({ path: ringPath, message: "interior ring (hole) winds counterclockwise; RFC 7946 recommends clockwise for interior rings (right-hand rule)" });
1743
+ }
1744
+ });
1745
+ }
1746
+ function _validateGeoJsonGeometry(geom, path, errors, warnings) {
1747
+ if (geom === null) return;
1748
+ if (typeof geom !== "object" || Array.isArray(geom)) {
1749
+ errors.push({ path, message: "geometry must be an object or null" });
1750
+ return;
1751
+ }
1752
+ const type = geom.type;
1753
+ if (typeof type !== "string" || !GEOJSON_GEOMETRY_TYPES.has(type)) {
1754
+ errors.push({ path: `${path}.type`, message: `geometry type must be one of ${[...GEOJSON_GEOMETRY_TYPES].join(", ")}` });
1755
+ return;
1756
+ }
1757
+ if (type === "GeometryCollection") {
1758
+ if (!Array.isArray(geom.geometries)) {
1759
+ errors.push({ path: `${path}.geometries`, message: 'GeometryCollection must have a "geometries" array' });
1760
+ return;
1761
+ }
1762
+ geom.geometries.forEach((g, i) => _validateGeoJsonGeometry(g, `${path}.geometries[${i}]`, errors, warnings));
1763
+ return;
1764
+ }
1765
+ const coords = geom.coordinates;
1766
+ const coordPath = `${path}.coordinates`;
1767
+ switch (type) {
1768
+ case "Point":
1769
+ if (!_isGeoJsonPosition(coords)) errors.push({ path: coordPath, message: "Point coordinates must be an array of 2 or 3 numbers" });
1770
+ break;
1771
+ case "MultiPoint":
1772
+ if (!Array.isArray(coords) || !coords.every(_isGeoJsonPosition)) {
1773
+ errors.push({ path: coordPath, message: "MultiPoint coordinates must be an array of positions" });
1774
+ }
1775
+ break;
1776
+ case "LineString":
1777
+ if (!Array.isArray(coords) || coords.length < 2 || !coords.every(_isGeoJsonPosition)) {
1778
+ errors.push({ path: coordPath, message: "LineString coordinates must be an array of at least 2 positions" });
1779
+ }
1780
+ break;
1781
+ case "MultiLineString":
1782
+ if (!Array.isArray(coords) || !coords.every((line) => Array.isArray(line) && line.length >= 2 && line.every(_isGeoJsonPosition))) {
1783
+ errors.push({ path: coordPath, message: "MultiLineString coordinates must be an array of LineString coordinate arrays" });
1784
+ }
1785
+ break;
1786
+ case "Polygon":
1787
+ _validateGeoJsonPolygonCoords(coords, coordPath, errors, warnings);
1788
+ break;
1789
+ case "MultiPolygon":
1790
+ if (!Array.isArray(coords)) {
1791
+ errors.push({ path: coordPath, message: "MultiPolygon coordinates must be an array of Polygon coordinate arrays" });
1792
+ } else {
1793
+ coords.forEach((poly, i) => _validateGeoJsonPolygonCoords(poly, `${coordPath}[${i}]`, errors, warnings));
1794
+ }
1795
+ break;
1796
+ }
1797
+ }
1798
+ function _validateGeoJsonBbox(bbox, path, errors) {
1799
+ if (bbox === void 0) return;
1800
+ if (!Array.isArray(bbox) || bbox.length % 2 !== 0 || bbox.length < 4 || !bbox.every(_isGeoJsonNumber)) {
1801
+ errors.push({ path: `${path}.bbox`, message: "bbox must be an array of 2*n numbers (min/max per axis)" });
1802
+ }
1803
+ }
1804
+ function _validateGeoJsonFeature(feature, path, errors, warnings) {
1805
+ if (typeof feature !== "object" || feature === null || Array.isArray(feature)) {
1806
+ errors.push({ path, message: "Feature must be an object" });
1807
+ return;
1808
+ }
1809
+ if (feature.type !== "Feature") {
1810
+ errors.push({ path: `${path}.type`, message: '"type" must be "Feature"' });
1811
+ }
1812
+ if (!("properties" in feature) || typeof feature.properties !== "object") {
1813
+ errors.push({ path: `${path}.properties`, message: '"properties" member is required and must be an object or null' });
1814
+ }
1815
+ if (!("geometry" in feature)) {
1816
+ errors.push({ path: `${path}.geometry`, message: '"geometry" member is required (an object or null)' });
1817
+ } else {
1818
+ _validateGeoJsonGeometry(feature.geometry, `${path}.geometry`, errors, warnings);
1819
+ }
1820
+ _validateGeoJsonBbox(feature.bbox, path, errors);
1821
+ }
1822
+ function validateGeoJson(input) {
1823
+ let doc;
1824
+ if (typeof input === "string") {
1825
+ try {
1826
+ doc = JSON.parse(input);
1827
+ } catch (e) {
1828
+ return { valid: false, type: null, errors: [{ path: "$", message: `invalid JSON: ${e.message}` }], warnings: [] };
1829
+ }
1830
+ } else {
1831
+ doc = input;
1832
+ }
1833
+ if (typeof doc !== "object" || doc === null || Array.isArray(doc)) {
1834
+ return { valid: false, type: null, errors: [{ path: "$", message: "document must be a JSON object" }], warnings: [] };
1835
+ }
1836
+ const type = doc.type;
1837
+ if (typeof type !== "string") {
1838
+ return { valid: false, type: null, errors: [{ path: "$.type", message: '"type" member is required' }], warnings: [] };
1839
+ }
1840
+ const errors = [];
1841
+ const warnings = [];
1842
+ _validateGeoJsonBbox(doc.bbox, "$", errors);
1843
+ if (type === "FeatureCollection") {
1844
+ if (!Array.isArray(doc.features)) {
1845
+ errors.push({ path: "$.features", message: 'FeatureCollection must have a "features" array' });
1846
+ } else {
1847
+ doc.features.forEach((feature, i) => _validateGeoJsonFeature(feature, `$.features[${i}]`, errors, warnings));
1848
+ }
1849
+ } else if (type === "Feature") {
1850
+ _validateGeoJsonFeature(doc, "$", errors, warnings);
1851
+ } else if (GEOJSON_GEOMETRY_TYPES.has(type)) {
1852
+ _validateGeoJsonGeometry(doc, "$", errors, warnings);
1853
+ } else {
1854
+ errors.push({ path: "$.type", message: '"type" must be one of Feature, FeatureCollection, or a geometry type' });
1855
+ }
1856
+ return { valid: errors.length === 0, type, errors, warnings };
1857
+ }
1692
1858
 
1693
1859
  // src/tools/encoding.ts
1694
1860
  var encoding_exports = {};
@@ -2020,6 +2186,7 @@ __export(hashing_exports, {
2020
2186
  HASH_BITS: () => HASH_BITS,
2021
2187
  ROUND_OPTIONS: () => ROUND_OPTIONS,
2022
2188
  SRI_ALGORITHMS: () => SRI_ALGORITHMS,
2189
+ checkKnownHostsFingerprints: () => checkKnownHostsFingerprints,
2023
2190
  createEntry: () => createEntry,
2024
2191
  generateBcryptHash: () => generateBcryptHash,
2025
2192
  generateEtag: () => generateEtag,
@@ -2301,6 +2468,94 @@ function generateEtag(content, algorithm = "SHA-1", weak = false) {
2301
2468
  const etag = weak ? `W/${quoted}` : quoted;
2302
2469
  return { algorithm, weak, hash, etag, headerName: "ETag", snippet: `ETag: ${etag}` };
2303
2470
  }
2471
+ function _readSshString(buf, offset) {
2472
+ if (offset + 4 > buf.length) return null;
2473
+ const len = buf.readUInt32BE(offset);
2474
+ const start = offset + 4;
2475
+ const end = start + len;
2476
+ if (end > buf.length) return null;
2477
+ return { value: buf.subarray(start, end), next: end };
2478
+ }
2479
+ function _mpintBitLength(buf) {
2480
+ let i = 0;
2481
+ while (i < buf.length - 1 && buf[i] === 0) i++;
2482
+ const trimmed = buf.subarray(i);
2483
+ if (trimmed.length === 0) return 0;
2484
+ let bits = (trimmed.length - 1) * 8;
2485
+ let firstByte = trimmed[0];
2486
+ while (firstByte > 0) {
2487
+ bits++;
2488
+ firstByte >>= 1;
2489
+ }
2490
+ return bits;
2491
+ }
2492
+ function _analyzeKnownHostsKey(keyType, blob) {
2493
+ if (keyType === "ssh-dss") {
2494
+ return { weak: true, weakReason: "DSA (ssh-dss) keys are deprecated and considered weak" };
2495
+ }
2496
+ if (keyType === "ssh-rsa") {
2497
+ const typeField = _readSshString(blob, 0);
2498
+ if (!typeField) return { weak: false };
2499
+ const eField = _readSshString(blob, typeField.next);
2500
+ if (!eField) return { weak: false };
2501
+ const nField = _readSshString(blob, eField.next);
2502
+ if (!nField) return { weak: false };
2503
+ const bits = _mpintBitLength(nField.value);
2504
+ return bits > 0 && bits < 2048 ? { bits, weak: true, weakReason: `RSA modulus is only ${bits} bits; 2048+ is recommended` } : { bits, weak: false };
2505
+ }
2506
+ if (keyType === "ssh-ed25519") {
2507
+ return { bits: 256, weak: false };
2508
+ }
2509
+ if (keyType.startsWith("ecdsa-sha2-")) {
2510
+ const curve = keyType.split("-").pop() ?? "";
2511
+ const bits = curve === "nistp256" ? 256 : curve === "nistp384" ? 384 : curve === "nistp521" ? 521 : void 0;
2512
+ return { bits, weak: false };
2513
+ }
2514
+ return { weak: false };
2515
+ }
2516
+ function checkKnownHostsFingerprints(input) {
2517
+ if (typeof input !== "string" || input.trim().length === 0) {
2518
+ return { error: "input is required" };
2519
+ }
2520
+ const lines = input.split("\n").map((l) => l.trim()).filter((l) => l.length > 0 && !l.startsWith("#"));
2521
+ if (lines.length === 0) {
2522
+ return { error: "No known_hosts entries found" };
2523
+ }
2524
+ const entries = [];
2525
+ for (const line of lines) {
2526
+ const parts = line.split(/\s+/);
2527
+ let idx = 0;
2528
+ if (parts[0] === "@cert-authority" || parts[0] === "@revoked") idx = 1;
2529
+ if (parts.length < idx + 3) {
2530
+ return { error: `Malformed line: "${line}"` };
2531
+ }
2532
+ const host = parts[idx];
2533
+ const keyType = parts[idx + 1];
2534
+ const base64Key = parts[idx + 2];
2535
+ let blob;
2536
+ try {
2537
+ blob = Buffer.from(base64Key, "base64");
2538
+ } catch {
2539
+ return { error: `Invalid base64 key for host "${host}"` };
2540
+ }
2541
+ if (blob.length === 0) {
2542
+ return { error: `Invalid base64 key for host "${host}"` };
2543
+ }
2544
+ const sha256 = crypto.createHash("sha256").update(blob).digest("base64").replace(/=+$/, "");
2545
+ const md52 = crypto.createHash("md5").update(blob).digest("hex").replace(/(.{2})(?=.)/g, "$1:");
2546
+ const analysis = _analyzeKnownHostsKey(keyType, blob);
2547
+ entries.push({
2548
+ host,
2549
+ keyType,
2550
+ fingerprintSha256: `SHA256:${sha256}`,
2551
+ fingerprintMd5: `MD5:${md52}`,
2552
+ bits: analysis.bits,
2553
+ weak: analysis.weak,
2554
+ weakReason: analysis.weakReason
2555
+ });
2556
+ }
2557
+ return { entries };
2558
+ }
2304
2559
 
2305
2560
  // src/tools/text.ts
2306
2561
  var text_exports = {};
@@ -9478,6 +9733,7 @@ __export(units_exports, {
9478
9733
  calculateDebtToIncomeRatio: () => calculateDebtToIncomeRatio,
9479
9734
  calculateDepreciationSchedule: () => calculateDepreciationSchedule,
9480
9735
  calculateDiscount: () => calculateDiscount,
9736
+ calculateDividendYield: () => calculateDividendYield,
9481
9737
  calculateEmi: () => calculateEmi,
9482
9738
  calculateExtraPaymentPayoff: () => calculateExtraPaymentPayoff,
9483
9739
  calculateFreelancerRate: () => calculateFreelancerRate,
@@ -9510,6 +9766,7 @@ __export(units_exports, {
9510
9766
  convertAprApy: () => convertAprApy,
9511
9767
  convertBytes: () => convertBytes,
9512
9768
  convertIp: () => convertIp,
9769
+ convertTimecode: () => convertTimecode,
9513
9770
  coverBox: () => coverBox,
9514
9771
  decimalToIp: () => decimalToIp,
9515
9772
  decimalToIpCidr: () => decimalToIpCidr,
@@ -12748,6 +13005,144 @@ function calculatePositionSize(input) {
12748
13005
  targetOnCorrectSide
12749
13006
  };
12750
13007
  }
13008
+ var TIMECODE_NOMINAL_FPS = {
13009
+ "23.976": 24,
13010
+ "24": 24,
13011
+ "25": 25,
13012
+ "29.97": 30,
13013
+ "30": 30,
13014
+ "50": 50,
13015
+ "59.94": 60,
13016
+ "60": 60
13017
+ };
13018
+ function _timecodeNominalFps(frameRate) {
13019
+ return TIMECODE_NOMINAL_FPS[String(frameRate)] ?? null;
13020
+ }
13021
+ function _timecodeIsDropFrameEligible(frameRate) {
13022
+ return frameRate === 29.97 || frameRate === 59.94;
13023
+ }
13024
+ function _framesToPlainTimecode(frameNumber, nominalFps) {
13025
+ const framesPerDay = nominalFps * 86400;
13026
+ const fn = (frameNumber % framesPerDay + framesPerDay) % framesPerDay;
13027
+ const frames = fn % nominalFps;
13028
+ const totalSeconds = Math.floor(fn / nominalFps);
13029
+ return {
13030
+ hours: Math.floor(totalSeconds / 3600) % 24,
13031
+ minutes: Math.floor(totalSeconds / 60) % 60,
13032
+ seconds: totalSeconds % 60,
13033
+ frames
13034
+ };
13035
+ }
13036
+ function _plainTimecodeToFrames(hh, mm, ss, ff, nominalFps) {
13037
+ return nominalFps * 3600 * hh + nominalFps * 60 * mm + nominalFps * ss + ff;
13038
+ }
13039
+ function _framesToDropFrameTimecode(frameNumber, nominalFps, frameRate) {
13040
+ const dropFrames = nominalFps === 30 ? 2 : 4;
13041
+ const framesPer24Hours = Math.round(frameRate * 86400);
13042
+ const framesPer10Minutes = Math.round(frameRate * 600);
13043
+ const framesPerMinute = nominalFps * 60 - dropFrames;
13044
+ const fn = (frameNumber % framesPer24Hours + framesPer24Hours) % framesPer24Hours;
13045
+ const d = Math.floor(fn / framesPer10Minutes);
13046
+ const m = fn % framesPer10Minutes;
13047
+ let frameNumberOut = fn + 9 * dropFrames * d;
13048
+ if (m > dropFrames) {
13049
+ frameNumberOut += dropFrames * Math.floor((m - dropFrames) / framesPerMinute);
13050
+ }
13051
+ const frames = frameNumberOut % nominalFps;
13052
+ const totalSeconds = Math.floor(frameNumberOut / nominalFps);
13053
+ return {
13054
+ hours: Math.floor(totalSeconds / 3600) % 24,
13055
+ minutes: Math.floor(totalSeconds / 60) % 60,
13056
+ seconds: totalSeconds % 60,
13057
+ frames
13058
+ };
13059
+ }
13060
+ function _dropFrameTimecodeToFrames(hh, mm, ss, ff, nominalFps) {
13061
+ const dropFrames = nominalFps === 30 ? 2 : 4;
13062
+ const totalMinutes = 60 * hh + mm;
13063
+ return nominalFps * 3600 * hh + nominalFps * 60 * mm + nominalFps * ss + ff - dropFrames * (totalMinutes - Math.floor(totalMinutes / 10));
13064
+ }
13065
+ function _formatTimecode(parts, dropFrame) {
13066
+ const p2 = (n) => String(n).padStart(2, "0");
13067
+ const sep = dropFrame ? ";" : ":";
13068
+ return `${p2(parts.hours)}:${p2(parts.minutes)}:${p2(parts.seconds)}${sep}${p2(parts.frames)}`;
13069
+ }
13070
+ function convertTimecode(input) {
13071
+ const { mode, frameRate } = input;
13072
+ const dropFrame = input.dropFrame ?? false;
13073
+ const nominalFps = _timecodeNominalFps(frameRate);
13074
+ if (nominalFps === null) {
13075
+ return { error: "frameRate must be one of 23.976, 24, 25, 29.97, 30, 50, 59.94, 60" };
13076
+ }
13077
+ if (dropFrame && !_timecodeIsDropFrameEligible(frameRate)) {
13078
+ return { error: "dropFrame is only valid for frameRate 29.97 or 59.94" };
13079
+ }
13080
+ if (mode === "frames-to-timecode") {
13081
+ const { frameCount } = input;
13082
+ if (typeof frameCount !== "number" || !Number.isFinite(frameCount) || frameCount < 0 || Math.floor(frameCount) !== frameCount) {
13083
+ return { error: 'frameCount must be a non-negative integer for mode "frames-to-timecode"' };
13084
+ }
13085
+ const parts = dropFrame ? _framesToDropFrameTimecode(frameCount, nominalFps, frameRate) : _framesToPlainTimecode(frameCount, nominalFps);
13086
+ return {
13087
+ mode,
13088
+ frameRate,
13089
+ dropFrame,
13090
+ frameCount,
13091
+ timecode: _formatTimecode(parts, dropFrame),
13092
+ seconds: Math.round(frameCount / frameRate * 1e6) / 1e6
13093
+ };
13094
+ }
13095
+ if (mode === "timecode-to-frames") {
13096
+ const { timecode } = input;
13097
+ if (typeof timecode !== "string") return { error: 'timecode must be a string for mode "timecode-to-frames"' };
13098
+ const match = /^(\d{2}):(\d{2}):(\d{2})[:;](\d{2})$/.exec(timecode.trim());
13099
+ if (!match) return { error: "timecode must be in the form HH:MM:SS:FF (or HH:MM:SS;FF)" };
13100
+ const [, hhS, mmS, ssS, ffS] = match;
13101
+ const hh = Number(hhS), mm = Number(mmS), ss = Number(ssS), ff = Number(ffS);
13102
+ if (hh > 23) return { error: "hours must be 00-23" };
13103
+ if (mm > 59) return { error: "minutes must be 00-59" };
13104
+ if (ss > 59) return { error: "seconds must be 00-59" };
13105
+ if (ff >= nominalFps) return { error: `frames must be 00-${nominalFps - 1} at this frame rate` };
13106
+ if (dropFrame && ff <= 1 && ss === 0 && mm % 10 !== 0) {
13107
+ return { error: `frame ${ffS} at ${hhS}:${mmS}:${ssS} does not exist in drop-frame timecode: frames 00 and 01 are dropped at the start of every minute except every 10th minute` };
13108
+ }
13109
+ const frameCount = dropFrame ? _dropFrameTimecodeToFrames(hh, mm, ss, ff, nominalFps) : _plainTimecodeToFrames(hh, mm, ss, ff, nominalFps);
13110
+ return {
13111
+ mode,
13112
+ frameRate,
13113
+ dropFrame,
13114
+ frameCount,
13115
+ timecode: _formatTimecode({ hours: hh, minutes: mm, seconds: ss, frames: ff }, dropFrame),
13116
+ seconds: Math.round(frameCount / frameRate * 1e6) / 1e6
13117
+ };
13118
+ }
13119
+ return { error: 'mode must be "frames-to-timecode" or "timecode-to-frames"' };
13120
+ }
13121
+ function calculateDividendYield(input) {
13122
+ const { annualDividendPerShare, sharePrice, epsPerShare } = input;
13123
+ if (!Number.isFinite(annualDividendPerShare) || annualDividendPerShare < 0) {
13124
+ return { error: "annualDividendPerShare must be a finite number greater than or equal to zero" };
13125
+ }
13126
+ if (!Number.isFinite(sharePrice) || sharePrice <= 0) {
13127
+ return { error: "sharePrice must be a finite number greater than zero" };
13128
+ }
13129
+ const round4 = (n) => Math.round(n * 1e4) / 1e4;
13130
+ const result = {
13131
+ annualDividendPerShare: round4(annualDividendPerShare),
13132
+ sharePrice: round4(sharePrice),
13133
+ dividendYieldPercent: round4(annualDividendPerShare / sharePrice * 100)
13134
+ };
13135
+ if (epsPerShare !== void 0) {
13136
+ if (!Number.isFinite(epsPerShare) || epsPerShare <= 0) {
13137
+ return { error: "epsPerShare must be a finite number greater than zero when provided" };
13138
+ }
13139
+ const payoutRatioPercent = annualDividendPerShare / epsPerShare * 100;
13140
+ result.epsPerShare = round4(epsPerShare);
13141
+ result.payoutRatioPercent = round4(payoutRatioPercent);
13142
+ result.retentionRatioPercent = round4(100 - payoutRatioPercent);
13143
+ }
13144
+ return result;
13145
+ }
12751
13146
 
12752
13147
  // src/tools/network.ts
12753
13148
  var network_exports = {};
package/dist/index.d.cts CHANGED
@@ -1,11 +1,11 @@
1
- export { j as json } from './json-Ca6gZCNB.cjs';
1
+ export { j as json } from './json-BtRszk1w.cjs';
2
2
  export { e as encoding } from './encoding-Dk3wpmb3.cjs';
3
- export { h as hashing } from './hashing-CJjlvqS_.cjs';
3
+ export { h as hashing } from './hashing-D2VIYoFn.cjs';
4
4
  export { t as text } from './text-DFCNpyvH.cjs';
5
5
  export { d as data } from './data-Dg5dEwWl.cjs';
6
6
  export { g as generators } from './generators-DAXXrMvG.cjs';
7
7
  export { t as time } from './time-VMAy_SrV.cjs';
8
- export { u as units } from './units-7rkeDBbW.cjs';
8
+ export { u as units } from './units-CmkM7-WZ.cjs';
9
9
  export { n as network } from './network-B6fQrsCc.cjs';
10
10
  export { a as api } from './api-CQnIUrVB.cjs';
11
11
  export { c as code } from './code-CZHElFHu.cjs';
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- export { j as json } from './json-Ca6gZCNB.js';
1
+ export { j as json } from './json-BtRszk1w.js';
2
2
  export { e as encoding } from './encoding-Dk3wpmb3.js';
3
- export { h as hashing } from './hashing-CJjlvqS_.js';
3
+ export { h as hashing } from './hashing-D2VIYoFn.js';
4
4
  export { t as text } from './text-DFCNpyvH.js';
5
5
  export { d as data } from './data-Dg5dEwWl.js';
6
6
  export { g as generators } from './generators-DAXXrMvG.js';
7
7
  export { t as time } from './time-VMAy_SrV.js';
8
- export { u as units } from './units-7rkeDBbW.js';
8
+ export { u as units } from './units-CmkM7-WZ.js';
9
9
  export { n as network } from './network-B6fQrsCc.js';
10
10
  export { a as api } from './api-CQnIUrVB.js';
11
11
  export { c as code } from './code-CZHElFHu.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { media_exports as media } from './chunk-YSS4VVZU.js';
2
- export { units_exports as units } from './chunk-NFTUG3XP.js';
2
+ export { units_exports as units } from './chunk-3LHLFKP7.js';
3
3
  export { network_exports as network } from './chunk-K242OOF4.js';
4
4
  export { api_exports as api } from './chunk-U2HREMZU.js';
5
5
  export { code_exports as code } from './chunk-KRPIOHJ4.js';
@@ -7,9 +7,9 @@ export { color_exports as color } from './chunk-BPVAB4P2.js';
7
7
  export { css_exports as css } from './chunk-6YPV2AB5.js';
8
8
  export { misc_exports as misc } from './chunk-GX7H6TAX.js';
9
9
  export { ai_agent_exports as ai_agent } from './chunk-5VVC7BHS.js';
10
- export { json_exports as json } from './chunk-WUOZHCIC.js';
10
+ export { json_exports as json } from './chunk-PAMHORKV.js';
11
11
  export { encoding_exports as encoding } from './chunk-DOWQZUTP.js';
12
- export { hashing_exports as hashing } from './chunk-PET2CGTH.js';
12
+ export { hashing_exports as hashing } from './chunk-3BFKPP5R.js';
13
13
  export { text_exports as text } from './chunk-2YWKRNDM.js';
14
14
  export { data_exports as data } from './chunk-NTHUTIZH.js';
15
15
  export { generators_exports as generators } from './chunk-422ICOZX.js';
@@ -16,6 +16,7 @@
16
16
  * - json-schema-to-typescript : jsonSchemaToTypescript
17
17
  * - json-merge-patch : mergeJsonPatch, applyJsonMergePatch
18
18
  * - json-patch : diffJsonPatch, applyJsonPatch, generateJsonPatch
19
+ * - geojson-validator : validateGeoJson
19
20
  */
20
21
  type ParseStatus = 'idle' | 'valid' | 'error';
21
22
  interface JsonParseResult {
@@ -258,11 +259,35 @@ declare function generateJsonPatch(aJson: string, bJson: string): {
258
259
  } | {
259
260
  error: string;
260
261
  };
262
+ interface GeoJsonIssue {
263
+ path: string;
264
+ message: string;
265
+ }
266
+ interface GeoJsonValidateResult {
267
+ valid: boolean;
268
+ type: string | null;
269
+ errors: GeoJsonIssue[];
270
+ warnings: GeoJsonIssue[];
271
+ }
272
+ /**
273
+ * Validate a GeoJSON document's structure against RFC 7946: the correct
274
+ * geometry type and coordinates shape for each of the seven geometry types,
275
+ * linear ring closure (first and last position identical) for Polygon and
276
+ * MultiPolygon, a Feature's required `properties`/`geometry` members, and a
277
+ * FeatureCollection's required `features` array. Also warns, without
278
+ * failing validation, when a Polygon ring winds the "wrong" way under RFC
279
+ * 7946's right-hand rule, since that's a SHOULD, not a MUST, and plenty of
280
+ * real-world producers don't follow it. Pure structural validation; no map
281
+ * is rendered and no tile server is ever contacted.
282
+ */
283
+ declare function validateGeoJson(input: string | object): GeoJsonValidateResult;
261
284
 
262
285
  type json_ConvertOptions = ConvertOptions;
263
286
  type json_CsvOptions = CsvOptions;
264
287
  type json_DiffNode = DiffNode;
265
288
  type json_DiffType = DiffType;
289
+ type json_GeoJsonIssue = GeoJsonIssue;
290
+ type json_GeoJsonValidateResult = GeoJsonValidateResult;
266
291
  type json_GoField = GoField;
267
292
  type json_GoStruct = GoStruct;
268
293
  type json_JsonDiffResult = JsonDiffResult;
@@ -310,12 +335,13 @@ declare const json_parseStructs: typeof parseStructs;
310
335
  declare const json_resolveJsonPointer: typeof resolveJsonPointer;
311
336
  declare const json_toPascalCase: typeof toPascalCase;
312
337
  declare const json_toSnakeCase: typeof toSnakeCase;
338
+ declare const json_validateGeoJson: typeof validateGeoJson;
313
339
  declare const json_validateJson: typeof validateJson;
314
340
  declare const json_validateJsonPath: typeof validateJsonPath;
315
341
  declare const json_validateJsonString: typeof validateJsonString;
316
342
  declare const json_yamlToJson: typeof yamlToJson;
317
343
  declare namespace json {
318
- export { type json_ConvertOptions as ConvertOptions, type json_CsvOptions as CsvOptions, type json_DiffNode as DiffNode, type json_DiffType as DiffType, type json_GoField as GoField, type json_GoStruct as GoStruct, type json_JsonDiffResult as JsonDiffResult, type json_JsonParseResult as JsonParseResult, type json_JsonPatchOp as JsonPatchOp, type json_JsonPatchOperation as JsonPatchOperation, type json_JsonPathResult as JsonPathResult, type json_JsonPointerResult as JsonPointerResult, type json_JsonSchemaLike as JsonSchemaLike, type json_JsonSchemaToTsOptions as JsonSchemaToTsOptions, type json_MergePatchResult as MergePatchResult, type json_ParseStatus as ParseStatus, type json_PythonClass as PythonClass, type json_PythonField as PythonField, type json_PythonMode as PythonMode, type json_ValidationError as ValidationError, type json_ValidationResult as ValidationResult, type json_ZodOptions as ZodOptions, json_applyJsonMergePatch as applyJsonMergePatch, json_applyJsonPatch as applyJsonPatch, json_csvToJson as csvToJson, json_detectFormat as detectFormat, json_diffJson as diffJson, json_diffJsonPatch as diffJsonPatch, json_evaluateJsonPath as evaluateJsonPath, json_formatDiffLine as formatDiffLine, json_formatJson as formatJson, json_generateExample as generateExample, json_generateJsonPatch as generateJsonPatch, json_getJsonStats as getJsonStats, json_inferGoType as inferGoType, json_inferPythonType as inferPythonType, json_inferType as inferType, json_jsonSchemaToTypescript as jsonSchemaToTypescript, json_jsonToCsv as jsonToCsv, json_jsonToGo as jsonToGo, json_jsonToPython as jsonToPython, json_jsonToTypescript as jsonToTypescript, json_jsonToYaml as jsonToYaml, json_jsonToZod as jsonToZod, json_mergeJsonPatch as mergeJsonPatch, json_minifyJson as minifyJson, json_parseJson as parseJson, json_parseStructs as parseStructs, json_resolveJsonPointer as resolveJsonPointer, json_toPascalCase as toPascalCase, json_toSnakeCase as toSnakeCase, json_validateJson as validateJson, json_validateJsonPath as validateJsonPath, json_validateJsonString as validateJsonString, json_yamlToJson as yamlToJson };
344
+ export { type json_ConvertOptions as ConvertOptions, type json_CsvOptions as CsvOptions, type json_DiffNode as DiffNode, type json_DiffType as DiffType, type json_GeoJsonIssue as GeoJsonIssue, type json_GeoJsonValidateResult as GeoJsonValidateResult, type json_GoField as GoField, type json_GoStruct as GoStruct, type json_JsonDiffResult as JsonDiffResult, type json_JsonParseResult as JsonParseResult, type json_JsonPatchOp as JsonPatchOp, type json_JsonPatchOperation as JsonPatchOperation, type json_JsonPathResult as JsonPathResult, type json_JsonPointerResult as JsonPointerResult, type json_JsonSchemaLike as JsonSchemaLike, type json_JsonSchemaToTsOptions as JsonSchemaToTsOptions, type json_MergePatchResult as MergePatchResult, type json_ParseStatus as ParseStatus, type json_PythonClass as PythonClass, type json_PythonField as PythonField, type json_PythonMode as PythonMode, type json_ValidationError as ValidationError, type json_ValidationResult as ValidationResult, type json_ZodOptions as ZodOptions, json_applyJsonMergePatch as applyJsonMergePatch, json_applyJsonPatch as applyJsonPatch, json_csvToJson as csvToJson, json_detectFormat as detectFormat, json_diffJson as diffJson, json_diffJsonPatch as diffJsonPatch, json_evaluateJsonPath as evaluateJsonPath, json_formatDiffLine as formatDiffLine, json_formatJson as formatJson, json_generateExample as generateExample, json_generateJsonPatch as generateJsonPatch, json_getJsonStats as getJsonStats, json_inferGoType as inferGoType, json_inferPythonType as inferPythonType, json_inferType as inferType, json_jsonSchemaToTypescript as jsonSchemaToTypescript, json_jsonToCsv as jsonToCsv, json_jsonToGo as jsonToGo, json_jsonToPython as jsonToPython, json_jsonToTypescript as jsonToTypescript, json_jsonToYaml as jsonToYaml, json_jsonToZod as jsonToZod, json_mergeJsonPatch as mergeJsonPatch, json_minifyJson as minifyJson, json_parseJson as parseJson, json_parseStructs as parseStructs, json_resolveJsonPointer as resolveJsonPointer, json_toPascalCase as toPascalCase, json_toSnakeCase as toSnakeCase, json_validateGeoJson as validateGeoJson, json_validateJson as validateJson, json_validateJsonPath as validateJsonPath, json_validateJsonString as validateJsonString, json_yamlToJson as yamlToJson };
319
345
  }
320
346
 
321
- export { validateJsonPath as $, getJsonStats as A, inferGoType as B, type ConvertOptions as C, type DiffNode as D, inferPythonType as E, inferType as F, type GoField as G, jsonSchemaToTypescript as H, jsonToCsv as I, type JsonDiffResult as J, jsonToGo as K, jsonToPython as L, type MergePatchResult as M, jsonToTypescript as N, jsonToYaml as O, type ParseStatus as P, jsonToZod as Q, mergeJsonPatch as R, minifyJson as S, parseJson as T, parseStructs as U, type ValidationError as V, resolveJsonPointer as W, toPascalCase as X, toSnakeCase as Y, type ZodOptions as Z, validateJson as _, type CsvOptions as a, validateJsonString as a0, yamlToJson as a1, type DiffType as b, type GoStruct as c, type JsonParseResult as d, type JsonPatchOp as e, type JsonPatchOperation as f, type JsonPathResult as g, type JsonPointerResult as h, type JsonSchemaLike as i, json as j, type JsonSchemaToTsOptions as k, type PythonClass as l, type PythonField as m, type PythonMode as n, type ValidationResult as o, applyJsonMergePatch as p, applyJsonPatch as q, csvToJson as r, detectFormat as s, diffJson as t, diffJsonPatch as u, evaluateJsonPath as v, formatDiffLine as w, formatJson as x, generateExample as y, generateJsonPatch as z };
347
+ export { toSnakeCase as $, generateExample as A, generateJsonPatch as B, type ConvertOptions as C, type DiffNode as D, getJsonStats as E, inferGoType as F, type GeoJsonIssue as G, inferPythonType as H, inferType as I, type JsonDiffResult as J, jsonSchemaToTypescript as K, jsonToCsv as L, type MergePatchResult as M, jsonToGo as N, jsonToPython as O, type ParseStatus as P, jsonToTypescript as Q, jsonToYaml as R, jsonToZod as S, mergeJsonPatch as T, minifyJson as U, type ValidationError as V, parseJson as W, parseStructs as X, resolveJsonPointer as Y, type ZodOptions as Z, toPascalCase as _, type CsvOptions as a, validateGeoJson as a0, validateJson as a1, validateJsonPath as a2, validateJsonString as a3, yamlToJson as a4, type DiffType as b, type GeoJsonValidateResult as c, type GoField as d, type GoStruct as e, type JsonParseResult as f, type JsonPatchOp as g, type JsonPatchOperation as h, type JsonPathResult as i, json as j, type JsonPointerResult as k, type JsonSchemaLike as l, type JsonSchemaToTsOptions as m, type PythonClass as n, type PythonField as o, type PythonMode as p, type ValidationResult as q, applyJsonMergePatch as r, applyJsonPatch as s, csvToJson as t, detectFormat as u, diffJson as v, diffJsonPatch as w, evaluateJsonPath as x, formatDiffLine as y, formatJson as z };