@utilix-tech/sdk 0.10.0 → 0.12.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 +7 -0
- package/README.md +25 -7
- package/dist/{chunk-YVFM5WYI.js → chunk-CJGHHS5M.js} +188 -1
- package/dist/{chunk-GUUYEIU6.js → chunk-XMKJYVKB.js} +35 -1
- package/dist/index.cjs +225 -4
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{media-C3ZvGyKc.d.cts → media-9HEpTPGA.d.cts} +29 -2
- package/dist/{media-C3ZvGyKc.d.ts → media-9HEpTPGA.d.ts} +29 -2
- package/dist/tools/media.cjs +34 -0
- package/dist/tools/media.d.cts +1 -1
- package/dist/tools/media.d.ts +1 -1
- package/dist/tools/media.js +1 -1
- package/dist/tools/units.cjs +187 -0
- package/dist/tools/units.d.cts +1 -1
- package/dist/tools/units.d.ts +1 -1
- package/dist/tools/units.js +1 -1
- package/dist/{units-DRT6W-vu.d.cts → units-Dt80-S2j.d.cts} +69 -2
- package/dist/{units-DRT6W-vu.d.ts → units-Dt80-S2j.d.ts} +69 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
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.12.0
|
|
6
|
+
- Added ICO Favicon Inspector (`readIcoInfo`) and Barcode Checksum Validator (`validateBarcode`).
|
|
7
|
+
|
|
8
|
+
## 0.11.0
|
|
9
|
+
- Added IBAN Validator / Formatter (`validateIban`) and Loan / Mortgage Calculator (`calculateLoan`).
|
|
10
|
+
- (npm publish for this version was retried after fixing a CI pin: `npm install -g npm@latest` started pulling npm 12, which requires Node >=22 and broke on this job's pinned Node 20 — now pinned to the npm 11 line.)
|
|
11
|
+
|
|
5
12
|
## 0.10.0
|
|
6
13
|
- Added robots.txt Validator and Credit Card Number Validator.
|
|
7
14
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @utilix-tech/sdk
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**535 developer utility functions for Node.js: runs locally, no API key required.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
6
6
|
[](https://www.npmjs.com/package/@utilix-tech/sdk)
|
|
@@ -242,7 +242,7 @@ getNextRuns("*/5 * * * *", 5); // next 5 run timestamps
|
|
|
242
242
|
### `/units`: Conversions
|
|
243
243
|
|
|
244
244
|
```ts
|
|
245
|
-
import { convertBytes, pxToAll, convert, formatValue, validateCardNumber } from "@utilix-tech/sdk/units";
|
|
245
|
+
import { convertBytes, pxToAll, convert, formatValue, validateCardNumber, validateIban, calculateLoan, validateBarcode } from "@utilix-tech/sdk/units";
|
|
246
246
|
|
|
247
247
|
// File sizes
|
|
248
248
|
convertBytes(1073741824, "GB"); // 1
|
|
@@ -264,6 +264,18 @@ formatValue(1234567.89, { locale: "en-US", currency: "USD" });
|
|
|
264
264
|
// Credit card Luhn checksum + network detection
|
|
265
265
|
validateCardNumber("4111 1111 1111 1111");
|
|
266
266
|
// { valid: true, network: "Visa", length: 16, formatted: "4111 1111 1111 1111" }
|
|
267
|
+
|
|
268
|
+
// IBAN mod-97 checksum + formatting
|
|
269
|
+
validateIban("DE89 3704 0044 0532 0130 00");
|
|
270
|
+
// { valid: true, countryCode: "DE", checksumValid: true, formatted: "DE89 3704 0044 0532 0130 00", ... }
|
|
271
|
+
|
|
272
|
+
// Loan / mortgage amortization
|
|
273
|
+
calculateLoan(200000, 6.5, 360);
|
|
274
|
+
// { monthlyPayment: 1264.14, totalInterest: 255085.82, termMonths: 360, schedule: [...] }
|
|
275
|
+
|
|
276
|
+
// EAN-13 / EAN-8 / UPC-A barcode checksum validation
|
|
277
|
+
validateBarcode("4006381333931");
|
|
278
|
+
// { valid: true, format: "EAN-13", digits: "4006381333931", checkDigit: 1, expectedCheckDigit: 1 }
|
|
267
279
|
```
|
|
268
280
|
|
|
269
281
|
---
|
|
@@ -436,10 +448,10 @@ analyzeString("café"); // { length: 4, codePoints: [...], ... }
|
|
|
436
448
|
|
|
437
449
|
---
|
|
438
450
|
|
|
439
|
-
### `/media`: Image Header Parsing, EXIF, PDF, WAV &
|
|
451
|
+
### `/media`: Image Header Parsing, EXIF, PDF, WAV, ID3 & ICO Metadata
|
|
440
452
|
|
|
441
453
|
```ts
|
|
442
|
-
import { readImageInfo, readExifData, readPdfMetadata, readWavInfo, readId3Tags } from "@utilix-tech/sdk/media";
|
|
454
|
+
import { readImageInfo, readExifData, readPdfMetadata, readWavInfo, readId3Tags, readIcoInfo } from "@utilix-tech/sdk/media";
|
|
443
455
|
|
|
444
456
|
// Reads format, dimensions, bit depth, and alpha channel straight from
|
|
445
457
|
// file bytes: no decoding, no canvas, no image library.
|
|
@@ -471,9 +483,15 @@ readWavInfo(new Uint8Array(wavBytes));
|
|
|
471
483
|
const mp3Bytes = await fs.promises.readFile("track.mp3");
|
|
472
484
|
readId3Tags(new Uint8Array(mp3Bytes));
|
|
473
485
|
// { version: "ID3v2.3.0", title: "Track Name", artist: "Artist Name", genre: "Rock", ... }
|
|
486
|
+
|
|
487
|
+
// Reads how many images a .ico file embeds and each one's dimensions, color
|
|
488
|
+
// depth, and size directly from its ICONDIR/ICONDIRENTRY header table.
|
|
489
|
+
const icoBytes = await fs.promises.readFile("favicon.ico");
|
|
490
|
+
readIcoInfo(new Uint8Array(icoBytes));
|
|
491
|
+
// { imageCount: 3, images: [{ width: 16, height: 16, bitCount: 32, bytesInRes: 1128, ... }, ...] }
|
|
474
492
|
```
|
|
475
493
|
|
|
476
|
-
`readImageInfo` supports PNG, JPEG, GIF, WebP, and BMP. `readExifData` supports JPEG only. `readWavInfo` supports the canonical RIFF/WAVE container only. `readId3Tags` decodes ID3v2.3/2.4 and ID3v1/1.1 only (ID3v2.2 is detected but not decoded).
|
|
494
|
+
`readImageInfo` supports PNG, JPEG, GIF, WebP, and BMP. `readExifData` supports JPEG only. `readWavInfo` supports the canonical RIFF/WAVE container only. `readId3Tags` decodes ID3v2.3/2.4 and ID3v1/1.1 only (ID3v2.2 is detected but not decoded). `readIcoInfo` reads .ico icon files only and rejects .cur cursor files.
|
|
477
495
|
|
|
478
496
|
---
|
|
479
497
|
|
|
@@ -488,7 +506,7 @@ readId3Tags(new Uint8Array(mp3Bytes));
|
|
|
488
506
|
| `@utilix-tech/sdk/data` | CSV, YAML, TOML, XML, INI, NDJSON parse and convert |
|
|
489
507
|
| `@utilix-tech/sdk/generators` | UUID v4/v7, ULID, passwords, strength check, fake data |
|
|
490
508
|
| `@utilix-tech/sdk/time` | Date diff, timezone convert, cron parse, relative time |
|
|
491
|
-
| `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format |
|
|
509
|
+
| `@utilix-tech/sdk/units` | Bytes, CSS px/rem, number bases, currency format, credit card/IBAN/barcode validation, loan calculator |
|
|
492
510
|
| `@utilix-tech/sdk/network` | HTTP status codes, IP validation, country flags, geolocation URLs, HAR file parsing |
|
|
493
511
|
| `@utilix-tech/sdk/api` | cURL build/parse, JWT decode/sign, JWKS parse, CORS headers, CSP header |
|
|
494
512
|
| `@utilix-tech/sdk/code` | SQL format/minify, HTML format/minify, regex tester, GraphQL format |
|
|
@@ -496,7 +514,7 @@ readId3Tags(new Uint8Array(mp3Bytes));
|
|
|
496
514
|
| `@utilix-tech/sdk/css` | CSS gradient, box-shadow, border-radius, keyframe animation generators |
|
|
497
515
|
| `@utilix-tech/sdk/misc` | SVG optimize/sanitize, file size format, Unicode inspector |
|
|
498
516
|
| `@utilix-tech/sdk/ai_agent` | Token estimate/trim, chunk text, extract URLs/JSON/keywords, sanitize HTML, flatten/merge JSON, dedupe lines, validate schema, PII/secret/injection detect |
|
|
499
|
-
| `@utilix-tech/sdk/media` | Image format & dimension reading from raw bytes (PNG, JPEG, GIF, WebP, BMP); PDF metadata reading; WAV audio info |
|
|
517
|
+
| `@utilix-tech/sdk/media` | Image format & dimension reading from raw bytes (PNG, JPEG, GIF, WebP, BMP); PDF metadata reading; WAV audio info; ID3 tags; ICO favicon inspection |
|
|
500
518
|
|
|
501
519
|
---
|
|
502
520
|
|
|
@@ -16,6 +16,7 @@ __export(units_exports, {
|
|
|
16
16
|
bumpVersion: () => bumpVersion,
|
|
17
17
|
calcAspectRatio: () => calcAspectRatio,
|
|
18
18
|
calcSubnet: () => calcSubnet,
|
|
19
|
+
calculateLoan: () => calculateLoan,
|
|
19
20
|
compareSemver: () => compareSemver,
|
|
20
21
|
convert: () => convert,
|
|
21
22
|
convertBytes: () => convertBytes,
|
|
@@ -60,7 +61,9 @@ __export(units_exports, {
|
|
|
60
61
|
sortVersions: () => sortVersions,
|
|
61
62
|
splitSubnet: () => splitSubnet,
|
|
62
63
|
symbolicToPermissions: () => symbolicToPermissions,
|
|
64
|
+
validateBarcode: () => validateBarcode,
|
|
63
65
|
validateCardNumber: () => validateCardNumber,
|
|
66
|
+
validateIban: () => validateIban,
|
|
64
67
|
viewportToPx: () => viewportToPx
|
|
65
68
|
});
|
|
66
69
|
function pxToAll(px, baseFontSize = 16, viewportWidth = 1440, viewportHeight = 900) {
|
|
@@ -953,5 +956,189 @@ function validateCardNumber(input) {
|
|
|
953
956
|
const formatted = formatCardNumber(digits, network);
|
|
954
957
|
return { valid, network, length: digits.length, formatted };
|
|
955
958
|
}
|
|
959
|
+
var IBAN_COUNTRY_LENGTHS = {
|
|
960
|
+
AD: 24,
|
|
961
|
+
AE: 23,
|
|
962
|
+
AL: 28,
|
|
963
|
+
AT: 20,
|
|
964
|
+
AZ: 28,
|
|
965
|
+
BA: 20,
|
|
966
|
+
BE: 16,
|
|
967
|
+
BG: 22,
|
|
968
|
+
BH: 22,
|
|
969
|
+
BR: 29,
|
|
970
|
+
BY: 28,
|
|
971
|
+
CH: 21,
|
|
972
|
+
CR: 22,
|
|
973
|
+
CY: 28,
|
|
974
|
+
CZ: 24,
|
|
975
|
+
DE: 22,
|
|
976
|
+
DK: 18,
|
|
977
|
+
DO: 28,
|
|
978
|
+
EE: 20,
|
|
979
|
+
EG: 29,
|
|
980
|
+
ES: 24,
|
|
981
|
+
FI: 18,
|
|
982
|
+
FO: 18,
|
|
983
|
+
FR: 27,
|
|
984
|
+
GB: 22,
|
|
985
|
+
GE: 22,
|
|
986
|
+
GI: 23,
|
|
987
|
+
GL: 18,
|
|
988
|
+
GR: 27,
|
|
989
|
+
GT: 28,
|
|
990
|
+
HR: 21,
|
|
991
|
+
HU: 28,
|
|
992
|
+
IE: 22,
|
|
993
|
+
IL: 23,
|
|
994
|
+
IQ: 23,
|
|
995
|
+
IS: 26,
|
|
996
|
+
IT: 27,
|
|
997
|
+
JO: 30,
|
|
998
|
+
KW: 30,
|
|
999
|
+
KZ: 20,
|
|
1000
|
+
LB: 28,
|
|
1001
|
+
LC: 32,
|
|
1002
|
+
LI: 21,
|
|
1003
|
+
LT: 20,
|
|
1004
|
+
LU: 20,
|
|
1005
|
+
LV: 21,
|
|
1006
|
+
LY: 25,
|
|
1007
|
+
MC: 27,
|
|
1008
|
+
MD: 24,
|
|
1009
|
+
ME: 22,
|
|
1010
|
+
MK: 19,
|
|
1011
|
+
MR: 27,
|
|
1012
|
+
MT: 31,
|
|
1013
|
+
MU: 30,
|
|
1014
|
+
NL: 18,
|
|
1015
|
+
NO: 15,
|
|
1016
|
+
PK: 24,
|
|
1017
|
+
PL: 28,
|
|
1018
|
+
PS: 29,
|
|
1019
|
+
PT: 25,
|
|
1020
|
+
QA: 29,
|
|
1021
|
+
RO: 24,
|
|
1022
|
+
RS: 22,
|
|
1023
|
+
SA: 24,
|
|
1024
|
+
SC: 31,
|
|
1025
|
+
SE: 24,
|
|
1026
|
+
SI: 19,
|
|
1027
|
+
SK: 24,
|
|
1028
|
+
SM: 27,
|
|
1029
|
+
ST: 25,
|
|
1030
|
+
SV: 28,
|
|
1031
|
+
TL: 23,
|
|
1032
|
+
TN: 24,
|
|
1033
|
+
TR: 26,
|
|
1034
|
+
UA: 29,
|
|
1035
|
+
VA: 22,
|
|
1036
|
+
VG: 24,
|
|
1037
|
+
XK: 20
|
|
1038
|
+
};
|
|
1039
|
+
function ibanMod97(numeric) {
|
|
1040
|
+
let remainder = 0;
|
|
1041
|
+
for (let i = 0; i < numeric.length; i += 7) {
|
|
1042
|
+
remainder = parseInt(String(remainder) + numeric.substr(i, 7), 10) % 97;
|
|
1043
|
+
}
|
|
1044
|
+
return remainder;
|
|
1045
|
+
}
|
|
1046
|
+
function formatIban(cleaned) {
|
|
1047
|
+
return cleaned.match(/.{1,4}/g)?.join(" ") ?? cleaned;
|
|
1048
|
+
}
|
|
1049
|
+
function validateIban(input) {
|
|
1050
|
+
if (!input || !input.trim()) return { error: "Input is empty" };
|
|
1051
|
+
const cleaned = input.replace(/\s/g, "").toUpperCase();
|
|
1052
|
+
if (!/^[A-Z0-9]+$/.test(cleaned)) return { error: "IBAN must contain only letters and digits" };
|
|
1053
|
+
if (cleaned.length < 4 || cleaned.length > 34) {
|
|
1054
|
+
return { error: `IBAN length (${cleaned.length}) is outside the valid range of 4-34 characters` };
|
|
1055
|
+
}
|
|
1056
|
+
if (!/^[A-Z]{2}\d{2}/.test(cleaned)) {
|
|
1057
|
+
return { error: "IBAN must start with a 2-letter country code followed by 2 check digits" };
|
|
1058
|
+
}
|
|
1059
|
+
const countryCode = cleaned.slice(0, 2);
|
|
1060
|
+
const checkDigits = cleaned.slice(2, 4);
|
|
1061
|
+
const bban = cleaned.slice(4);
|
|
1062
|
+
const rearranged = cleaned.slice(4) + cleaned.slice(0, 4);
|
|
1063
|
+
const numeric = rearranged.split("").map((ch) => /[A-Z]/.test(ch) ? String(ch.charCodeAt(0) - 55) : ch).join("");
|
|
1064
|
+
const checksumValid = ibanMod97(numeric) === 1;
|
|
1065
|
+
const expectedLength = IBAN_COUNTRY_LENGTHS[countryCode] ?? null;
|
|
1066
|
+
const lengthValid = expectedLength === null ? null : cleaned.length === expectedLength;
|
|
1067
|
+
const valid = checksumValid && lengthValid !== false;
|
|
1068
|
+
return {
|
|
1069
|
+
valid,
|
|
1070
|
+
formatted: formatIban(cleaned),
|
|
1071
|
+
countryCode,
|
|
1072
|
+
checkDigits,
|
|
1073
|
+
bban,
|
|
1074
|
+
length: cleaned.length,
|
|
1075
|
+
expectedLength,
|
|
1076
|
+
checksumValid,
|
|
1077
|
+
lengthValid
|
|
1078
|
+
};
|
|
1079
|
+
}
|
|
1080
|
+
function round2(n) {
|
|
1081
|
+
return Math.round(n * 100) / 100;
|
|
1082
|
+
}
|
|
1083
|
+
function calculateLoan(principal, annualRatePercent, termMonths) {
|
|
1084
|
+
if (!Number.isFinite(principal) || principal <= 0) return { error: "Principal must be a positive number" };
|
|
1085
|
+
if (!Number.isFinite(annualRatePercent) || annualRatePercent < 0) {
|
|
1086
|
+
return { error: "Annual interest rate must be zero or a positive number" };
|
|
1087
|
+
}
|
|
1088
|
+
if (!Number.isInteger(termMonths) || termMonths <= 0) {
|
|
1089
|
+
return { error: "Term must be a positive whole number of months" };
|
|
1090
|
+
}
|
|
1091
|
+
const monthlyRate = annualRatePercent / 100 / 12;
|
|
1092
|
+
let monthlyPayment;
|
|
1093
|
+
if (monthlyRate === 0) {
|
|
1094
|
+
monthlyPayment = principal / termMonths;
|
|
1095
|
+
} else {
|
|
1096
|
+
const factor = Math.pow(1 + monthlyRate, termMonths);
|
|
1097
|
+
monthlyPayment = principal * monthlyRate * factor / (factor - 1);
|
|
1098
|
+
}
|
|
1099
|
+
const schedule = [];
|
|
1100
|
+
let balance = round2(principal);
|
|
1101
|
+
let totalPayment = 0;
|
|
1102
|
+
for (let month = 1; month <= termMonths; month++) {
|
|
1103
|
+
const interest = monthlyRate === 0 ? 0 : round2(balance * monthlyRate);
|
|
1104
|
+
let principalPortion = round2(monthlyPayment) - interest;
|
|
1105
|
+
if (month === termMonths || principalPortion > balance) principalPortion = balance;
|
|
1106
|
+
const payment = round2(principalPortion + interest);
|
|
1107
|
+
balance = round2(balance - principalPortion);
|
|
1108
|
+
totalPayment += payment;
|
|
1109
|
+
schedule.push({ month, payment, principal: round2(principalPortion), interest, balance: Math.max(balance, 0) });
|
|
1110
|
+
}
|
|
1111
|
+
return {
|
|
1112
|
+
monthlyPayment: round2(monthlyPayment),
|
|
1113
|
+
totalPayment: round2(totalPayment),
|
|
1114
|
+
totalInterest: round2(totalPayment - principal),
|
|
1115
|
+
termMonths,
|
|
1116
|
+
schedule
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
var BARCODE_FORMAT_BY_LENGTH = { 8: "EAN-8", 12: "UPC-A", 13: "EAN-13" };
|
|
1120
|
+
function computeBarcodeCheckDigit(dataDigits) {
|
|
1121
|
+
let sum = 0;
|
|
1122
|
+
const n = dataDigits.length;
|
|
1123
|
+
for (let i = 0; i < n; i++) {
|
|
1124
|
+
const distanceFromEnd = n - 1 - i;
|
|
1125
|
+
const weight = distanceFromEnd % 2 === 0 ? 3 : 1;
|
|
1126
|
+
sum += dataDigits[i] * weight;
|
|
1127
|
+
}
|
|
1128
|
+
return (10 - sum % 10) % 10;
|
|
1129
|
+
}
|
|
1130
|
+
function validateBarcode(input) {
|
|
1131
|
+
if (!input || !input.trim()) return { error: "Input is empty" };
|
|
1132
|
+
const digits = input.replace(/[\s-]/g, "");
|
|
1133
|
+
if (!/^\d+$/.test(digits)) return { error: "Barcode must contain only digits (spaces and hyphens are ignored)" };
|
|
1134
|
+
const format = BARCODE_FORMAT_BY_LENGTH[digits.length];
|
|
1135
|
+
if (!format) {
|
|
1136
|
+
return { error: `Unsupported barcode length (${digits.length} digits); expected 8 (EAN-8), 12 (UPC-A), or 13 (EAN-13)` };
|
|
1137
|
+
}
|
|
1138
|
+
const dataDigits = digits.slice(0, -1).split("").map(Number);
|
|
1139
|
+
const checkDigit = Number(digits[digits.length - 1]);
|
|
1140
|
+
const expectedCheckDigit = computeBarcodeCheckDigit(dataDigits);
|
|
1141
|
+
return { valid: checkDigit === expectedCheckDigit, format, digits, checkDigit, expectedCheckDigit };
|
|
1142
|
+
}
|
|
956
1143
|
|
|
957
|
-
export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_VIEWPORTS, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, compareSemver, convert, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateCardNumber, viewportToPx };
|
|
1144
|
+
export { BASE_LABELS, BASE_PREFIXES, BYTE_UNITS, COMMON_CURRENCIES, COMMON_LOCALES, COMMON_PERMISSIONS, COMMON_RATIOS, COMMON_SIZES, COMMON_VIEWPORTS, autoFormat, bumpVersion, calcAspectRatio, calcSubnet, calculateLoan, compareSemver, convert, convertBytes, convertIp, coverBox, decimalToIp, decimalToIpCidr, describePermissions, fitIntoBox, formatNumber, formatValue, formatVwValue, formatWithSeparator, gcd, ipFromBinary, ipFromDecimal, ipFromHex, ipToBinary, ipToDecimal, ipToDecimalCidr, ipToHex, ipToOctal, isValid, isValidCidr, isValidIp, isValidIpv4, octalToPermissions, parseFileSize, parseInput, parseNumberString, parseSemver, permissionsToChmod, permissionsToOctal, permissionsToSymbolic, ptToPx, pxToAll, pxToViewport, remToPx, satisfiesRange, scaleByHeight, scaleByWidth, sortVersions, splitSubnet, symbolicToPermissions, units_exports, validateBarcode, validateCardNumber, validateIban, viewportToPx };
|
|
@@ -4,6 +4,7 @@ import { __export } from './chunk-MLKGABMK.js';
|
|
|
4
4
|
var media_exports = {};
|
|
5
5
|
__export(media_exports, {
|
|
6
6
|
readExifData: () => readExifData,
|
|
7
|
+
readIcoInfo: () => readIcoInfo,
|
|
7
8
|
readId3Tags: () => readId3Tags,
|
|
8
9
|
readImageInfo: () => readImageInfo,
|
|
9
10
|
readPdfMetadata: () => readPdfMetadata,
|
|
@@ -730,5 +731,38 @@ function readId3Tags(bytes) {
|
|
|
730
731
|
}
|
|
731
732
|
return { error: "No ID3v1 or ID3v2.3/2.4 tags found in this file" };
|
|
732
733
|
}
|
|
734
|
+
function readU16LE(bytes, offset) {
|
|
735
|
+
return bytes[offset] | bytes[offset + 1] << 8;
|
|
736
|
+
}
|
|
737
|
+
function readU32LE(bytes, offset) {
|
|
738
|
+
return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
|
|
739
|
+
}
|
|
740
|
+
function readIcoInfo(bytes) {
|
|
741
|
+
if (bytes.length < 6) return { error: "File too small to be a valid ICO file" };
|
|
742
|
+
if (readU16LE(bytes, 0) !== 0) return { error: "Not a valid ICO file (reserved header field must be 0)" };
|
|
743
|
+
const type = readU16LE(bytes, 2);
|
|
744
|
+
if (type === 2) return { error: "This is a .cur cursor file (type 2), not a .ico icon file" };
|
|
745
|
+
if (type !== 1) return { error: `Unrecognized ICONDIR type (${type}); expected 1 for an icon file` };
|
|
746
|
+
const count = readU16LE(bytes, 4);
|
|
747
|
+
if (count === 0) return { error: "ICO file declares zero embedded images" };
|
|
748
|
+
const images = [];
|
|
749
|
+
for (let i = 0; i < count; i++) {
|
|
750
|
+
const offset = 6 + i * 16;
|
|
751
|
+
if (offset + 16 > bytes.length) return { error: `Truncated ICONDIRENTRY for image ${i}` };
|
|
752
|
+
const widthRaw = bytes[offset];
|
|
753
|
+
const heightRaw = bytes[offset + 1];
|
|
754
|
+
const colorCountRaw = bytes[offset + 2];
|
|
755
|
+
images.push({
|
|
756
|
+
width: widthRaw === 0 ? 256 : widthRaw,
|
|
757
|
+
height: heightRaw === 0 ? 256 : heightRaw,
|
|
758
|
+
colorCount: colorCountRaw === 0 ? null : colorCountRaw,
|
|
759
|
+
planes: readU16LE(bytes, offset + 4),
|
|
760
|
+
bitCount: readU16LE(bytes, offset + 6),
|
|
761
|
+
bytesInRes: readU32LE(bytes, offset + 8),
|
|
762
|
+
imageOffset: readU32LE(bytes, offset + 12)
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
return { imageCount: count, images };
|
|
766
|
+
}
|
|
733
767
|
|
|
734
|
-
export { media_exports, readExifData, readId3Tags, readImageInfo, readPdfMetadata, readWavInfo };
|
|
768
|
+
export { media_exports, readExifData, readIcoInfo, readId3Tags, readImageInfo, readPdfMetadata, readWavInfo };
|
package/dist/index.cjs
CHANGED
|
@@ -6621,6 +6621,7 @@ __export(units_exports, {
|
|
|
6621
6621
|
bumpVersion: () => bumpVersion,
|
|
6622
6622
|
calcAspectRatio: () => calcAspectRatio,
|
|
6623
6623
|
calcSubnet: () => calcSubnet,
|
|
6624
|
+
calculateLoan: () => calculateLoan,
|
|
6624
6625
|
compareSemver: () => compareSemver,
|
|
6625
6626
|
convert: () => convert,
|
|
6626
6627
|
convertBytes: () => convertBytes,
|
|
@@ -6665,7 +6666,9 @@ __export(units_exports, {
|
|
|
6665
6666
|
sortVersions: () => sortVersions,
|
|
6666
6667
|
splitSubnet: () => splitSubnet,
|
|
6667
6668
|
symbolicToPermissions: () => symbolicToPermissions,
|
|
6669
|
+
validateBarcode: () => validateBarcode,
|
|
6668
6670
|
validateCardNumber: () => validateCardNumber,
|
|
6671
|
+
validateIban: () => validateIban,
|
|
6669
6672
|
viewportToPx: () => viewportToPx
|
|
6670
6673
|
});
|
|
6671
6674
|
function pxToAll(px, baseFontSize = 16, viewportWidth = 1440, viewportHeight = 900) {
|
|
@@ -7558,6 +7561,190 @@ function validateCardNumber(input) {
|
|
|
7558
7561
|
const formatted = formatCardNumber(digits, network);
|
|
7559
7562
|
return { valid, network, length: digits.length, formatted };
|
|
7560
7563
|
}
|
|
7564
|
+
var IBAN_COUNTRY_LENGTHS = {
|
|
7565
|
+
AD: 24,
|
|
7566
|
+
AE: 23,
|
|
7567
|
+
AL: 28,
|
|
7568
|
+
AT: 20,
|
|
7569
|
+
AZ: 28,
|
|
7570
|
+
BA: 20,
|
|
7571
|
+
BE: 16,
|
|
7572
|
+
BG: 22,
|
|
7573
|
+
BH: 22,
|
|
7574
|
+
BR: 29,
|
|
7575
|
+
BY: 28,
|
|
7576
|
+
CH: 21,
|
|
7577
|
+
CR: 22,
|
|
7578
|
+
CY: 28,
|
|
7579
|
+
CZ: 24,
|
|
7580
|
+
DE: 22,
|
|
7581
|
+
DK: 18,
|
|
7582
|
+
DO: 28,
|
|
7583
|
+
EE: 20,
|
|
7584
|
+
EG: 29,
|
|
7585
|
+
ES: 24,
|
|
7586
|
+
FI: 18,
|
|
7587
|
+
FO: 18,
|
|
7588
|
+
FR: 27,
|
|
7589
|
+
GB: 22,
|
|
7590
|
+
GE: 22,
|
|
7591
|
+
GI: 23,
|
|
7592
|
+
GL: 18,
|
|
7593
|
+
GR: 27,
|
|
7594
|
+
GT: 28,
|
|
7595
|
+
HR: 21,
|
|
7596
|
+
HU: 28,
|
|
7597
|
+
IE: 22,
|
|
7598
|
+
IL: 23,
|
|
7599
|
+
IQ: 23,
|
|
7600
|
+
IS: 26,
|
|
7601
|
+
IT: 27,
|
|
7602
|
+
JO: 30,
|
|
7603
|
+
KW: 30,
|
|
7604
|
+
KZ: 20,
|
|
7605
|
+
LB: 28,
|
|
7606
|
+
LC: 32,
|
|
7607
|
+
LI: 21,
|
|
7608
|
+
LT: 20,
|
|
7609
|
+
LU: 20,
|
|
7610
|
+
LV: 21,
|
|
7611
|
+
LY: 25,
|
|
7612
|
+
MC: 27,
|
|
7613
|
+
MD: 24,
|
|
7614
|
+
ME: 22,
|
|
7615
|
+
MK: 19,
|
|
7616
|
+
MR: 27,
|
|
7617
|
+
MT: 31,
|
|
7618
|
+
MU: 30,
|
|
7619
|
+
NL: 18,
|
|
7620
|
+
NO: 15,
|
|
7621
|
+
PK: 24,
|
|
7622
|
+
PL: 28,
|
|
7623
|
+
PS: 29,
|
|
7624
|
+
PT: 25,
|
|
7625
|
+
QA: 29,
|
|
7626
|
+
RO: 24,
|
|
7627
|
+
RS: 22,
|
|
7628
|
+
SA: 24,
|
|
7629
|
+
SC: 31,
|
|
7630
|
+
SE: 24,
|
|
7631
|
+
SI: 19,
|
|
7632
|
+
SK: 24,
|
|
7633
|
+
SM: 27,
|
|
7634
|
+
ST: 25,
|
|
7635
|
+
SV: 28,
|
|
7636
|
+
TL: 23,
|
|
7637
|
+
TN: 24,
|
|
7638
|
+
TR: 26,
|
|
7639
|
+
UA: 29,
|
|
7640
|
+
VA: 22,
|
|
7641
|
+
VG: 24,
|
|
7642
|
+
XK: 20
|
|
7643
|
+
};
|
|
7644
|
+
function ibanMod97(numeric) {
|
|
7645
|
+
let remainder = 0;
|
|
7646
|
+
for (let i = 0; i < numeric.length; i += 7) {
|
|
7647
|
+
remainder = parseInt(String(remainder) + numeric.substr(i, 7), 10) % 97;
|
|
7648
|
+
}
|
|
7649
|
+
return remainder;
|
|
7650
|
+
}
|
|
7651
|
+
function formatIban(cleaned) {
|
|
7652
|
+
return cleaned.match(/.{1,4}/g)?.join(" ") ?? cleaned;
|
|
7653
|
+
}
|
|
7654
|
+
function validateIban(input) {
|
|
7655
|
+
if (!input || !input.trim()) return { error: "Input is empty" };
|
|
7656
|
+
const cleaned = input.replace(/\s/g, "").toUpperCase();
|
|
7657
|
+
if (!/^[A-Z0-9]+$/.test(cleaned)) return { error: "IBAN must contain only letters and digits" };
|
|
7658
|
+
if (cleaned.length < 4 || cleaned.length > 34) {
|
|
7659
|
+
return { error: `IBAN length (${cleaned.length}) is outside the valid range of 4-34 characters` };
|
|
7660
|
+
}
|
|
7661
|
+
if (!/^[A-Z]{2}\d{2}/.test(cleaned)) {
|
|
7662
|
+
return { error: "IBAN must start with a 2-letter country code followed by 2 check digits" };
|
|
7663
|
+
}
|
|
7664
|
+
const countryCode = cleaned.slice(0, 2);
|
|
7665
|
+
const checkDigits = cleaned.slice(2, 4);
|
|
7666
|
+
const bban = cleaned.slice(4);
|
|
7667
|
+
const rearranged = cleaned.slice(4) + cleaned.slice(0, 4);
|
|
7668
|
+
const numeric = rearranged.split("").map((ch) => /[A-Z]/.test(ch) ? String(ch.charCodeAt(0) - 55) : ch).join("");
|
|
7669
|
+
const checksumValid = ibanMod97(numeric) === 1;
|
|
7670
|
+
const expectedLength = IBAN_COUNTRY_LENGTHS[countryCode] ?? null;
|
|
7671
|
+
const lengthValid = expectedLength === null ? null : cleaned.length === expectedLength;
|
|
7672
|
+
const valid = checksumValid && lengthValid !== false;
|
|
7673
|
+
return {
|
|
7674
|
+
valid,
|
|
7675
|
+
formatted: formatIban(cleaned),
|
|
7676
|
+
countryCode,
|
|
7677
|
+
checkDigits,
|
|
7678
|
+
bban,
|
|
7679
|
+
length: cleaned.length,
|
|
7680
|
+
expectedLength,
|
|
7681
|
+
checksumValid,
|
|
7682
|
+
lengthValid
|
|
7683
|
+
};
|
|
7684
|
+
}
|
|
7685
|
+
function round2(n) {
|
|
7686
|
+
return Math.round(n * 100) / 100;
|
|
7687
|
+
}
|
|
7688
|
+
function calculateLoan(principal, annualRatePercent, termMonths) {
|
|
7689
|
+
if (!Number.isFinite(principal) || principal <= 0) return { error: "Principal must be a positive number" };
|
|
7690
|
+
if (!Number.isFinite(annualRatePercent) || annualRatePercent < 0) {
|
|
7691
|
+
return { error: "Annual interest rate must be zero or a positive number" };
|
|
7692
|
+
}
|
|
7693
|
+
if (!Number.isInteger(termMonths) || termMonths <= 0) {
|
|
7694
|
+
return { error: "Term must be a positive whole number of months" };
|
|
7695
|
+
}
|
|
7696
|
+
const monthlyRate = annualRatePercent / 100 / 12;
|
|
7697
|
+
let monthlyPayment;
|
|
7698
|
+
if (monthlyRate === 0) {
|
|
7699
|
+
monthlyPayment = principal / termMonths;
|
|
7700
|
+
} else {
|
|
7701
|
+
const factor = Math.pow(1 + monthlyRate, termMonths);
|
|
7702
|
+
monthlyPayment = principal * monthlyRate * factor / (factor - 1);
|
|
7703
|
+
}
|
|
7704
|
+
const schedule = [];
|
|
7705
|
+
let balance = round2(principal);
|
|
7706
|
+
let totalPayment = 0;
|
|
7707
|
+
for (let month = 1; month <= termMonths; month++) {
|
|
7708
|
+
const interest = monthlyRate === 0 ? 0 : round2(balance * monthlyRate);
|
|
7709
|
+
let principalPortion = round2(monthlyPayment) - interest;
|
|
7710
|
+
if (month === termMonths || principalPortion > balance) principalPortion = balance;
|
|
7711
|
+
const payment = round2(principalPortion + interest);
|
|
7712
|
+
balance = round2(balance - principalPortion);
|
|
7713
|
+
totalPayment += payment;
|
|
7714
|
+
schedule.push({ month, payment, principal: round2(principalPortion), interest, balance: Math.max(balance, 0) });
|
|
7715
|
+
}
|
|
7716
|
+
return {
|
|
7717
|
+
monthlyPayment: round2(monthlyPayment),
|
|
7718
|
+
totalPayment: round2(totalPayment),
|
|
7719
|
+
totalInterest: round2(totalPayment - principal),
|
|
7720
|
+
termMonths,
|
|
7721
|
+
schedule
|
|
7722
|
+
};
|
|
7723
|
+
}
|
|
7724
|
+
var BARCODE_FORMAT_BY_LENGTH = { 8: "EAN-8", 12: "UPC-A", 13: "EAN-13" };
|
|
7725
|
+
function computeBarcodeCheckDigit(dataDigits) {
|
|
7726
|
+
let sum = 0;
|
|
7727
|
+
const n = dataDigits.length;
|
|
7728
|
+
for (let i = 0; i < n; i++) {
|
|
7729
|
+
const distanceFromEnd = n - 1 - i;
|
|
7730
|
+
const weight = distanceFromEnd % 2 === 0 ? 3 : 1;
|
|
7731
|
+
sum += dataDigits[i] * weight;
|
|
7732
|
+
}
|
|
7733
|
+
return (10 - sum % 10) % 10;
|
|
7734
|
+
}
|
|
7735
|
+
function validateBarcode(input) {
|
|
7736
|
+
if (!input || !input.trim()) return { error: "Input is empty" };
|
|
7737
|
+
const digits = input.replace(/[\s-]/g, "");
|
|
7738
|
+
if (!/^\d+$/.test(digits)) return { error: "Barcode must contain only digits (spaces and hyphens are ignored)" };
|
|
7739
|
+
const format = BARCODE_FORMAT_BY_LENGTH[digits.length];
|
|
7740
|
+
if (!format) {
|
|
7741
|
+
return { error: `Unsupported barcode length (${digits.length} digits); expected 8 (EAN-8), 12 (UPC-A), or 13 (EAN-13)` };
|
|
7742
|
+
}
|
|
7743
|
+
const dataDigits = digits.slice(0, -1).split("").map(Number);
|
|
7744
|
+
const checkDigit = Number(digits[digits.length - 1]);
|
|
7745
|
+
const expectedCheckDigit = computeBarcodeCheckDigit(dataDigits);
|
|
7746
|
+
return { valid: checkDigit === expectedCheckDigit, format, digits, checkDigit, expectedCheckDigit };
|
|
7747
|
+
}
|
|
7561
7748
|
|
|
7562
7749
|
// src/tools/network.ts
|
|
7563
7750
|
var network_exports = {};
|
|
@@ -17251,6 +17438,7 @@ function summarizeForLlm(text, maxTokens = 200, strategy = "extractive") {
|
|
|
17251
17438
|
var media_exports = {};
|
|
17252
17439
|
__export(media_exports, {
|
|
17253
17440
|
readExifData: () => readExifData,
|
|
17441
|
+
readIcoInfo: () => readIcoInfo,
|
|
17254
17442
|
readId3Tags: () => readId3Tags,
|
|
17255
17443
|
readImageInfo: () => readImageInfo,
|
|
17256
17444
|
readPdfMetadata: () => readPdfMetadata,
|
|
@@ -17452,12 +17640,12 @@ function readGpsCoordinate(r, entries, valueTag, refTag) {
|
|
|
17452
17640
|
function gcd2(a, b) {
|
|
17453
17641
|
return b === 0 ? a : gcd2(b, a % b);
|
|
17454
17642
|
}
|
|
17455
|
-
function
|
|
17643
|
+
function round22(n) {
|
|
17456
17644
|
return Math.round(n * 100) / 100;
|
|
17457
17645
|
}
|
|
17458
17646
|
function formatExposureTime(num, den) {
|
|
17459
17647
|
if (num === 0) return "0s";
|
|
17460
|
-
if (num >= den) return `${
|
|
17648
|
+
if (num >= den) return `${round22(num / den)}s`;
|
|
17461
17649
|
const divisor = gcd2(num, den) || 1;
|
|
17462
17650
|
const n = num / divisor;
|
|
17463
17651
|
const d = den / divisor;
|
|
@@ -17546,14 +17734,14 @@ function readExifData(bytes) {
|
|
|
17546
17734
|
const fEntry = findEntry(sub.entries, 33437);
|
|
17547
17735
|
if (fEntry) {
|
|
17548
17736
|
const rat = readRational(r, fEntry);
|
|
17549
|
-
if (rat && rat.den !== 0) result.fNumber =
|
|
17737
|
+
if (rat && rat.den !== 0) result.fNumber = round22(rat.num / rat.den);
|
|
17550
17738
|
}
|
|
17551
17739
|
const isoEntry = findEntry(sub.entries, 34855);
|
|
17552
17740
|
if (isoEntry) result.isoSpeed = tu16(r, isoEntry.valueOffsetField);
|
|
17553
17741
|
const focalEntry = findEntry(sub.entries, 37386);
|
|
17554
17742
|
if (focalEntry) {
|
|
17555
17743
|
const rat = readRational(r, focalEntry);
|
|
17556
|
-
if (rat && rat.den !== 0) result.focalLength =
|
|
17744
|
+
if (rat && rat.den !== 0) result.focalLength = round22(rat.num / rat.den);
|
|
17557
17745
|
}
|
|
17558
17746
|
}
|
|
17559
17747
|
}
|
|
@@ -17977,6 +18165,39 @@ function readId3Tags(bytes) {
|
|
|
17977
18165
|
}
|
|
17978
18166
|
return { error: "No ID3v1 or ID3v2.3/2.4 tags found in this file" };
|
|
17979
18167
|
}
|
|
18168
|
+
function readU16LE(bytes, offset) {
|
|
18169
|
+
return bytes[offset] | bytes[offset + 1] << 8;
|
|
18170
|
+
}
|
|
18171
|
+
function readU32LE(bytes, offset) {
|
|
18172
|
+
return (bytes[offset] | bytes[offset + 1] << 8 | bytes[offset + 2] << 16 | bytes[offset + 3] << 24) >>> 0;
|
|
18173
|
+
}
|
|
18174
|
+
function readIcoInfo(bytes) {
|
|
18175
|
+
if (bytes.length < 6) return { error: "File too small to be a valid ICO file" };
|
|
18176
|
+
if (readU16LE(bytes, 0) !== 0) return { error: "Not a valid ICO file (reserved header field must be 0)" };
|
|
18177
|
+
const type = readU16LE(bytes, 2);
|
|
18178
|
+
if (type === 2) return { error: "This is a .cur cursor file (type 2), not a .ico icon file" };
|
|
18179
|
+
if (type !== 1) return { error: `Unrecognized ICONDIR type (${type}); expected 1 for an icon file` };
|
|
18180
|
+
const count = readU16LE(bytes, 4);
|
|
18181
|
+
if (count === 0) return { error: "ICO file declares zero embedded images" };
|
|
18182
|
+
const images = [];
|
|
18183
|
+
for (let i = 0; i < count; i++) {
|
|
18184
|
+
const offset = 6 + i * 16;
|
|
18185
|
+
if (offset + 16 > bytes.length) return { error: `Truncated ICONDIRENTRY for image ${i}` };
|
|
18186
|
+
const widthRaw = bytes[offset];
|
|
18187
|
+
const heightRaw = bytes[offset + 1];
|
|
18188
|
+
const colorCountRaw = bytes[offset + 2];
|
|
18189
|
+
images.push({
|
|
18190
|
+
width: widthRaw === 0 ? 256 : widthRaw,
|
|
18191
|
+
height: heightRaw === 0 ? 256 : heightRaw,
|
|
18192
|
+
colorCount: colorCountRaw === 0 ? null : colorCountRaw,
|
|
18193
|
+
planes: readU16LE(bytes, offset + 4),
|
|
18194
|
+
bitCount: readU16LE(bytes, offset + 6),
|
|
18195
|
+
bytesInRes: readU32LE(bytes, offset + 8),
|
|
18196
|
+
imageOffset: readU32LE(bytes, offset + 12)
|
|
18197
|
+
});
|
|
18198
|
+
}
|
|
18199
|
+
return { imageCount: count, images };
|
|
18200
|
+
}
|
|
17980
18201
|
|
|
17981
18202
|
// src/index.ts
|
|
17982
18203
|
var version = "0.1.0";
|
package/dist/index.d.cts
CHANGED
|
@@ -5,7 +5,7 @@ export { t as text } from './text-Bbx-tZ43.cjs';
|
|
|
5
5
|
export { d as data } from './data-D8XTI7Du.cjs';
|
|
6
6
|
export { g as generators } from './generators-BGtRGpJZ.cjs';
|
|
7
7
|
export { t as time } from './time-DbT8fjaF.cjs';
|
|
8
|
-
export { u as units } from './units-
|
|
8
|
+
export { u as units } from './units-Dt80-S2j.cjs';
|
|
9
9
|
export { n as network } from './network-DaNoZ5ER.cjs';
|
|
10
10
|
export { a as api } from './api-Xl7OzIgq.cjs';
|
|
11
11
|
export { c as code } from './code-BUqyaofO.cjs';
|
|
@@ -13,7 +13,7 @@ export { c as color } from './color-tPwZCr9H.cjs';
|
|
|
13
13
|
export { c as css } from './css-Cf7AMGM-.cjs';
|
|
14
14
|
export { m as misc } from './misc-CA3N198T.cjs';
|
|
15
15
|
export { a as ai_agent } from './ai_agent-CcpkV2DR.cjs';
|
|
16
|
-
export { m as media } from './media-
|
|
16
|
+
export { m as media } from './media-9HEpTPGA.cjs';
|
|
17
17
|
|
|
18
18
|
declare const version = "0.1.0";
|
|
19
19
|
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { t as text } from './text-Bbx-tZ43.js';
|
|
|
5
5
|
export { d as data } from './data-D8XTI7Du.js';
|
|
6
6
|
export { g as generators } from './generators-BGtRGpJZ.js';
|
|
7
7
|
export { t as time } from './time-DbT8fjaF.js';
|
|
8
|
-
export { u as units } from './units-
|
|
8
|
+
export { u as units } from './units-Dt80-S2j.js';
|
|
9
9
|
export { n as network } from './network-DaNoZ5ER.js';
|
|
10
10
|
export { a as api } from './api-Xl7OzIgq.js';
|
|
11
11
|
export { c as code } from './code-BUqyaofO.js';
|
|
@@ -13,7 +13,7 @@ export { c as color } from './color-tPwZCr9H.js';
|
|
|
13
13
|
export { c as css } from './css-Cf7AMGM-.js';
|
|
14
14
|
export { m as misc } from './misc-CA3N198T.js';
|
|
15
15
|
export { a as ai_agent } from './ai_agent-CcpkV2DR.js';
|
|
16
|
-
export { m as media } from './media-
|
|
16
|
+
export { m as media } from './media-9HEpTPGA.js';
|
|
17
17
|
|
|
18
18
|
declare const version = "0.1.0";
|
|
19
19
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { media_exports as media } from './chunk-
|
|
2
|
-
export { units_exports as units } from './chunk-
|
|
1
|
+
export { media_exports as media } from './chunk-XMKJYVKB.js';
|
|
2
|
+
export { units_exports as units } from './chunk-CJGHHS5M.js';
|
|
3
3
|
export { network_exports as network } from './chunk-OB56VNKJ.js';
|
|
4
4
|
export { api_exports as api } from './chunk-Q3B3YWOA.js';
|
|
5
5
|
export { code_exports as code } from './chunk-V5S6OJ4A.js';
|