@utilix-tech/sdk 0.40.0 → 0.41.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,10 @@
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.41.0
6
+ - Add `buildRangeHeader`, `parseContentRangeHeader` (http-range-header-builder): build an HTTP `Range` request header from explicit, open-ended, or suffix ("last N bytes") byte ranges, and parse a server's `Content-Range` response to verify what it actually sent back.
7
+ - Add `findCsvDuplicateRows` (csv-duplicate-row-finder): group CSV/TSV rows that share the same value across a chosen set of key columns, or the entire row, and report each duplicate group's occurrence count and data row numbers.
8
+
5
9
  ## 0.40.0
6
10
  - Add `calculateCashBreakdown`, `calculateChange` (cash-till-calculator): break a cash amount down into the minimum count of bills/coins from a set of denominations (largest first), or compute change owed for a payment/tender pair and its breakdown.
7
11
  - Add `generateEtag` (etag-generator): compute a content-hash ETag (MD5/SHA-1/SHA-256) for a response header, with an optional weak-validator (W/) prefix.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @utilix-tech/sdk
2
2
 
3
- **610 developer utility functions for Node.js: runs locally, no API key required.**
3
+ **618 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)
@@ -201,7 +201,7 @@ import { parseCsv, csvToJson, validateYaml, tomlToJson, jsonToToml,
201
201
  formatXml, xmlToJson, jsonToXml, parseIni,
202
202
  validateNdjson, formatNdjson, ndjsonToJsonArray, diffEnvExample,
203
203
  parseSubtitles, convertSubtitles, shiftSubtitles, parseFrontMatter,
204
- generateMarkdownToc, csvToSqlInsert } from "@utilix-tech/sdk/data";
204
+ generateMarkdownToc, csvToSqlInsert, findCsvDuplicateRows } from "@utilix-tech/sdk/data";
205
205
 
206
206
  // CSV
207
207
  const rows = parseCsv("name,age\nalice,30\nbob,25");
@@ -247,6 +247,10 @@ generateMarkdownToc("# Title\n\n## Section One\n\n## Section Two\n");
247
247
  // CSV to SQL INSERT statements, with basic type inference and identifier quoting
248
248
  csvToSqlInsert("name,age\nAlice,30\nBob,25", { tableName: "users" });
249
249
  // { sql: 'INSERT INTO "users" ("name", "age") VALUES (\'Alice\', 30);\n...', rowCount: 2, ... }
250
+
251
+ // Find duplicate rows in CSV/TSV data, by the whole row or a chosen key column set
252
+ findCsvDuplicateRows("name,email\nAlice,a@x.com\nBob,b@x.com\nAlice,a@x.com");
253
+ // { duplicateGroups: [{ key: ["Alice", "a@x.com"], rowNumbers: [1, 3], count: 2 }], duplicateRowCount: 2, ... }
250
254
  ```
251
255
 
252
256
  ---
@@ -428,7 +432,8 @@ calculateChange(4.65, 5.0, USD_DENOMINATIONS);
428
432
  import { getStatusCode, isValidIp, isValidIpv4, isValidIpv6,
429
433
  searchStatusCodes, buildGeoUrl, countryCodeToFlag,
430
434
  parseHar, validateSitemap, validateRobotsTxt,
431
- parseUserAgent, buildCacheControl, buildReferrerPolicy, parseIpv6Address, buildLinkHeader, checkSetCookieHeader, analyzeEmailHeaders } from "@utilix-tech/sdk/network";
435
+ parseUserAgent, buildCacheControl, buildReferrerPolicy, parseIpv6Address, buildLinkHeader, checkSetCookieHeader, analyzeEmailHeaders,
436
+ buildRangeHeader, parseContentRangeHeader } from "@utilix-tech/sdk/network";
432
437
 
433
438
  getStatusCode(404);
434
439
  // { code: 404, text: "Not Found", description: "...", category: "Client Error" }
@@ -483,6 +488,14 @@ checkSetCookieHeader("session=abc123; SameSite=None");
483
488
  // Parse a raw email header block: fields, Received hop chain, SPF/DKIM/DMARC results
484
489
  analyzeEmailHeaders(rawHeaderText);
485
490
  // { from: "...", to: "...", receivedHops: [...], hopCount: 2, spf: "pass", dkim: "pass", dmarc: "pass", warnings: [] }
491
+
492
+ // Build a Range request header from explicit, open-ended, or suffix ("last N bytes") byte ranges
493
+ buildRangeHeader([{ start: 0, end: 1023 }], { totalSize: 146515 });
494
+ // { header: "Range: bytes=0-1023", ranges: [...], totalBytesRequested: 1024, warnings: [] }
495
+
496
+ // Parse a Content-Range response header to verify what a server actually sent back
497
+ parseContentRangeHeader("bytes 200-1000/67589");
498
+ // { unit: "bytes", start: 200, end: 1000, total: 67589, byteLength: 801, isUnsatisfiable: false }
486
499
  ```
487
500
 
488
501
  ---
@@ -14,6 +14,7 @@ __export(network_exports, {
14
14
  buildGeoUrl: () => buildGeoUrl,
15
15
  buildLinkHeader: () => buildLinkHeader,
16
16
  buildMapUrl: () => buildMapUrl,
17
+ buildRangeHeader: () => buildRangeHeader,
17
18
  buildReferrerPolicy: () => buildReferrerPolicy,
18
19
  checkSetCookieHeader: () => checkSetCookieHeader,
19
20
  countryCodeToFlag: () => countryCodeToFlag,
@@ -30,6 +31,7 @@ __export(network_exports, {
30
31
  isValidIp: () => isValidIp,
31
32
  isValidIpv4: () => isValidIpv4,
32
33
  isValidIpv6: () => isValidIpv6,
34
+ parseContentRangeHeader: () => parseContentRangeHeader,
33
35
  parseDnsResponse: () => parseDnsResponse,
34
36
  parseGeoResponse: () => parseGeoResponse,
35
37
  parseHar: () => parseHar,
@@ -2209,5 +2211,118 @@ function analyzeEmailHeaders(raw) {
2209
2211
  warnings
2210
2212
  };
2211
2213
  }
2214
+ function _round2(n) {
2215
+ return Math.round(n * 100) / 100;
2216
+ }
2217
+ function buildRangeHeader(entries, options) {
2218
+ if (!Array.isArray(entries) || entries.length === 0) {
2219
+ return { error: "At least one range is required" };
2220
+ }
2221
+ const unit = options?.unit?.trim() || "bytes";
2222
+ const totalSize = typeof options?.totalSize === "number" && Number.isFinite(options.totalSize) ? options.totalSize : void 0;
2223
+ if (totalSize !== void 0 && totalSize <= 0) {
2224
+ return { error: "totalSize must be a positive number when provided" };
2225
+ }
2226
+ const parsed = [];
2227
+ for (const entry of entries) {
2228
+ if (entry.suffixLength !== void 0) {
2229
+ if (!Number.isFinite(entry.suffixLength) || entry.suffixLength <= 0) {
2230
+ return { error: "suffixLength must be a positive number" };
2231
+ }
2232
+ const suffixLength = Math.floor(entry.suffixLength);
2233
+ const byteLength = totalSize !== void 0 ? Math.min(suffixLength, totalSize) : suffixLength;
2234
+ parsed.push({
2235
+ spec: `-${suffixLength}`,
2236
+ start: null,
2237
+ end: null,
2238
+ suffixLength,
2239
+ byteLength,
2240
+ percentOfTotal: totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
2241
+ });
2242
+ continue;
2243
+ }
2244
+ if (entry.start === void 0) {
2245
+ return { error: "Each range requires either a start byte or a suffixLength" };
2246
+ }
2247
+ if (!Number.isFinite(entry.start) || entry.start < 0) {
2248
+ return { error: "start must be a non-negative number" };
2249
+ }
2250
+ const start = Math.floor(entry.start);
2251
+ if (totalSize !== void 0 && start >= totalSize) {
2252
+ return { error: `start byte ${start} is beyond totalSize (${totalSize})` };
2253
+ }
2254
+ if (entry.end !== void 0) {
2255
+ if (!Number.isFinite(entry.end) || entry.end < 0) {
2256
+ return { error: "end must be a non-negative number" };
2257
+ }
2258
+ const end = Math.floor(entry.end);
2259
+ if (end < start) {
2260
+ return { error: `range end (${end}) must be >= start (${start})` };
2261
+ }
2262
+ if (totalSize !== void 0 && end >= totalSize) {
2263
+ return { error: `end byte ${end} is beyond totalSize (${totalSize})` };
2264
+ }
2265
+ const byteLength = end - start + 1;
2266
+ parsed.push({
2267
+ spec: `${start}-${end}`,
2268
+ start,
2269
+ end,
2270
+ suffixLength: null,
2271
+ byteLength,
2272
+ percentOfTotal: totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
2273
+ });
2274
+ } else {
2275
+ const byteLength = totalSize !== void 0 ? totalSize - start : null;
2276
+ parsed.push({
2277
+ spec: `${start}-`,
2278
+ start,
2279
+ end: null,
2280
+ suffixLength: null,
2281
+ byteLength,
2282
+ percentOfTotal: byteLength !== null && totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
2283
+ });
2284
+ }
2285
+ }
2286
+ const warnings = [];
2287
+ const resolvable = parsed.map((r, i) => ({ i, start: r.start ?? (totalSize !== void 0 && r.suffixLength !== null ? totalSize - Math.min(r.suffixLength, totalSize) : null), end: r.end ?? (totalSize !== void 0 ? totalSize - 1 : null) })).filter((r) => r.start !== null && r.end !== null).sort((a, b) => a.start - b.start);
2288
+ for (let i = 1; i < resolvable.length; i++) {
2289
+ if (resolvable[i].start <= resolvable[i - 1].end) {
2290
+ warnings.push(`ranges "${parsed[resolvable[i - 1].i].spec}" and "${parsed[resolvable[i].i].spec}" overlap - servers may reject overlapping multi-range requests`);
2291
+ }
2292
+ }
2293
+ if (parsed.length > 1 && parsed.some((r) => r.byteLength === null)) {
2294
+ warnings.push("totalSize was not provided, so open-ended ranges cannot be checked for overlap or total byte count");
2295
+ }
2296
+ const totalBytesRequested = parsed.every((r) => r.byteLength !== null) ? parsed.reduce((sum, r) => sum + (r.byteLength ?? 0), 0) : null;
2297
+ const headerValue = `${unit}=${parsed.map((r) => r.spec).join(",")}`;
2298
+ return {
2299
+ header: `Range: ${headerValue}`,
2300
+ headerValue,
2301
+ ranges: parsed,
2302
+ totalBytesRequested,
2303
+ warnings
2304
+ };
2305
+ }
2306
+ function parseContentRangeHeader(header) {
2307
+ if (!header || header.trim() === "") return { error: "Input is empty" };
2308
+ const match = header.trim().match(/^(\S+)\s+(\*|\d+-\d+)\/(\*|\d+)$/);
2309
+ if (!match) {
2310
+ return { error: 'Could not parse Content-Range header. Expected a format like "bytes 200-1000/67589" or "bytes */67589"' };
2311
+ }
2312
+ const [, unit, range, totalRaw] = match;
2313
+ const isUnsatisfiable = range === "*";
2314
+ const isTotalUnknown = totalRaw === "*";
2315
+ const total = isTotalUnknown ? null : Number(totalRaw);
2316
+ if (isUnsatisfiable) {
2317
+ return { unit, start: null, end: null, total, isUnsatisfiable, isTotalUnknown, byteLength: null };
2318
+ }
2319
+ const [startRaw, endRaw] = range.split("-");
2320
+ const start = Number(startRaw);
2321
+ const end = Number(endRaw);
2322
+ if (end < start) {
2323
+ return { error: `Invalid range: end (${end}) is before start (${start})` };
2324
+ }
2325
+ return { unit, start, end, total, isUnsatisfiable, isTotalUnknown, byteLength: end - start + 1 };
2326
+ }
2212
2327
 
2213
- export { DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, REFERRER_POLICY_VALUES, STATUS_CODES, analyzeEmailHeaders, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildReferrerPolicy, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, network_exports, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parseUserAgent, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateRobotsTxt, validateSitemap };
2328
+ export { DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, REFERRER_POLICY_VALUES, STATUS_CODES, analyzeEmailHeaders, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildRangeHeader, buildReferrerPolicy, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, network_exports, parseContentRangeHeader, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parseUserAgent, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateRobotsTxt, validateSitemap };
@@ -13,6 +13,7 @@ __export(data_exports, {
13
13
  diffEnvExample: () => diffEnvExample,
14
14
  envToExport: () => envToExport,
15
15
  envToJson: () => envToJson,
16
+ findCsvDuplicateRows: () => findCsvDuplicateRows,
16
17
  formatNdjson: () => formatNdjson,
17
18
  formatSubtitleTimestamp: () => formatSubtitleTimestamp,
18
19
  formatToml: () => formatToml,
@@ -1500,5 +1501,64 @@ function csvToSqlInsert(input, options) {
1500
1501
  columns
1501
1502
  };
1502
1503
  }
1504
+ function _normalizeDuplicateValue(value, caseSensitive, trimWhitespace) {
1505
+ let v = value;
1506
+ if (trimWhitespace) v = v.trim();
1507
+ if (!caseSensitive) v = v.toLowerCase();
1508
+ return v;
1509
+ }
1510
+ function findCsvDuplicateRows(input, options) {
1511
+ const parsed = parseCsv(input, {
1512
+ delimiter: options?.delimiter ?? ",",
1513
+ hasHeader: options?.hasHeader !== false,
1514
+ trimWhitespace: false
1515
+ });
1516
+ if ("error" in parsed) return parsed;
1517
+ if (parsed.rows.length === 0) return { error: "No data rows found" };
1518
+ const caseSensitive = options?.caseSensitive !== false;
1519
+ const trimWhitespace = options?.trimWhitespace !== false;
1520
+ let keyIndexes;
1521
+ if (options?.keyColumns && options.keyColumns.length > 0) {
1522
+ keyIndexes = [];
1523
+ for (const col of options.keyColumns) {
1524
+ const idx = parsed.headers.indexOf(col);
1525
+ if (idx === -1) {
1526
+ return { error: `Column "${col}" not found. Available columns: ${parsed.headers.join(", ")}` };
1527
+ }
1528
+ keyIndexes.push(idx);
1529
+ }
1530
+ } else {
1531
+ keyIndexes = parsed.headers.map((_, idx) => idx);
1532
+ }
1533
+ const groups = /* @__PURE__ */ new Map();
1534
+ parsed.rows.forEach((row, i) => {
1535
+ const key = keyIndexes.map((idx) => row[idx] ?? "");
1536
+ const normalizedKey = keyIndexes.map((idx) => _normalizeDuplicateValue(row[idx] ?? "", caseSensitive, trimWhitespace));
1537
+ const mapKey = JSON.stringify(normalizedKey);
1538
+ const rowNumber = i + 1;
1539
+ const existing = groups.get(mapKey);
1540
+ if (existing) {
1541
+ existing.rowNumbers.push(rowNumber);
1542
+ } else {
1543
+ groups.set(mapKey, { key, rowNumbers: [rowNumber] });
1544
+ }
1545
+ });
1546
+ const duplicateGroups = [];
1547
+ let duplicateRowCount = 0;
1548
+ for (const group of groups.values()) {
1549
+ if (group.rowNumbers.length > 1) {
1550
+ duplicateGroups.push({ key: group.key, rowNumbers: group.rowNumbers, count: group.rowNumbers.length });
1551
+ duplicateRowCount += group.rowNumbers.length;
1552
+ }
1553
+ }
1554
+ duplicateGroups.sort((a, b) => b.count - a.count);
1555
+ return {
1556
+ headers: parsed.headers,
1557
+ totalRows: parsed.rows.length,
1558
+ duplicateGroups,
1559
+ duplicateRowCount,
1560
+ uniqueRowCount: parsed.rows.length - duplicateRowCount + duplicateGroups.length
1561
+ };
1562
+ }
1503
1563
 
1504
- export { convertSubtitles, csvToJson, csvToSqlInsert, data_exports, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, generateMarkdownToc, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson };
1564
+ export { convertSubtitles, csvToJson, csvToSqlInsert, data_exports, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, findCsvDuplicateRows, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, generateMarkdownToc, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson };
@@ -16,6 +16,7 @@
16
16
  * - markdown-front-matter-parser: parseFrontMatter
17
17
  * - markdown-toc-generator: generateMarkdownToc
18
18
  * - csv-to-sql-insert-generator: csvToSqlInsert
19
+ * - csv-duplicate-row-finder: findCsvDuplicateRows
19
20
  */
20
21
  interface ValidationResult {
21
22
  valid: boolean;
@@ -343,8 +344,39 @@ interface CsvToSqlResult {
343
344
  declare function csvToSqlInsert(input: string, options?: CsvToSqlOptions): CsvToSqlResult | {
344
345
  error: string;
345
346
  };
347
+ interface CsvDuplicateOptions {
348
+ delimiter?: string;
349
+ hasHeader?: boolean;
350
+ keyColumns?: string[];
351
+ caseSensitive?: boolean;
352
+ trimWhitespace?: boolean;
353
+ }
354
+ interface CsvDuplicateGroup {
355
+ key: string[];
356
+ rowNumbers: number[];
357
+ count: number;
358
+ }
359
+ interface CsvDuplicateResult {
360
+ headers: string[];
361
+ totalRows: number;
362
+ duplicateGroups: CsvDuplicateGroup[];
363
+ duplicateRowCount: number;
364
+ uniqueRowCount: number;
365
+ }
366
+ /**
367
+ * Parse CSV/TSV data and group rows that share the same value across a
368
+ * chosen set of key columns (or the entire row, if no key columns are
369
+ * given), so you can spot and clean up accidental duplicates before an
370
+ * import.
371
+ */
372
+ declare function findCsvDuplicateRows(input: string, options?: CsvDuplicateOptions): CsvDuplicateResult | {
373
+ error: string;
374
+ };
346
375
 
347
376
  type data_ConvertedSubtitles = ConvertedSubtitles;
377
+ type data_CsvDuplicateGroup = CsvDuplicateGroup;
378
+ type data_CsvDuplicateOptions = CsvDuplicateOptions;
379
+ type data_CsvDuplicateResult = CsvDuplicateResult;
348
380
  type data_CsvParseResult = CsvParseResult;
349
381
  type data_CsvToSqlOptions = CsvToSqlOptions;
350
382
  type data_CsvToSqlResult = CsvToSqlResult;
@@ -377,6 +409,7 @@ declare const data_detectSubtitleFormat: typeof detectSubtitleFormat;
377
409
  declare const data_diffEnvExample: typeof diffEnvExample;
378
410
  declare const data_envToExport: typeof envToExport;
379
411
  declare const data_envToJson: typeof envToJson;
412
+ declare const data_findCsvDuplicateRows: typeof findCsvDuplicateRows;
380
413
  declare const data_formatNdjson: typeof formatNdjson;
381
414
  declare const data_formatSubtitleTimestamp: typeof formatSubtitleTimestamp;
382
415
  declare const data_formatToml: typeof formatToml;
@@ -416,7 +449,7 @@ declare const data_validateXml: typeof validateXml;
416
449
  declare const data_validateYaml: typeof validateYaml;
417
450
  declare const data_xmlToJson: typeof xmlToJson;
418
451
  declare namespace data {
419
- export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvParseResult as CsvParseResult, type data_CsvToSqlOptions as CsvToSqlOptions, type data_CsvToSqlResult as CsvToSqlResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_FrontMatterError as FrontMatterError, type data_FrontMatterResult as FrontMatterResult, type data_IniSection as IniSection, type data_MarkdownTocEntry as MarkdownTocEntry, type data_MarkdownTocOptions as MarkdownTocOptions, type data_MarkdownTocResult as MarkdownTocResult, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_csvToSqlInsert as csvToSqlInsert, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_generateMarkdownToc as generateMarkdownToc, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseFrontMatter as parseFrontMatter, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
452
+ export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvDuplicateGroup as CsvDuplicateGroup, type data_CsvDuplicateOptions as CsvDuplicateOptions, type data_CsvDuplicateResult as CsvDuplicateResult, type data_CsvParseResult as CsvParseResult, type data_CsvToSqlOptions as CsvToSqlOptions, type data_CsvToSqlResult as CsvToSqlResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_FrontMatterError as FrontMatterError, type data_FrontMatterResult as FrontMatterResult, type data_IniSection as IniSection, type data_MarkdownTocEntry as MarkdownTocEntry, type data_MarkdownTocOptions as MarkdownTocOptions, type data_MarkdownTocResult as MarkdownTocResult, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_csvToSqlInsert as csvToSqlInsert, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_findCsvDuplicateRows as findCsvDuplicateRows, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_generateMarkdownToc as generateMarkdownToc, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseFrontMatter as parseFrontMatter, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
420
453
  }
421
454
 
422
- export { parseCsv as $, formatXml as A, generateMarkdownToc as B, type ConvertedSubtitles as C, getSection as D, type EnvDiffError as E, type FrontMatterError as F, getSectionNames as G, getTomlStats as H, type IniSection as I, getXmlStats as J, getYamlStats as K, iniToJson as L, type MarkdownTocEntry as M, type NdjsonLineResult as N, jsonArrayToNdjson as O, type ParseOptions as P, jsonToIni as Q, jsonToToml as R, type SubtitleCue as S, type TomlFormatResult as T, jsonToXml as U, type ValidationResult as V, minifyNdjson as W, type XmlFormatResult as X, minifyToml as Y, minifyXml as Z, ndjsonToJsonArray as _, type CsvParseResult as a, parseEnv as a0, parseFrontMatter as a1, parseIni as a2, parseSubtitleTimestamp as a3, parseSubtitles as a4, parseXmlToObject as a5, serializeSubtitles as a6, shiftSubtitles as a7, stringifyIni as a8, toCsvString as a9, tomlToJson as aa, validateEnvKey as ab, validateIni as ac, validateNdjson as ad, validateToml as ae, validateXml as af, validateYaml as ag, xmlToJson as ah, type CsvToSqlOptions as b, type CsvToSqlResult as c, data as d, type EnvDiffResult as e, type EnvEntry as f, type EnvParseResult as g, type FrontMatterResult as h, type MarkdownTocOptions as i, type MarkdownTocResult as j, type NdjsonValidateResult as k, type ParsedIni as l, type ParsedSubtitles as m, type SubtitleFormat as n, type XmlToJsonOptions as o, convertSubtitles as p, csvToJson as q, csvToSqlInsert as r, detectDelimiter as s, detectSubtitleFormat as t, diffEnvExample as u, envToExport as v, envToJson as w, formatNdjson as x, formatSubtitleTimestamp as y, formatToml as z };
455
+ export { minifyNdjson as $, findCsvDuplicateRows as A, formatNdjson as B, type ConvertedSubtitles as C, formatSubtitleTimestamp as D, type EnvDiffError as E, type FrontMatterError as F, formatToml as G, formatXml as H, type IniSection as I, generateMarkdownToc as J, getSection as K, getSectionNames as L, type MarkdownTocEntry as M, type NdjsonLineResult as N, getTomlStats as O, type ParseOptions as P, getXmlStats as Q, getYamlStats as R, type SubtitleCue as S, type TomlFormatResult as T, iniToJson as U, type ValidationResult as V, jsonArrayToNdjson as W, type XmlFormatResult as X, jsonToIni as Y, jsonToToml as Z, jsonToXml as _, type CsvDuplicateGroup as a, minifyToml as a0, minifyXml as a1, ndjsonToJsonArray as a2, parseCsv as a3, parseEnv as a4, parseFrontMatter as a5, parseIni as a6, parseSubtitleTimestamp as a7, parseSubtitles as a8, parseXmlToObject as a9, serializeSubtitles as aa, shiftSubtitles as ab, stringifyIni as ac, toCsvString as ad, tomlToJson as ae, validateEnvKey as af, validateIni as ag, validateNdjson as ah, validateToml as ai, validateXml as aj, validateYaml as ak, xmlToJson as al, type CsvDuplicateOptions as b, type CsvDuplicateResult as c, data as d, type CsvParseResult as e, type CsvToSqlOptions as f, type CsvToSqlResult as g, type EnvDiffResult as h, type EnvEntry as i, type EnvParseResult as j, type FrontMatterResult as k, type MarkdownTocOptions as l, type MarkdownTocResult as m, type NdjsonValidateResult as n, type ParsedIni as o, type ParsedSubtitles as p, type SubtitleFormat as q, type XmlToJsonOptions as r, convertSubtitles as s, csvToJson as t, csvToSqlInsert as u, detectDelimiter as v, detectSubtitleFormat as w, diffEnvExample as x, envToExport as y, envToJson as z };
@@ -16,6 +16,7 @@
16
16
  * - markdown-front-matter-parser: parseFrontMatter
17
17
  * - markdown-toc-generator: generateMarkdownToc
18
18
  * - csv-to-sql-insert-generator: csvToSqlInsert
19
+ * - csv-duplicate-row-finder: findCsvDuplicateRows
19
20
  */
20
21
  interface ValidationResult {
21
22
  valid: boolean;
@@ -343,8 +344,39 @@ interface CsvToSqlResult {
343
344
  declare function csvToSqlInsert(input: string, options?: CsvToSqlOptions): CsvToSqlResult | {
344
345
  error: string;
345
346
  };
347
+ interface CsvDuplicateOptions {
348
+ delimiter?: string;
349
+ hasHeader?: boolean;
350
+ keyColumns?: string[];
351
+ caseSensitive?: boolean;
352
+ trimWhitespace?: boolean;
353
+ }
354
+ interface CsvDuplicateGroup {
355
+ key: string[];
356
+ rowNumbers: number[];
357
+ count: number;
358
+ }
359
+ interface CsvDuplicateResult {
360
+ headers: string[];
361
+ totalRows: number;
362
+ duplicateGroups: CsvDuplicateGroup[];
363
+ duplicateRowCount: number;
364
+ uniqueRowCount: number;
365
+ }
366
+ /**
367
+ * Parse CSV/TSV data and group rows that share the same value across a
368
+ * chosen set of key columns (or the entire row, if no key columns are
369
+ * given), so you can spot and clean up accidental duplicates before an
370
+ * import.
371
+ */
372
+ declare function findCsvDuplicateRows(input: string, options?: CsvDuplicateOptions): CsvDuplicateResult | {
373
+ error: string;
374
+ };
346
375
 
347
376
  type data_ConvertedSubtitles = ConvertedSubtitles;
377
+ type data_CsvDuplicateGroup = CsvDuplicateGroup;
378
+ type data_CsvDuplicateOptions = CsvDuplicateOptions;
379
+ type data_CsvDuplicateResult = CsvDuplicateResult;
348
380
  type data_CsvParseResult = CsvParseResult;
349
381
  type data_CsvToSqlOptions = CsvToSqlOptions;
350
382
  type data_CsvToSqlResult = CsvToSqlResult;
@@ -377,6 +409,7 @@ declare const data_detectSubtitleFormat: typeof detectSubtitleFormat;
377
409
  declare const data_diffEnvExample: typeof diffEnvExample;
378
410
  declare const data_envToExport: typeof envToExport;
379
411
  declare const data_envToJson: typeof envToJson;
412
+ declare const data_findCsvDuplicateRows: typeof findCsvDuplicateRows;
380
413
  declare const data_formatNdjson: typeof formatNdjson;
381
414
  declare const data_formatSubtitleTimestamp: typeof formatSubtitleTimestamp;
382
415
  declare const data_formatToml: typeof formatToml;
@@ -416,7 +449,7 @@ declare const data_validateXml: typeof validateXml;
416
449
  declare const data_validateYaml: typeof validateYaml;
417
450
  declare const data_xmlToJson: typeof xmlToJson;
418
451
  declare namespace data {
419
- export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvParseResult as CsvParseResult, type data_CsvToSqlOptions as CsvToSqlOptions, type data_CsvToSqlResult as CsvToSqlResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_FrontMatterError as FrontMatterError, type data_FrontMatterResult as FrontMatterResult, type data_IniSection as IniSection, type data_MarkdownTocEntry as MarkdownTocEntry, type data_MarkdownTocOptions as MarkdownTocOptions, type data_MarkdownTocResult as MarkdownTocResult, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_csvToSqlInsert as csvToSqlInsert, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_generateMarkdownToc as generateMarkdownToc, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseFrontMatter as parseFrontMatter, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
452
+ export { type data_ConvertedSubtitles as ConvertedSubtitles, type data_CsvDuplicateGroup as CsvDuplicateGroup, type data_CsvDuplicateOptions as CsvDuplicateOptions, type data_CsvDuplicateResult as CsvDuplicateResult, type data_CsvParseResult as CsvParseResult, type data_CsvToSqlOptions as CsvToSqlOptions, type data_CsvToSqlResult as CsvToSqlResult, type data_EnvDiffError as EnvDiffError, type data_EnvDiffResult as EnvDiffResult, type data_EnvEntry as EnvEntry, type data_EnvParseResult as EnvParseResult, type data_FrontMatterError as FrontMatterError, type data_FrontMatterResult as FrontMatterResult, type data_IniSection as IniSection, type data_MarkdownTocEntry as MarkdownTocEntry, type data_MarkdownTocOptions as MarkdownTocOptions, type data_MarkdownTocResult as MarkdownTocResult, type data_NdjsonLineResult as NdjsonLineResult, type data_NdjsonValidateResult as NdjsonValidateResult, type data_ParseOptions as ParseOptions, type data_ParsedIni as ParsedIni, type data_ParsedSubtitles as ParsedSubtitles, type data_SubtitleCue as SubtitleCue, type data_SubtitleFormat as SubtitleFormat, type data_TomlFormatResult as TomlFormatResult, type data_ValidationResult as ValidationResult, type data_XmlFormatResult as XmlFormatResult, type data_XmlToJsonOptions as XmlToJsonOptions, data_convertSubtitles as convertSubtitles, data_csvToJson as csvToJson, data_csvToSqlInsert as csvToSqlInsert, data_detectDelimiter as detectDelimiter, data_detectSubtitleFormat as detectSubtitleFormat, data_diffEnvExample as diffEnvExample, data_envToExport as envToExport, data_envToJson as envToJson, data_findCsvDuplicateRows as findCsvDuplicateRows, data_formatNdjson as formatNdjson, data_formatSubtitleTimestamp as formatSubtitleTimestamp, data_formatToml as formatToml, data_formatXml as formatXml, data_generateMarkdownToc as generateMarkdownToc, data_getSection as getSection, data_getSectionNames as getSectionNames, data_getTomlStats as getTomlStats, data_getXmlStats as getXmlStats, data_getYamlStats as getYamlStats, data_iniToJson as iniToJson, data_jsonArrayToNdjson as jsonArrayToNdjson, data_jsonToIni as jsonToIni, data_jsonToToml as jsonToToml, data_jsonToXml as jsonToXml, data_minifyNdjson as minifyNdjson, data_minifyToml as minifyToml, data_minifyXml as minifyXml, data_ndjsonToJsonArray as ndjsonToJsonArray, data_parseCsv as parseCsv, data_parseEnv as parseEnv, data_parseFrontMatter as parseFrontMatter, data_parseIni as parseIni, data_parseSubtitleTimestamp as parseSubtitleTimestamp, data_parseSubtitles as parseSubtitles, data_parseXmlToObject as parseXmlToObject, data_serializeSubtitles as serializeSubtitles, data_shiftSubtitles as shiftSubtitles, data_stringifyIni as stringifyIni, data_toCsvString as toCsvString, data_tomlToJson as tomlToJson, data_validateEnvKey as validateEnvKey, data_validateIni as validateIni, data_validateNdjson as validateNdjson, data_validateToml as validateToml, data_validateXml as validateXml, data_validateYaml as validateYaml, data_xmlToJson as xmlToJson };
420
453
  }
421
454
 
422
- export { parseCsv as $, formatXml as A, generateMarkdownToc as B, type ConvertedSubtitles as C, getSection as D, type EnvDiffError as E, type FrontMatterError as F, getSectionNames as G, getTomlStats as H, type IniSection as I, getXmlStats as J, getYamlStats as K, iniToJson as L, type MarkdownTocEntry as M, type NdjsonLineResult as N, jsonArrayToNdjson as O, type ParseOptions as P, jsonToIni as Q, jsonToToml as R, type SubtitleCue as S, type TomlFormatResult as T, jsonToXml as U, type ValidationResult as V, minifyNdjson as W, type XmlFormatResult as X, minifyToml as Y, minifyXml as Z, ndjsonToJsonArray as _, type CsvParseResult as a, parseEnv as a0, parseFrontMatter as a1, parseIni as a2, parseSubtitleTimestamp as a3, parseSubtitles as a4, parseXmlToObject as a5, serializeSubtitles as a6, shiftSubtitles as a7, stringifyIni as a8, toCsvString as a9, tomlToJson as aa, validateEnvKey as ab, validateIni as ac, validateNdjson as ad, validateToml as ae, validateXml as af, validateYaml as ag, xmlToJson as ah, type CsvToSqlOptions as b, type CsvToSqlResult as c, data as d, type EnvDiffResult as e, type EnvEntry as f, type EnvParseResult as g, type FrontMatterResult as h, type MarkdownTocOptions as i, type MarkdownTocResult as j, type NdjsonValidateResult as k, type ParsedIni as l, type ParsedSubtitles as m, type SubtitleFormat as n, type XmlToJsonOptions as o, convertSubtitles as p, csvToJson as q, csvToSqlInsert as r, detectDelimiter as s, detectSubtitleFormat as t, diffEnvExample as u, envToExport as v, envToJson as w, formatNdjson as x, formatSubtitleTimestamp as y, formatToml as z };
455
+ export { minifyNdjson as $, findCsvDuplicateRows as A, formatNdjson as B, type ConvertedSubtitles as C, formatSubtitleTimestamp as D, type EnvDiffError as E, type FrontMatterError as F, formatToml as G, formatXml as H, type IniSection as I, generateMarkdownToc as J, getSection as K, getSectionNames as L, type MarkdownTocEntry as M, type NdjsonLineResult as N, getTomlStats as O, type ParseOptions as P, getXmlStats as Q, getYamlStats as R, type SubtitleCue as S, type TomlFormatResult as T, iniToJson as U, type ValidationResult as V, jsonArrayToNdjson as W, type XmlFormatResult as X, jsonToIni as Y, jsonToToml as Z, jsonToXml as _, type CsvDuplicateGroup as a, minifyToml as a0, minifyXml as a1, ndjsonToJsonArray as a2, parseCsv as a3, parseEnv as a4, parseFrontMatter as a5, parseIni as a6, parseSubtitleTimestamp as a7, parseSubtitles as a8, parseXmlToObject as a9, serializeSubtitles as aa, shiftSubtitles as ab, stringifyIni as ac, toCsvString as ad, tomlToJson as ae, validateEnvKey as af, validateIni as ag, validateNdjson as ah, validateToml as ai, validateXml as aj, validateYaml as ak, xmlToJson as al, type CsvDuplicateOptions as b, type CsvDuplicateResult as c, data as d, type CsvParseResult as e, type CsvToSqlOptions as f, type CsvToSqlResult as g, type EnvDiffResult as h, type EnvEntry as i, type EnvParseResult as j, type FrontMatterResult as k, type MarkdownTocOptions as l, type MarkdownTocResult as m, type NdjsonValidateResult as n, type ParsedIni as o, type ParsedSubtitles as p, type SubtitleFormat as q, type XmlToJsonOptions as r, convertSubtitles as s, csvToJson as t, csvToSqlInsert as u, detectDelimiter as v, detectSubtitleFormat as w, diffEnvExample as x, envToExport as y, envToJson as z };
package/dist/index.cjs CHANGED
@@ -5033,6 +5033,7 @@ __export(data_exports, {
5033
5033
  diffEnvExample: () => diffEnvExample,
5034
5034
  envToExport: () => envToExport,
5035
5035
  envToJson: () => envToJson,
5036
+ findCsvDuplicateRows: () => findCsvDuplicateRows,
5036
5037
  formatNdjson: () => formatNdjson,
5037
5038
  formatSubtitleTimestamp: () => formatSubtitleTimestamp,
5038
5039
  formatToml: () => formatToml,
@@ -6520,6 +6521,65 @@ function csvToSqlInsert(input, options) {
6520
6521
  columns
6521
6522
  };
6522
6523
  }
6524
+ function _normalizeDuplicateValue(value, caseSensitive, trimWhitespace) {
6525
+ let v = value;
6526
+ if (trimWhitespace) v = v.trim();
6527
+ if (!caseSensitive) v = v.toLowerCase();
6528
+ return v;
6529
+ }
6530
+ function findCsvDuplicateRows(input, options) {
6531
+ const parsed = parseCsv(input, {
6532
+ delimiter: options?.delimiter ?? ",",
6533
+ hasHeader: options?.hasHeader !== false,
6534
+ trimWhitespace: false
6535
+ });
6536
+ if ("error" in parsed) return parsed;
6537
+ if (parsed.rows.length === 0) return { error: "No data rows found" };
6538
+ const caseSensitive = options?.caseSensitive !== false;
6539
+ const trimWhitespace = options?.trimWhitespace !== false;
6540
+ let keyIndexes;
6541
+ if (options?.keyColumns && options.keyColumns.length > 0) {
6542
+ keyIndexes = [];
6543
+ for (const col of options.keyColumns) {
6544
+ const idx = parsed.headers.indexOf(col);
6545
+ if (idx === -1) {
6546
+ return { error: `Column "${col}" not found. Available columns: ${parsed.headers.join(", ")}` };
6547
+ }
6548
+ keyIndexes.push(idx);
6549
+ }
6550
+ } else {
6551
+ keyIndexes = parsed.headers.map((_, idx) => idx);
6552
+ }
6553
+ const groups = /* @__PURE__ */ new Map();
6554
+ parsed.rows.forEach((row, i) => {
6555
+ const key = keyIndexes.map((idx) => row[idx] ?? "");
6556
+ const normalizedKey = keyIndexes.map((idx) => _normalizeDuplicateValue(row[idx] ?? "", caseSensitive, trimWhitespace));
6557
+ const mapKey = JSON.stringify(normalizedKey);
6558
+ const rowNumber = i + 1;
6559
+ const existing = groups.get(mapKey);
6560
+ if (existing) {
6561
+ existing.rowNumbers.push(rowNumber);
6562
+ } else {
6563
+ groups.set(mapKey, { key, rowNumbers: [rowNumber] });
6564
+ }
6565
+ });
6566
+ const duplicateGroups = [];
6567
+ let duplicateRowCount = 0;
6568
+ for (const group of groups.values()) {
6569
+ if (group.rowNumbers.length > 1) {
6570
+ duplicateGroups.push({ key: group.key, rowNumbers: group.rowNumbers, count: group.rowNumbers.length });
6571
+ duplicateRowCount += group.rowNumbers.length;
6572
+ }
6573
+ }
6574
+ duplicateGroups.sort((a, b) => b.count - a.count);
6575
+ return {
6576
+ headers: parsed.headers,
6577
+ totalRows: parsed.rows.length,
6578
+ duplicateGroups,
6579
+ duplicateRowCount,
6580
+ uniqueRowCount: parsed.rows.length - duplicateRowCount + duplicateGroups.length
6581
+ };
6582
+ }
6523
6583
 
6524
6584
  // src/tools/generators.ts
6525
6585
  var generators_exports = {};
@@ -9860,6 +9920,7 @@ __export(network_exports, {
9860
9920
  buildGeoUrl: () => buildGeoUrl,
9861
9921
  buildLinkHeader: () => buildLinkHeader,
9862
9922
  buildMapUrl: () => buildMapUrl,
9923
+ buildRangeHeader: () => buildRangeHeader,
9863
9924
  buildReferrerPolicy: () => buildReferrerPolicy,
9864
9925
  checkSetCookieHeader: () => checkSetCookieHeader,
9865
9926
  countryCodeToFlag: () => countryCodeToFlag,
@@ -9876,6 +9937,7 @@ __export(network_exports, {
9876
9937
  isValidIp: () => isValidIp2,
9877
9938
  isValidIpv4: () => isValidIpv42,
9878
9939
  isValidIpv6: () => isValidIpv6,
9940
+ parseContentRangeHeader: () => parseContentRangeHeader,
9879
9941
  parseDnsResponse: () => parseDnsResponse,
9880
9942
  parseGeoResponse: () => parseGeoResponse,
9881
9943
  parseHar: () => parseHar,
@@ -12055,6 +12117,119 @@ function analyzeEmailHeaders(raw) {
12055
12117
  warnings
12056
12118
  };
12057
12119
  }
12120
+ function _round2(n) {
12121
+ return Math.round(n * 100) / 100;
12122
+ }
12123
+ function buildRangeHeader(entries, options) {
12124
+ if (!Array.isArray(entries) || entries.length === 0) {
12125
+ return { error: "At least one range is required" };
12126
+ }
12127
+ const unit = options?.unit?.trim() || "bytes";
12128
+ const totalSize = typeof options?.totalSize === "number" && Number.isFinite(options.totalSize) ? options.totalSize : void 0;
12129
+ if (totalSize !== void 0 && totalSize <= 0) {
12130
+ return { error: "totalSize must be a positive number when provided" };
12131
+ }
12132
+ const parsed = [];
12133
+ for (const entry of entries) {
12134
+ if (entry.suffixLength !== void 0) {
12135
+ if (!Number.isFinite(entry.suffixLength) || entry.suffixLength <= 0) {
12136
+ return { error: "suffixLength must be a positive number" };
12137
+ }
12138
+ const suffixLength = Math.floor(entry.suffixLength);
12139
+ const byteLength = totalSize !== void 0 ? Math.min(suffixLength, totalSize) : suffixLength;
12140
+ parsed.push({
12141
+ spec: `-${suffixLength}`,
12142
+ start: null,
12143
+ end: null,
12144
+ suffixLength,
12145
+ byteLength,
12146
+ percentOfTotal: totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
12147
+ });
12148
+ continue;
12149
+ }
12150
+ if (entry.start === void 0) {
12151
+ return { error: "Each range requires either a start byte or a suffixLength" };
12152
+ }
12153
+ if (!Number.isFinite(entry.start) || entry.start < 0) {
12154
+ return { error: "start must be a non-negative number" };
12155
+ }
12156
+ const start = Math.floor(entry.start);
12157
+ if (totalSize !== void 0 && start >= totalSize) {
12158
+ return { error: `start byte ${start} is beyond totalSize (${totalSize})` };
12159
+ }
12160
+ if (entry.end !== void 0) {
12161
+ if (!Number.isFinite(entry.end) || entry.end < 0) {
12162
+ return { error: "end must be a non-negative number" };
12163
+ }
12164
+ const end = Math.floor(entry.end);
12165
+ if (end < start) {
12166
+ return { error: `range end (${end}) must be >= start (${start})` };
12167
+ }
12168
+ if (totalSize !== void 0 && end >= totalSize) {
12169
+ return { error: `end byte ${end} is beyond totalSize (${totalSize})` };
12170
+ }
12171
+ const byteLength = end - start + 1;
12172
+ parsed.push({
12173
+ spec: `${start}-${end}`,
12174
+ start,
12175
+ end,
12176
+ suffixLength: null,
12177
+ byteLength,
12178
+ percentOfTotal: totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
12179
+ });
12180
+ } else {
12181
+ const byteLength = totalSize !== void 0 ? totalSize - start : null;
12182
+ parsed.push({
12183
+ spec: `${start}-`,
12184
+ start,
12185
+ end: null,
12186
+ suffixLength: null,
12187
+ byteLength,
12188
+ percentOfTotal: byteLength !== null && totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
12189
+ });
12190
+ }
12191
+ }
12192
+ const warnings = [];
12193
+ const resolvable = parsed.map((r, i) => ({ i, start: r.start ?? (totalSize !== void 0 && r.suffixLength !== null ? totalSize - Math.min(r.suffixLength, totalSize) : null), end: r.end ?? (totalSize !== void 0 ? totalSize - 1 : null) })).filter((r) => r.start !== null && r.end !== null).sort((a, b) => a.start - b.start);
12194
+ for (let i = 1; i < resolvable.length; i++) {
12195
+ if (resolvable[i].start <= resolvable[i - 1].end) {
12196
+ warnings.push(`ranges "${parsed[resolvable[i - 1].i].spec}" and "${parsed[resolvable[i].i].spec}" overlap - servers may reject overlapping multi-range requests`);
12197
+ }
12198
+ }
12199
+ if (parsed.length > 1 && parsed.some((r) => r.byteLength === null)) {
12200
+ warnings.push("totalSize was not provided, so open-ended ranges cannot be checked for overlap or total byte count");
12201
+ }
12202
+ const totalBytesRequested = parsed.every((r) => r.byteLength !== null) ? parsed.reduce((sum, r) => sum + (r.byteLength ?? 0), 0) : null;
12203
+ const headerValue = `${unit}=${parsed.map((r) => r.spec).join(",")}`;
12204
+ return {
12205
+ header: `Range: ${headerValue}`,
12206
+ headerValue,
12207
+ ranges: parsed,
12208
+ totalBytesRequested,
12209
+ warnings
12210
+ };
12211
+ }
12212
+ function parseContentRangeHeader(header) {
12213
+ if (!header || header.trim() === "") return { error: "Input is empty" };
12214
+ const match = header.trim().match(/^(\S+)\s+(\*|\d+-\d+)\/(\*|\d+)$/);
12215
+ if (!match) {
12216
+ return { error: 'Could not parse Content-Range header. Expected a format like "bytes 200-1000/67589" or "bytes */67589"' };
12217
+ }
12218
+ const [, unit, range, totalRaw] = match;
12219
+ const isUnsatisfiable = range === "*";
12220
+ const isTotalUnknown = totalRaw === "*";
12221
+ const total = isTotalUnknown ? null : Number(totalRaw);
12222
+ if (isUnsatisfiable) {
12223
+ return { unit, start: null, end: null, total, isUnsatisfiable, isTotalUnknown, byteLength: null };
12224
+ }
12225
+ const [startRaw, endRaw] = range.split("-");
12226
+ const start = Number(startRaw);
12227
+ const end = Number(endRaw);
12228
+ if (end < start) {
12229
+ return { error: `Invalid range: end (${end}) is before start (${start})` };
12230
+ }
12231
+ return { unit, start, end, total, isUnsatisfiable, isTotalUnknown, byteLength: end - start + 1 };
12232
+ }
12058
12233
 
12059
12234
  // src/tools/api.ts
12060
12235
  var api_exports = {};
package/dist/index.d.cts CHANGED
@@ -2,11 +2,11 @@ export { j as json } from './json-Ta9JykSB.cjs';
2
2
  export { e as encoding } from './encoding-Dk3wpmb3.cjs';
3
3
  export { h as hashing } from './hashing-CJjlvqS_.cjs';
4
4
  export { t as text } from './text-kHkT9VtT.cjs';
5
- export { d as data } from './data-BCf3dm-E.cjs';
5
+ export { d as data } from './data-BKpEOcOX.cjs';
6
6
  export { g as generators } from './generators-Du8cBesn.cjs';
7
7
  export { t as time } from './time-KqJjdqII.cjs';
8
8
  export { u as units } from './units-CzPwRC03.cjs';
9
- export { n as network } from './network-CKPoesdD.cjs';
9
+ export { n as network } from './network-BC8McQOh.cjs';
10
10
  export { a as api } from './api-DmTNE4c1.cjs';
11
11
  export { c as code } from './code-KXoRsHtl.cjs';
12
12
  export { c as color } from './color-tPwZCr9H.cjs';
package/dist/index.d.ts CHANGED
@@ -2,11 +2,11 @@ export { j as json } from './json-Ta9JykSB.js';
2
2
  export { e as encoding } from './encoding-Dk3wpmb3.js';
3
3
  export { h as hashing } from './hashing-CJjlvqS_.js';
4
4
  export { t as text } from './text-kHkT9VtT.js';
5
- export { d as data } from './data-BCf3dm-E.js';
5
+ export { d as data } from './data-BKpEOcOX.js';
6
6
  export { g as generators } from './generators-Du8cBesn.js';
7
7
  export { t as time } from './time-KqJjdqII.js';
8
8
  export { u as units } from './units-CzPwRC03.js';
9
- export { n as network } from './network-CKPoesdD.js';
9
+ export { n as network } from './network-BC8McQOh.js';
10
10
  export { a as api } from './api-DmTNE4c1.js';
11
11
  export { c as code } from './code-KXoRsHtl.js';
12
12
  export { c as color } from './color-tPwZCr9H.js';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { media_exports as media } from './chunk-L6V4W4SU.js';
2
2
  export { units_exports as units } from './chunk-2MTHD2LG.js';
3
- export { network_exports as network } from './chunk-Y4BVU76A.js';
3
+ export { network_exports as network } from './chunk-7WSFJTYP.js';
4
4
  export { api_exports as api } from './chunk-52ZDKSIX.js';
5
5
  export { code_exports as code } from './chunk-JL7YTXRB.js';
6
6
  export { color_exports as color } from './chunk-BPVAB4P2.js';
@@ -11,7 +11,7 @@ export { json_exports as json } from './chunk-WVEKRKGU.js';
11
11
  export { encoding_exports as encoding } from './chunk-DOWQZUTP.js';
12
12
  export { hashing_exports as hashing } from './chunk-PET2CGTH.js';
13
13
  export { text_exports as text } from './chunk-F2CEN226.js';
14
- export { data_exports as data } from './chunk-RZUNTYEH.js';
14
+ export { data_exports as data } from './chunk-JR354NH4.js';
15
15
  export { generators_exports as generators } from './chunk-3TYWIX3B.js';
16
16
  export { time_exports as time } from './chunk-IEPWZERQ.js';
17
17
  import './chunk-MLKGABMK.js';
@@ -17,6 +17,7 @@
17
17
  * - link-header-builder: buildLinkHeader
18
18
  * - same-site-cookie-checker: checkSetCookieHeader
19
19
  * - email-header-analyzer: analyzeEmailHeaders
20
+ * - http-range-header-builder: buildRangeHeader, parseContentRangeHeader
20
21
  */
21
22
  declare const DNS_RECORD_TYPES: readonly ["A", "AAAA", "CNAME", "MX", "TXT", "NS", "SOA", "PTR", "SRV", "CAA"];
22
23
  type DnsRecordType = typeof DNS_RECORD_TYPES[number];
@@ -447,11 +448,63 @@ interface EmailHeaderAnalysis {
447
448
  declare function analyzeEmailHeaders(raw: string): EmailHeaderAnalysis | {
448
449
  error: string;
449
450
  };
451
+ interface RangeEntryInput {
452
+ start?: number;
453
+ end?: number;
454
+ suffixLength?: number;
455
+ }
456
+ interface RangeEntry {
457
+ spec: string;
458
+ start: number | null;
459
+ end: number | null;
460
+ suffixLength: number | null;
461
+ byteLength: number | null;
462
+ percentOfTotal: number | null;
463
+ }
464
+ interface RangeHeaderResult {
465
+ header: string;
466
+ headerValue: string;
467
+ ranges: RangeEntry[];
468
+ totalBytesRequested: number | null;
469
+ warnings: string[];
470
+ }
471
+ interface BuildRangeHeaderOptions {
472
+ totalSize?: number;
473
+ unit?: string;
474
+ }
475
+ /**
476
+ * Build an HTTP `Range` request header from a list of byte ranges. Each
477
+ * entry is either `{ start, end? }` (an explicit or open-ended range) or
478
+ * `{ suffixLength }` (the last N bytes). Pass `totalSize` to resolve
479
+ * open-ended/suffix byte lengths and get overlap warnings.
480
+ */
481
+ declare function buildRangeHeader(entries: RangeEntryInput[], options?: BuildRangeHeaderOptions): RangeHeaderResult | {
482
+ error: string;
483
+ };
484
+ interface ContentRangeResult {
485
+ unit: string;
486
+ start: number | null;
487
+ end: number | null;
488
+ total: number | null;
489
+ isUnsatisfiable: boolean;
490
+ isTotalUnknown: boolean;
491
+ byteLength: number | null;
492
+ }
493
+ /**
494
+ * Parse a `Content-Range` response header (e.g. `bytes 200-1000/67589` or
495
+ * `bytes *\/67589` for an unsatisfiable range) into its unit, byte bounds,
496
+ * and total resource size.
497
+ */
498
+ declare function parseContentRangeHeader(header: string): ContentRangeResult | {
499
+ error: string;
500
+ };
450
501
 
451
502
  type network_AuthResultEntry = AuthResultEntry;
503
+ type network_BuildRangeHeaderOptions = BuildRangeHeaderOptions;
452
504
  type network_CacheControlDirective = CacheControlDirective;
453
505
  type network_CacheControlOptions = CacheControlOptions;
454
506
  type network_CacheControlResult = CacheControlResult;
507
+ type network_ContentRangeResult = ContentRangeResult;
455
508
  type network_CookieAttributes = CookieAttributes;
456
509
  type network_CookieCheckResult = CookieCheckResult;
457
510
  declare const network_DNS_RECORD_TYPES: typeof DNS_RECORD_TYPES;
@@ -477,6 +530,9 @@ type network_LinkRel = LinkRel;
477
530
  type network_ParsedDnsResult = ParsedDnsResult;
478
531
  type network_ParsedGeoResult = ParsedGeoResult;
479
532
  declare const network_REFERRER_POLICY_VALUES: typeof REFERRER_POLICY_VALUES;
533
+ type network_RangeEntry = RangeEntry;
534
+ type network_RangeEntryInput = RangeEntryInput;
535
+ type network_RangeHeaderResult = RangeHeaderResult;
480
536
  type network_ReceivedHop = ReceivedHop;
481
537
  type network_ReferrerPolicyEntry = ReferrerPolicyEntry;
482
538
  type network_ReferrerPolicyResult = ReferrerPolicyResult;
@@ -500,6 +556,7 @@ declare const network_buildDnsQueryUrl: typeof buildDnsQueryUrl;
500
556
  declare const network_buildGeoUrl: typeof buildGeoUrl;
501
557
  declare const network_buildLinkHeader: typeof buildLinkHeader;
502
558
  declare const network_buildMapUrl: typeof buildMapUrl;
559
+ declare const network_buildRangeHeader: typeof buildRangeHeader;
503
560
  declare const network_buildReferrerPolicy: typeof buildReferrerPolicy;
504
561
  declare const network_checkSetCookieHeader: typeof checkSetCookieHeader;
505
562
  declare const network_countryCodeToFlag: typeof countryCodeToFlag;
@@ -516,6 +573,7 @@ declare const network_isSuccess: typeof isSuccess;
516
573
  declare const network_isValidIp: typeof isValidIp;
517
574
  declare const network_isValidIpv4: typeof isValidIpv4;
518
575
  declare const network_isValidIpv6: typeof isValidIpv6;
576
+ declare const network_parseContentRangeHeader: typeof parseContentRangeHeader;
519
577
  declare const network_parseDnsResponse: typeof parseDnsResponse;
520
578
  declare const network_parseGeoResponse: typeof parseGeoResponse;
521
579
  declare const network_parseHar: typeof parseHar;
@@ -531,7 +589,7 @@ declare const network_validateHeaderValue: typeof validateHeaderValue;
531
589
  declare const network_validateRobotsTxt: typeof validateRobotsTxt;
532
590
  declare const network_validateSitemap: typeof validateSitemap;
533
591
  declare namespace network {
534
- export { type network_AuthResultEntry as AuthResultEntry, type network_CacheControlDirective as CacheControlDirective, type network_CacheControlOptions as CacheControlOptions, type network_CacheControlResult as CacheControlResult, type network_CookieAttributes as CookieAttributes, type network_CookieCheckResult as CookieCheckResult, network_DNS_RECORD_TYPES as DNS_RECORD_TYPES, type network_DnsRecord as DnsRecord, type network_DnsRecordType as DnsRecordType, type network_DnsResponse as DnsResponse, type network_EmailHeaderAnalysis as EmailHeaderAnalysis, type network_EmailHeaderField as EmailHeaderField, type network_GeoResult as GeoResult, network_HTTP_HEADERS as HTTP_HEADERS, type network_HarEntry as HarEntry, type network_HarParseResult as HarParseResult, type network_HarSummary as HarSummary, type network_HeaderCategory as HeaderCategory, type network_HttpHeader as HttpHeader, type network_Ipv6AddressType as Ipv6AddressType, type network_Ipv6ParseResult as Ipv6ParseResult, network_LINK_REL_VALUES as LINK_REL_VALUES, type network_LinkHeaderEntry as LinkHeaderEntry, type network_LinkHeaderEntryInput as LinkHeaderEntryInput, type network_LinkHeaderResult as LinkHeaderResult, type network_LinkRel as LinkRel, type network_ParsedDnsResult as ParsedDnsResult, type network_ParsedGeoResult as ParsedGeoResult, network_REFERRER_POLICY_VALUES as REFERRER_POLICY_VALUES, type network_ReceivedHop as ReceivedHop, type network_ReferrerPolicyEntry as ReferrerPolicyEntry, type network_ReferrerPolicyResult as ReferrerPolicyResult, type network_ReferrerPolicyValue as ReferrerPolicyValue, type network_RobotsGroup as RobotsGroup, type network_RobotsIssue as RobotsIssue, type network_RobotsRule as RobotsRule, type network_RobotsValidationResult as RobotsValidationResult, network_STATUS_CODES as STATUS_CODES, type network_SameSiteValue as SameSiteValue, type network_SitemapIndexEntry as SitemapIndexEntry, type network_SitemapIssue as SitemapIssue, type network_SitemapUrlEntry as SitemapUrlEntry, type network_SitemapValidationResult as SitemapValidationResult, type network_StatusCode as StatusCode, type network_UaDeviceType as UaDeviceType, type network_UserAgentInfo as UserAgentInfo, network_analyzeEmailHeaders as analyzeEmailHeaders, network_buildCacheControl as buildCacheControl, network_buildDnsQueryUrl as buildDnsQueryUrl, network_buildGeoUrl as buildGeoUrl, network_buildLinkHeader as buildLinkHeader, network_buildMapUrl as buildMapUrl, network_buildReferrerPolicy as buildReferrerPolicy, network_checkSetCookieHeader as checkSetCookieHeader, network_countryCodeToFlag as countryCodeToFlag, network_formatCoordinates as formatCoordinates, network_formatTtl as formatTtl, network_getByCategory as getByCategory, network_getHeader as getHeader, network_getHeadersByCategory as getHeadersByCategory, network_getStatusByCategory as getStatusByCategory, network_getStatusCode as getStatusCode, network_isClientError as isClientError, network_isServerError as isServerError, network_isSuccess as isSuccess, network_isValidIp as isValidIp, network_isValidIpv4 as isValidIpv4, network_isValidIpv6 as isValidIpv6, network_parseDnsResponse as parseDnsResponse, network_parseGeoResponse as parseGeoResponse, network_parseHar as parseHar, network_parseIpv6Address as parseIpv6Address, network_parseUserAgent as parseUserAgent, network_searchHeaders as searchHeaders, network_searchStatusCodes as searchStatusCodes, network_statusCodeToText as statusCodeToText, network_typeNumberToLabel as typeNumberToLabel, network_validateDomain as validateDomain, network_validateHeaderName as validateHeaderName, network_validateHeaderValue as validateHeaderValue, network_validateRobotsTxt as validateRobotsTxt, network_validateSitemap as validateSitemap };
592
+ export { type network_AuthResultEntry as AuthResultEntry, type network_BuildRangeHeaderOptions as BuildRangeHeaderOptions, type network_CacheControlDirective as CacheControlDirective, type network_CacheControlOptions as CacheControlOptions, type network_CacheControlResult as CacheControlResult, type network_ContentRangeResult as ContentRangeResult, type network_CookieAttributes as CookieAttributes, type network_CookieCheckResult as CookieCheckResult, network_DNS_RECORD_TYPES as DNS_RECORD_TYPES, type network_DnsRecord as DnsRecord, type network_DnsRecordType as DnsRecordType, type network_DnsResponse as DnsResponse, type network_EmailHeaderAnalysis as EmailHeaderAnalysis, type network_EmailHeaderField as EmailHeaderField, type network_GeoResult as GeoResult, network_HTTP_HEADERS as HTTP_HEADERS, type network_HarEntry as HarEntry, type network_HarParseResult as HarParseResult, type network_HarSummary as HarSummary, type network_HeaderCategory as HeaderCategory, type network_HttpHeader as HttpHeader, type network_Ipv6AddressType as Ipv6AddressType, type network_Ipv6ParseResult as Ipv6ParseResult, network_LINK_REL_VALUES as LINK_REL_VALUES, type network_LinkHeaderEntry as LinkHeaderEntry, type network_LinkHeaderEntryInput as LinkHeaderEntryInput, type network_LinkHeaderResult as LinkHeaderResult, type network_LinkRel as LinkRel, type network_ParsedDnsResult as ParsedDnsResult, type network_ParsedGeoResult as ParsedGeoResult, network_REFERRER_POLICY_VALUES as REFERRER_POLICY_VALUES, type network_RangeEntry as RangeEntry, type network_RangeEntryInput as RangeEntryInput, type network_RangeHeaderResult as RangeHeaderResult, type network_ReceivedHop as ReceivedHop, type network_ReferrerPolicyEntry as ReferrerPolicyEntry, type network_ReferrerPolicyResult as ReferrerPolicyResult, type network_ReferrerPolicyValue as ReferrerPolicyValue, type network_RobotsGroup as RobotsGroup, type network_RobotsIssue as RobotsIssue, type network_RobotsRule as RobotsRule, type network_RobotsValidationResult as RobotsValidationResult, network_STATUS_CODES as STATUS_CODES, type network_SameSiteValue as SameSiteValue, type network_SitemapIndexEntry as SitemapIndexEntry, type network_SitemapIssue as SitemapIssue, type network_SitemapUrlEntry as SitemapUrlEntry, type network_SitemapValidationResult as SitemapValidationResult, type network_StatusCode as StatusCode, type network_UaDeviceType as UaDeviceType, type network_UserAgentInfo as UserAgentInfo, network_analyzeEmailHeaders as analyzeEmailHeaders, network_buildCacheControl as buildCacheControl, network_buildDnsQueryUrl as buildDnsQueryUrl, network_buildGeoUrl as buildGeoUrl, network_buildLinkHeader as buildLinkHeader, network_buildMapUrl as buildMapUrl, network_buildRangeHeader as buildRangeHeader, network_buildReferrerPolicy as buildReferrerPolicy, network_checkSetCookieHeader as checkSetCookieHeader, network_countryCodeToFlag as countryCodeToFlag, network_formatCoordinates as formatCoordinates, network_formatTtl as formatTtl, network_getByCategory as getByCategory, network_getHeader as getHeader, network_getHeadersByCategory as getHeadersByCategory, network_getStatusByCategory as getStatusByCategory, network_getStatusCode as getStatusCode, network_isClientError as isClientError, network_isServerError as isServerError, network_isSuccess as isSuccess, network_isValidIp as isValidIp, network_isValidIpv4 as isValidIpv4, network_isValidIpv6 as isValidIpv6, network_parseContentRangeHeader as parseContentRangeHeader, network_parseDnsResponse as parseDnsResponse, network_parseGeoResponse as parseGeoResponse, network_parseHar as parseHar, network_parseIpv6Address as parseIpv6Address, network_parseUserAgent as parseUserAgent, network_searchHeaders as searchHeaders, network_searchStatusCodes as searchStatusCodes, network_statusCodeToText as statusCodeToText, network_typeNumberToLabel as typeNumberToLabel, network_validateDomain as validateDomain, network_validateHeaderName as validateHeaderName, network_validateHeaderValue as validateHeaderValue, network_validateRobotsTxt as validateRobotsTxt, network_validateSitemap as validateSitemap };
535
593
  }
536
594
 
537
- export { buildReferrerPolicy as $, type AuthResultEntry as A, type RobotsRule as B, type CacheControlDirective as C, DNS_RECORD_TYPES as D, type EmailHeaderAnalysis as E, type RobotsValidationResult as F, type GeoResult as G, HTTP_HEADERS as H, type Ipv6AddressType as I, type SameSiteValue as J, type SitemapIndexEntry as K, LINK_REL_VALUES as L, type SitemapIssue as M, type SitemapUrlEntry as N, type SitemapValidationResult as O, type ParsedDnsResult as P, type StatusCode as Q, REFERRER_POLICY_VALUES as R, STATUS_CODES as S, type UserAgentInfo as T, type UaDeviceType as U, analyzeEmailHeaders as V, buildCacheControl as W, buildDnsQueryUrl as X, buildGeoUrl as Y, buildLinkHeader as Z, buildMapUrl as _, type CacheControlOptions as a, checkSetCookieHeader as a0, countryCodeToFlag as a1, formatCoordinates as a2, formatTtl as a3, getByCategory as a4, getHeader as a5, getHeadersByCategory as a6, getStatusByCategory as a7, getStatusCode as a8, isClientError as a9, isServerError as aa, isSuccess as ab, isValidIp as ac, isValidIpv4 as ad, isValidIpv6 as ae, parseDnsResponse as af, parseGeoResponse as ag, parseHar as ah, parseIpv6Address as ai, parseUserAgent as aj, searchHeaders as ak, searchStatusCodes as al, statusCodeToText as am, typeNumberToLabel as an, validateDomain as ao, validateHeaderName as ap, validateHeaderValue as aq, validateRobotsTxt as ar, validateSitemap as as, type CacheControlResult as b, type CookieAttributes as c, type CookieCheckResult as d, type DnsRecord as e, type DnsRecordType as f, type DnsResponse as g, type EmailHeaderField as h, type HarEntry as i, type HarParseResult as j, type HarSummary as k, type HeaderCategory as l, type HttpHeader as m, network as n, type Ipv6ParseResult as o, type LinkHeaderEntry as p, type LinkHeaderEntryInput as q, type LinkHeaderResult as r, type LinkRel as s, type ParsedGeoResult as t, type ReceivedHop as u, type ReferrerPolicyEntry as v, type ReferrerPolicyResult as w, type ReferrerPolicyValue as x, type RobotsGroup as y, type RobotsIssue as z };
595
+ export { buildCacheControl as $, type AuthResultEntry as A, type BuildRangeHeaderOptions as B, type CacheControlDirective as C, DNS_RECORD_TYPES as D, type EmailHeaderAnalysis as E, type ReferrerPolicyResult as F, type GeoResult as G, HTTP_HEADERS as H, type Ipv6AddressType as I, type ReferrerPolicyValue as J, type RobotsGroup as K, LINK_REL_VALUES as L, type RobotsIssue as M, type RobotsRule as N, type RobotsValidationResult as O, type ParsedDnsResult as P, type SameSiteValue as Q, REFERRER_POLICY_VALUES as R, STATUS_CODES as S, type SitemapIndexEntry as T, type SitemapIssue as U, type SitemapUrlEntry as V, type SitemapValidationResult as W, type StatusCode as X, type UaDeviceType as Y, type UserAgentInfo as Z, analyzeEmailHeaders as _, type CacheControlOptions as a, buildDnsQueryUrl as a0, buildGeoUrl as a1, buildLinkHeader as a2, buildMapUrl as a3, buildRangeHeader as a4, buildReferrerPolicy as a5, checkSetCookieHeader as a6, countryCodeToFlag as a7, formatCoordinates as a8, formatTtl as a9, getByCategory as aa, getHeader as ab, getHeadersByCategory as ac, getStatusByCategory as ad, getStatusCode as ae, isClientError as af, isServerError as ag, isSuccess as ah, isValidIp as ai, isValidIpv4 as aj, isValidIpv6 as ak, parseContentRangeHeader as al, parseDnsResponse as am, parseGeoResponse as an, parseHar as ao, parseIpv6Address as ap, parseUserAgent as aq, searchHeaders as ar, searchStatusCodes as as, statusCodeToText as at, typeNumberToLabel as au, validateDomain as av, validateHeaderName as aw, validateHeaderValue as ax, validateRobotsTxt as ay, validateSitemap as az, type CacheControlResult as b, type ContentRangeResult as c, type CookieAttributes as d, type CookieCheckResult as e, type DnsRecord as f, type DnsRecordType as g, type DnsResponse as h, type EmailHeaderField as i, type HarEntry as j, type HarParseResult as k, type HarSummary as l, type HeaderCategory as m, network as n, type HttpHeader as o, type Ipv6ParseResult as p, type LinkHeaderEntry as q, type LinkHeaderEntryInput as r, type LinkHeaderResult as s, type LinkRel as t, type ParsedGeoResult as u, type RangeEntry as v, type RangeEntryInput as w, type RangeHeaderResult as x, type ReceivedHop as y, type ReferrerPolicyEntry as z };
@@ -17,6 +17,7 @@
17
17
  * - link-header-builder: buildLinkHeader
18
18
  * - same-site-cookie-checker: checkSetCookieHeader
19
19
  * - email-header-analyzer: analyzeEmailHeaders
20
+ * - http-range-header-builder: buildRangeHeader, parseContentRangeHeader
20
21
  */
21
22
  declare const DNS_RECORD_TYPES: readonly ["A", "AAAA", "CNAME", "MX", "TXT", "NS", "SOA", "PTR", "SRV", "CAA"];
22
23
  type DnsRecordType = typeof DNS_RECORD_TYPES[number];
@@ -447,11 +448,63 @@ interface EmailHeaderAnalysis {
447
448
  declare function analyzeEmailHeaders(raw: string): EmailHeaderAnalysis | {
448
449
  error: string;
449
450
  };
451
+ interface RangeEntryInput {
452
+ start?: number;
453
+ end?: number;
454
+ suffixLength?: number;
455
+ }
456
+ interface RangeEntry {
457
+ spec: string;
458
+ start: number | null;
459
+ end: number | null;
460
+ suffixLength: number | null;
461
+ byteLength: number | null;
462
+ percentOfTotal: number | null;
463
+ }
464
+ interface RangeHeaderResult {
465
+ header: string;
466
+ headerValue: string;
467
+ ranges: RangeEntry[];
468
+ totalBytesRequested: number | null;
469
+ warnings: string[];
470
+ }
471
+ interface BuildRangeHeaderOptions {
472
+ totalSize?: number;
473
+ unit?: string;
474
+ }
475
+ /**
476
+ * Build an HTTP `Range` request header from a list of byte ranges. Each
477
+ * entry is either `{ start, end? }` (an explicit or open-ended range) or
478
+ * `{ suffixLength }` (the last N bytes). Pass `totalSize` to resolve
479
+ * open-ended/suffix byte lengths and get overlap warnings.
480
+ */
481
+ declare function buildRangeHeader(entries: RangeEntryInput[], options?: BuildRangeHeaderOptions): RangeHeaderResult | {
482
+ error: string;
483
+ };
484
+ interface ContentRangeResult {
485
+ unit: string;
486
+ start: number | null;
487
+ end: number | null;
488
+ total: number | null;
489
+ isUnsatisfiable: boolean;
490
+ isTotalUnknown: boolean;
491
+ byteLength: number | null;
492
+ }
493
+ /**
494
+ * Parse a `Content-Range` response header (e.g. `bytes 200-1000/67589` or
495
+ * `bytes *\/67589` for an unsatisfiable range) into its unit, byte bounds,
496
+ * and total resource size.
497
+ */
498
+ declare function parseContentRangeHeader(header: string): ContentRangeResult | {
499
+ error: string;
500
+ };
450
501
 
451
502
  type network_AuthResultEntry = AuthResultEntry;
503
+ type network_BuildRangeHeaderOptions = BuildRangeHeaderOptions;
452
504
  type network_CacheControlDirective = CacheControlDirective;
453
505
  type network_CacheControlOptions = CacheControlOptions;
454
506
  type network_CacheControlResult = CacheControlResult;
507
+ type network_ContentRangeResult = ContentRangeResult;
455
508
  type network_CookieAttributes = CookieAttributes;
456
509
  type network_CookieCheckResult = CookieCheckResult;
457
510
  declare const network_DNS_RECORD_TYPES: typeof DNS_RECORD_TYPES;
@@ -477,6 +530,9 @@ type network_LinkRel = LinkRel;
477
530
  type network_ParsedDnsResult = ParsedDnsResult;
478
531
  type network_ParsedGeoResult = ParsedGeoResult;
479
532
  declare const network_REFERRER_POLICY_VALUES: typeof REFERRER_POLICY_VALUES;
533
+ type network_RangeEntry = RangeEntry;
534
+ type network_RangeEntryInput = RangeEntryInput;
535
+ type network_RangeHeaderResult = RangeHeaderResult;
480
536
  type network_ReceivedHop = ReceivedHop;
481
537
  type network_ReferrerPolicyEntry = ReferrerPolicyEntry;
482
538
  type network_ReferrerPolicyResult = ReferrerPolicyResult;
@@ -500,6 +556,7 @@ declare const network_buildDnsQueryUrl: typeof buildDnsQueryUrl;
500
556
  declare const network_buildGeoUrl: typeof buildGeoUrl;
501
557
  declare const network_buildLinkHeader: typeof buildLinkHeader;
502
558
  declare const network_buildMapUrl: typeof buildMapUrl;
559
+ declare const network_buildRangeHeader: typeof buildRangeHeader;
503
560
  declare const network_buildReferrerPolicy: typeof buildReferrerPolicy;
504
561
  declare const network_checkSetCookieHeader: typeof checkSetCookieHeader;
505
562
  declare const network_countryCodeToFlag: typeof countryCodeToFlag;
@@ -516,6 +573,7 @@ declare const network_isSuccess: typeof isSuccess;
516
573
  declare const network_isValidIp: typeof isValidIp;
517
574
  declare const network_isValidIpv4: typeof isValidIpv4;
518
575
  declare const network_isValidIpv6: typeof isValidIpv6;
576
+ declare const network_parseContentRangeHeader: typeof parseContentRangeHeader;
519
577
  declare const network_parseDnsResponse: typeof parseDnsResponse;
520
578
  declare const network_parseGeoResponse: typeof parseGeoResponse;
521
579
  declare const network_parseHar: typeof parseHar;
@@ -531,7 +589,7 @@ declare const network_validateHeaderValue: typeof validateHeaderValue;
531
589
  declare const network_validateRobotsTxt: typeof validateRobotsTxt;
532
590
  declare const network_validateSitemap: typeof validateSitemap;
533
591
  declare namespace network {
534
- export { type network_AuthResultEntry as AuthResultEntry, type network_CacheControlDirective as CacheControlDirective, type network_CacheControlOptions as CacheControlOptions, type network_CacheControlResult as CacheControlResult, type network_CookieAttributes as CookieAttributes, type network_CookieCheckResult as CookieCheckResult, network_DNS_RECORD_TYPES as DNS_RECORD_TYPES, type network_DnsRecord as DnsRecord, type network_DnsRecordType as DnsRecordType, type network_DnsResponse as DnsResponse, type network_EmailHeaderAnalysis as EmailHeaderAnalysis, type network_EmailHeaderField as EmailHeaderField, type network_GeoResult as GeoResult, network_HTTP_HEADERS as HTTP_HEADERS, type network_HarEntry as HarEntry, type network_HarParseResult as HarParseResult, type network_HarSummary as HarSummary, type network_HeaderCategory as HeaderCategory, type network_HttpHeader as HttpHeader, type network_Ipv6AddressType as Ipv6AddressType, type network_Ipv6ParseResult as Ipv6ParseResult, network_LINK_REL_VALUES as LINK_REL_VALUES, type network_LinkHeaderEntry as LinkHeaderEntry, type network_LinkHeaderEntryInput as LinkHeaderEntryInput, type network_LinkHeaderResult as LinkHeaderResult, type network_LinkRel as LinkRel, type network_ParsedDnsResult as ParsedDnsResult, type network_ParsedGeoResult as ParsedGeoResult, network_REFERRER_POLICY_VALUES as REFERRER_POLICY_VALUES, type network_ReceivedHop as ReceivedHop, type network_ReferrerPolicyEntry as ReferrerPolicyEntry, type network_ReferrerPolicyResult as ReferrerPolicyResult, type network_ReferrerPolicyValue as ReferrerPolicyValue, type network_RobotsGroup as RobotsGroup, type network_RobotsIssue as RobotsIssue, type network_RobotsRule as RobotsRule, type network_RobotsValidationResult as RobotsValidationResult, network_STATUS_CODES as STATUS_CODES, type network_SameSiteValue as SameSiteValue, type network_SitemapIndexEntry as SitemapIndexEntry, type network_SitemapIssue as SitemapIssue, type network_SitemapUrlEntry as SitemapUrlEntry, type network_SitemapValidationResult as SitemapValidationResult, type network_StatusCode as StatusCode, type network_UaDeviceType as UaDeviceType, type network_UserAgentInfo as UserAgentInfo, network_analyzeEmailHeaders as analyzeEmailHeaders, network_buildCacheControl as buildCacheControl, network_buildDnsQueryUrl as buildDnsQueryUrl, network_buildGeoUrl as buildGeoUrl, network_buildLinkHeader as buildLinkHeader, network_buildMapUrl as buildMapUrl, network_buildReferrerPolicy as buildReferrerPolicy, network_checkSetCookieHeader as checkSetCookieHeader, network_countryCodeToFlag as countryCodeToFlag, network_formatCoordinates as formatCoordinates, network_formatTtl as formatTtl, network_getByCategory as getByCategory, network_getHeader as getHeader, network_getHeadersByCategory as getHeadersByCategory, network_getStatusByCategory as getStatusByCategory, network_getStatusCode as getStatusCode, network_isClientError as isClientError, network_isServerError as isServerError, network_isSuccess as isSuccess, network_isValidIp as isValidIp, network_isValidIpv4 as isValidIpv4, network_isValidIpv6 as isValidIpv6, network_parseDnsResponse as parseDnsResponse, network_parseGeoResponse as parseGeoResponse, network_parseHar as parseHar, network_parseIpv6Address as parseIpv6Address, network_parseUserAgent as parseUserAgent, network_searchHeaders as searchHeaders, network_searchStatusCodes as searchStatusCodes, network_statusCodeToText as statusCodeToText, network_typeNumberToLabel as typeNumberToLabel, network_validateDomain as validateDomain, network_validateHeaderName as validateHeaderName, network_validateHeaderValue as validateHeaderValue, network_validateRobotsTxt as validateRobotsTxt, network_validateSitemap as validateSitemap };
592
+ export { type network_AuthResultEntry as AuthResultEntry, type network_BuildRangeHeaderOptions as BuildRangeHeaderOptions, type network_CacheControlDirective as CacheControlDirective, type network_CacheControlOptions as CacheControlOptions, type network_CacheControlResult as CacheControlResult, type network_ContentRangeResult as ContentRangeResult, type network_CookieAttributes as CookieAttributes, type network_CookieCheckResult as CookieCheckResult, network_DNS_RECORD_TYPES as DNS_RECORD_TYPES, type network_DnsRecord as DnsRecord, type network_DnsRecordType as DnsRecordType, type network_DnsResponse as DnsResponse, type network_EmailHeaderAnalysis as EmailHeaderAnalysis, type network_EmailHeaderField as EmailHeaderField, type network_GeoResult as GeoResult, network_HTTP_HEADERS as HTTP_HEADERS, type network_HarEntry as HarEntry, type network_HarParseResult as HarParseResult, type network_HarSummary as HarSummary, type network_HeaderCategory as HeaderCategory, type network_HttpHeader as HttpHeader, type network_Ipv6AddressType as Ipv6AddressType, type network_Ipv6ParseResult as Ipv6ParseResult, network_LINK_REL_VALUES as LINK_REL_VALUES, type network_LinkHeaderEntry as LinkHeaderEntry, type network_LinkHeaderEntryInput as LinkHeaderEntryInput, type network_LinkHeaderResult as LinkHeaderResult, type network_LinkRel as LinkRel, type network_ParsedDnsResult as ParsedDnsResult, type network_ParsedGeoResult as ParsedGeoResult, network_REFERRER_POLICY_VALUES as REFERRER_POLICY_VALUES, type network_RangeEntry as RangeEntry, type network_RangeEntryInput as RangeEntryInput, type network_RangeHeaderResult as RangeHeaderResult, type network_ReceivedHop as ReceivedHop, type network_ReferrerPolicyEntry as ReferrerPolicyEntry, type network_ReferrerPolicyResult as ReferrerPolicyResult, type network_ReferrerPolicyValue as ReferrerPolicyValue, type network_RobotsGroup as RobotsGroup, type network_RobotsIssue as RobotsIssue, type network_RobotsRule as RobotsRule, type network_RobotsValidationResult as RobotsValidationResult, network_STATUS_CODES as STATUS_CODES, type network_SameSiteValue as SameSiteValue, type network_SitemapIndexEntry as SitemapIndexEntry, type network_SitemapIssue as SitemapIssue, type network_SitemapUrlEntry as SitemapUrlEntry, type network_SitemapValidationResult as SitemapValidationResult, type network_StatusCode as StatusCode, type network_UaDeviceType as UaDeviceType, type network_UserAgentInfo as UserAgentInfo, network_analyzeEmailHeaders as analyzeEmailHeaders, network_buildCacheControl as buildCacheControl, network_buildDnsQueryUrl as buildDnsQueryUrl, network_buildGeoUrl as buildGeoUrl, network_buildLinkHeader as buildLinkHeader, network_buildMapUrl as buildMapUrl, network_buildRangeHeader as buildRangeHeader, network_buildReferrerPolicy as buildReferrerPolicy, network_checkSetCookieHeader as checkSetCookieHeader, network_countryCodeToFlag as countryCodeToFlag, network_formatCoordinates as formatCoordinates, network_formatTtl as formatTtl, network_getByCategory as getByCategory, network_getHeader as getHeader, network_getHeadersByCategory as getHeadersByCategory, network_getStatusByCategory as getStatusByCategory, network_getStatusCode as getStatusCode, network_isClientError as isClientError, network_isServerError as isServerError, network_isSuccess as isSuccess, network_isValidIp as isValidIp, network_isValidIpv4 as isValidIpv4, network_isValidIpv6 as isValidIpv6, network_parseContentRangeHeader as parseContentRangeHeader, network_parseDnsResponse as parseDnsResponse, network_parseGeoResponse as parseGeoResponse, network_parseHar as parseHar, network_parseIpv6Address as parseIpv6Address, network_parseUserAgent as parseUserAgent, network_searchHeaders as searchHeaders, network_searchStatusCodes as searchStatusCodes, network_statusCodeToText as statusCodeToText, network_typeNumberToLabel as typeNumberToLabel, network_validateDomain as validateDomain, network_validateHeaderName as validateHeaderName, network_validateHeaderValue as validateHeaderValue, network_validateRobotsTxt as validateRobotsTxt, network_validateSitemap as validateSitemap };
535
593
  }
536
594
 
537
- export { buildReferrerPolicy as $, type AuthResultEntry as A, type RobotsRule as B, type CacheControlDirective as C, DNS_RECORD_TYPES as D, type EmailHeaderAnalysis as E, type RobotsValidationResult as F, type GeoResult as G, HTTP_HEADERS as H, type Ipv6AddressType as I, type SameSiteValue as J, type SitemapIndexEntry as K, LINK_REL_VALUES as L, type SitemapIssue as M, type SitemapUrlEntry as N, type SitemapValidationResult as O, type ParsedDnsResult as P, type StatusCode as Q, REFERRER_POLICY_VALUES as R, STATUS_CODES as S, type UserAgentInfo as T, type UaDeviceType as U, analyzeEmailHeaders as V, buildCacheControl as W, buildDnsQueryUrl as X, buildGeoUrl as Y, buildLinkHeader as Z, buildMapUrl as _, type CacheControlOptions as a, checkSetCookieHeader as a0, countryCodeToFlag as a1, formatCoordinates as a2, formatTtl as a3, getByCategory as a4, getHeader as a5, getHeadersByCategory as a6, getStatusByCategory as a7, getStatusCode as a8, isClientError as a9, isServerError as aa, isSuccess as ab, isValidIp as ac, isValidIpv4 as ad, isValidIpv6 as ae, parseDnsResponse as af, parseGeoResponse as ag, parseHar as ah, parseIpv6Address as ai, parseUserAgent as aj, searchHeaders as ak, searchStatusCodes as al, statusCodeToText as am, typeNumberToLabel as an, validateDomain as ao, validateHeaderName as ap, validateHeaderValue as aq, validateRobotsTxt as ar, validateSitemap as as, type CacheControlResult as b, type CookieAttributes as c, type CookieCheckResult as d, type DnsRecord as e, type DnsRecordType as f, type DnsResponse as g, type EmailHeaderField as h, type HarEntry as i, type HarParseResult as j, type HarSummary as k, type HeaderCategory as l, type HttpHeader as m, network as n, type Ipv6ParseResult as o, type LinkHeaderEntry as p, type LinkHeaderEntryInput as q, type LinkHeaderResult as r, type LinkRel as s, type ParsedGeoResult as t, type ReceivedHop as u, type ReferrerPolicyEntry as v, type ReferrerPolicyResult as w, type ReferrerPolicyValue as x, type RobotsGroup as y, type RobotsIssue as z };
595
+ export { buildCacheControl as $, type AuthResultEntry as A, type BuildRangeHeaderOptions as B, type CacheControlDirective as C, DNS_RECORD_TYPES as D, type EmailHeaderAnalysis as E, type ReferrerPolicyResult as F, type GeoResult as G, HTTP_HEADERS as H, type Ipv6AddressType as I, type ReferrerPolicyValue as J, type RobotsGroup as K, LINK_REL_VALUES as L, type RobotsIssue as M, type RobotsRule as N, type RobotsValidationResult as O, type ParsedDnsResult as P, type SameSiteValue as Q, REFERRER_POLICY_VALUES as R, STATUS_CODES as S, type SitemapIndexEntry as T, type SitemapIssue as U, type SitemapUrlEntry as V, type SitemapValidationResult as W, type StatusCode as X, type UaDeviceType as Y, type UserAgentInfo as Z, analyzeEmailHeaders as _, type CacheControlOptions as a, buildDnsQueryUrl as a0, buildGeoUrl as a1, buildLinkHeader as a2, buildMapUrl as a3, buildRangeHeader as a4, buildReferrerPolicy as a5, checkSetCookieHeader as a6, countryCodeToFlag as a7, formatCoordinates as a8, formatTtl as a9, getByCategory as aa, getHeader as ab, getHeadersByCategory as ac, getStatusByCategory as ad, getStatusCode as ae, isClientError as af, isServerError as ag, isSuccess as ah, isValidIp as ai, isValidIpv4 as aj, isValidIpv6 as ak, parseContentRangeHeader as al, parseDnsResponse as am, parseGeoResponse as an, parseHar as ao, parseIpv6Address as ap, parseUserAgent as aq, searchHeaders as ar, searchStatusCodes as as, statusCodeToText as at, typeNumberToLabel as au, validateDomain as av, validateHeaderName as aw, validateHeaderValue as ax, validateRobotsTxt as ay, validateSitemap as az, type CacheControlResult as b, type ContentRangeResult as c, type CookieAttributes as d, type CookieCheckResult as e, type DnsRecord as f, type DnsRecordType as g, type DnsResponse as h, type EmailHeaderField as i, type HarEntry as j, type HarParseResult as k, type HarSummary as l, type HeaderCategory as m, network as n, type HttpHeader as o, type Ipv6ParseResult as p, type LinkHeaderEntry as q, type LinkHeaderEntryInput as r, type LinkHeaderResult as s, type LinkRel as t, type ParsedGeoResult as u, type RangeEntry as v, type RangeEntryInput as w, type RangeHeaderResult as x, type ReceivedHop as y, type ReferrerPolicyEntry as z };
@@ -1472,6 +1472,65 @@ function csvToSqlInsert(input, options) {
1472
1472
  columns
1473
1473
  };
1474
1474
  }
1475
+ function _normalizeDuplicateValue(value, caseSensitive, trimWhitespace) {
1476
+ let v = value;
1477
+ if (trimWhitespace) v = v.trim();
1478
+ if (!caseSensitive) v = v.toLowerCase();
1479
+ return v;
1480
+ }
1481
+ function findCsvDuplicateRows(input, options) {
1482
+ const parsed = parseCsv(input, {
1483
+ delimiter: options?.delimiter ?? ",",
1484
+ hasHeader: options?.hasHeader !== false,
1485
+ trimWhitespace: false
1486
+ });
1487
+ if ("error" in parsed) return parsed;
1488
+ if (parsed.rows.length === 0) return { error: "No data rows found" };
1489
+ const caseSensitive = options?.caseSensitive !== false;
1490
+ const trimWhitespace = options?.trimWhitespace !== false;
1491
+ let keyIndexes;
1492
+ if (options?.keyColumns && options.keyColumns.length > 0) {
1493
+ keyIndexes = [];
1494
+ for (const col of options.keyColumns) {
1495
+ const idx = parsed.headers.indexOf(col);
1496
+ if (idx === -1) {
1497
+ return { error: `Column "${col}" not found. Available columns: ${parsed.headers.join(", ")}` };
1498
+ }
1499
+ keyIndexes.push(idx);
1500
+ }
1501
+ } else {
1502
+ keyIndexes = parsed.headers.map((_, idx) => idx);
1503
+ }
1504
+ const groups = /* @__PURE__ */ new Map();
1505
+ parsed.rows.forEach((row, i) => {
1506
+ const key = keyIndexes.map((idx) => row[idx] ?? "");
1507
+ const normalizedKey = keyIndexes.map((idx) => _normalizeDuplicateValue(row[idx] ?? "", caseSensitive, trimWhitespace));
1508
+ const mapKey = JSON.stringify(normalizedKey);
1509
+ const rowNumber = i + 1;
1510
+ const existing = groups.get(mapKey);
1511
+ if (existing) {
1512
+ existing.rowNumbers.push(rowNumber);
1513
+ } else {
1514
+ groups.set(mapKey, { key, rowNumbers: [rowNumber] });
1515
+ }
1516
+ });
1517
+ const duplicateGroups = [];
1518
+ let duplicateRowCount = 0;
1519
+ for (const group of groups.values()) {
1520
+ if (group.rowNumbers.length > 1) {
1521
+ duplicateGroups.push({ key: group.key, rowNumbers: group.rowNumbers, count: group.rowNumbers.length });
1522
+ duplicateRowCount += group.rowNumbers.length;
1523
+ }
1524
+ }
1525
+ duplicateGroups.sort((a, b) => b.count - a.count);
1526
+ return {
1527
+ headers: parsed.headers,
1528
+ totalRows: parsed.rows.length,
1529
+ duplicateGroups,
1530
+ duplicateRowCount,
1531
+ uniqueRowCount: parsed.rows.length - duplicateRowCount + duplicateGroups.length
1532
+ };
1533
+ }
1475
1534
 
1476
1535
  exports.convertSubtitles = convertSubtitles;
1477
1536
  exports.csvToJson = csvToJson;
@@ -1481,6 +1540,7 @@ exports.detectSubtitleFormat = detectSubtitleFormat;
1481
1540
  exports.diffEnvExample = diffEnvExample;
1482
1541
  exports.envToExport = envToExport;
1483
1542
  exports.envToJson = envToJson;
1543
+ exports.findCsvDuplicateRows = findCsvDuplicateRows;
1484
1544
  exports.formatNdjson = formatNdjson;
1485
1545
  exports.formatSubtitleTimestamp = formatSubtitleTimestamp;
1486
1546
  exports.formatToml = formatToml;
@@ -1 +1 @@
1
- export { C as ConvertedSubtitles, a as CsvParseResult, b as CsvToSqlOptions, c as CsvToSqlResult, E as EnvDiffError, e as EnvDiffResult, f as EnvEntry, g as EnvParseResult, F as FrontMatterError, h as FrontMatterResult, I as IniSection, M as MarkdownTocEntry, i as MarkdownTocOptions, j as MarkdownTocResult, N as NdjsonLineResult, k as NdjsonValidateResult, P as ParseOptions, l as ParsedIni, m as ParsedSubtitles, S as SubtitleCue, n as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, o as XmlToJsonOptions, p as convertSubtitles, q as csvToJson, r as csvToSqlInsert, s as detectDelimiter, t as detectSubtitleFormat, u as diffEnvExample, v as envToExport, w as envToJson, x as formatNdjson, y as formatSubtitleTimestamp, z as formatToml, A as formatXml, B as generateMarkdownToc, D as getSection, G as getSectionNames, H as getTomlStats, J as getXmlStats, K as getYamlStats, L as iniToJson, O as jsonArrayToNdjson, Q as jsonToIni, R as jsonToToml, U as jsonToXml, W as minifyNdjson, Y as minifyToml, Z as minifyXml, _ as ndjsonToJsonArray, $ as parseCsv, a0 as parseEnv, a1 as parseFrontMatter, a2 as parseIni, a3 as parseSubtitleTimestamp, a4 as parseSubtitles, a5 as parseXmlToObject, a6 as serializeSubtitles, a7 as shiftSubtitles, a8 as stringifyIni, a9 as toCsvString, aa as tomlToJson, ab as validateEnvKey, ac as validateIni, ad as validateNdjson, ae as validateToml, af as validateXml, ag as validateYaml, ah as xmlToJson } from '../data-BCf3dm-E.cjs';
1
+ export { C as ConvertedSubtitles, a as CsvDuplicateGroup, b as CsvDuplicateOptions, c as CsvDuplicateResult, e as CsvParseResult, f as CsvToSqlOptions, g as CsvToSqlResult, E as EnvDiffError, h as EnvDiffResult, i as EnvEntry, j as EnvParseResult, F as FrontMatterError, k as FrontMatterResult, I as IniSection, M as MarkdownTocEntry, l as MarkdownTocOptions, m as MarkdownTocResult, N as NdjsonLineResult, n as NdjsonValidateResult, P as ParseOptions, o as ParsedIni, p as ParsedSubtitles, S as SubtitleCue, q as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, r as XmlToJsonOptions, s as convertSubtitles, t as csvToJson, u as csvToSqlInsert, v as detectDelimiter, w as detectSubtitleFormat, x as diffEnvExample, y as envToExport, z as envToJson, A as findCsvDuplicateRows, B as formatNdjson, D as formatSubtitleTimestamp, G as formatToml, H as formatXml, J as generateMarkdownToc, K as getSection, L as getSectionNames, O as getTomlStats, Q as getXmlStats, R as getYamlStats, U as iniToJson, W as jsonArrayToNdjson, Y as jsonToIni, Z as jsonToToml, _ as jsonToXml, $ as minifyNdjson, a0 as minifyToml, a1 as minifyXml, a2 as ndjsonToJsonArray, a3 as parseCsv, a4 as parseEnv, a5 as parseFrontMatter, a6 as parseIni, a7 as parseSubtitleTimestamp, a8 as parseSubtitles, a9 as parseXmlToObject, aa as serializeSubtitles, ab as shiftSubtitles, ac as stringifyIni, ad as toCsvString, ae as tomlToJson, af as validateEnvKey, ag as validateIni, ah as validateNdjson, ai as validateToml, aj as validateXml, ak as validateYaml, al as xmlToJson } from '../data-BKpEOcOX.cjs';
@@ -1 +1 @@
1
- export { C as ConvertedSubtitles, a as CsvParseResult, b as CsvToSqlOptions, c as CsvToSqlResult, E as EnvDiffError, e as EnvDiffResult, f as EnvEntry, g as EnvParseResult, F as FrontMatterError, h as FrontMatterResult, I as IniSection, M as MarkdownTocEntry, i as MarkdownTocOptions, j as MarkdownTocResult, N as NdjsonLineResult, k as NdjsonValidateResult, P as ParseOptions, l as ParsedIni, m as ParsedSubtitles, S as SubtitleCue, n as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, o as XmlToJsonOptions, p as convertSubtitles, q as csvToJson, r as csvToSqlInsert, s as detectDelimiter, t as detectSubtitleFormat, u as diffEnvExample, v as envToExport, w as envToJson, x as formatNdjson, y as formatSubtitleTimestamp, z as formatToml, A as formatXml, B as generateMarkdownToc, D as getSection, G as getSectionNames, H as getTomlStats, J as getXmlStats, K as getYamlStats, L as iniToJson, O as jsonArrayToNdjson, Q as jsonToIni, R as jsonToToml, U as jsonToXml, W as minifyNdjson, Y as minifyToml, Z as minifyXml, _ as ndjsonToJsonArray, $ as parseCsv, a0 as parseEnv, a1 as parseFrontMatter, a2 as parseIni, a3 as parseSubtitleTimestamp, a4 as parseSubtitles, a5 as parseXmlToObject, a6 as serializeSubtitles, a7 as shiftSubtitles, a8 as stringifyIni, a9 as toCsvString, aa as tomlToJson, ab as validateEnvKey, ac as validateIni, ad as validateNdjson, ae as validateToml, af as validateXml, ag as validateYaml, ah as xmlToJson } from '../data-BCf3dm-E.js';
1
+ export { C as ConvertedSubtitles, a as CsvDuplicateGroup, b as CsvDuplicateOptions, c as CsvDuplicateResult, e as CsvParseResult, f as CsvToSqlOptions, g as CsvToSqlResult, E as EnvDiffError, h as EnvDiffResult, i as EnvEntry, j as EnvParseResult, F as FrontMatterError, k as FrontMatterResult, I as IniSection, M as MarkdownTocEntry, l as MarkdownTocOptions, m as MarkdownTocResult, N as NdjsonLineResult, n as NdjsonValidateResult, P as ParseOptions, o as ParsedIni, p as ParsedSubtitles, S as SubtitleCue, q as SubtitleFormat, T as TomlFormatResult, V as ValidationResult, X as XmlFormatResult, r as XmlToJsonOptions, s as convertSubtitles, t as csvToJson, u as csvToSqlInsert, v as detectDelimiter, w as detectSubtitleFormat, x as diffEnvExample, y as envToExport, z as envToJson, A as findCsvDuplicateRows, B as formatNdjson, D as formatSubtitleTimestamp, G as formatToml, H as formatXml, J as generateMarkdownToc, K as getSection, L as getSectionNames, O as getTomlStats, Q as getXmlStats, R as getYamlStats, U as iniToJson, W as jsonArrayToNdjson, Y as jsonToIni, Z as jsonToToml, _ as jsonToXml, $ as minifyNdjson, a0 as minifyToml, a1 as minifyXml, a2 as ndjsonToJsonArray, a3 as parseCsv, a4 as parseEnv, a5 as parseFrontMatter, a6 as parseIni, a7 as parseSubtitleTimestamp, a8 as parseSubtitles, a9 as parseXmlToObject, aa as serializeSubtitles, ab as shiftSubtitles, ac as stringifyIni, ad as toCsvString, ae as tomlToJson, af as validateEnvKey, ag as validateIni, ah as validateNdjson, ai as validateToml, aj as validateXml, ak as validateYaml, al as xmlToJson } from '../data-BKpEOcOX.js';
@@ -1,2 +1,2 @@
1
- export { convertSubtitles, csvToJson, csvToSqlInsert, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, generateMarkdownToc, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson } from '../chunk-RZUNTYEH.js';
1
+ export { convertSubtitles, csvToJson, csvToSqlInsert, detectDelimiter, detectSubtitleFormat, diffEnvExample, envToExport, envToJson, findCsvDuplicateRows, formatNdjson, formatSubtitleTimestamp, formatToml, formatXml, generateMarkdownToc, getSection, getSectionNames, getTomlStats, getXmlStats, getYamlStats, iniToJson, jsonArrayToNdjson, jsonToIni, jsonToToml, jsonToXml, minifyNdjson, minifyToml, minifyXml, ndjsonToJsonArray, parseCsv, parseEnv, parseFrontMatter, parseIni, parseSubtitleTimestamp, parseSubtitles, parseXmlToObject, serializeSubtitles, shiftSubtitles, stringifyIni, toCsvString, tomlToJson, validateEnvKey, validateIni, validateNdjson, validateToml, validateXml, validateYaml, xmlToJson } from '../chunk-JR354NH4.js';
2
2
  import '../chunk-MLKGABMK.js';
@@ -2165,6 +2165,119 @@ function analyzeEmailHeaders(raw) {
2165
2165
  warnings
2166
2166
  };
2167
2167
  }
2168
+ function _round2(n) {
2169
+ return Math.round(n * 100) / 100;
2170
+ }
2171
+ function buildRangeHeader(entries, options) {
2172
+ if (!Array.isArray(entries) || entries.length === 0) {
2173
+ return { error: "At least one range is required" };
2174
+ }
2175
+ const unit = options?.unit?.trim() || "bytes";
2176
+ const totalSize = typeof options?.totalSize === "number" && Number.isFinite(options.totalSize) ? options.totalSize : void 0;
2177
+ if (totalSize !== void 0 && totalSize <= 0) {
2178
+ return { error: "totalSize must be a positive number when provided" };
2179
+ }
2180
+ const parsed = [];
2181
+ for (const entry of entries) {
2182
+ if (entry.suffixLength !== void 0) {
2183
+ if (!Number.isFinite(entry.suffixLength) || entry.suffixLength <= 0) {
2184
+ return { error: "suffixLength must be a positive number" };
2185
+ }
2186
+ const suffixLength = Math.floor(entry.suffixLength);
2187
+ const byteLength = totalSize !== void 0 ? Math.min(suffixLength, totalSize) : suffixLength;
2188
+ parsed.push({
2189
+ spec: `-${suffixLength}`,
2190
+ start: null,
2191
+ end: null,
2192
+ suffixLength,
2193
+ byteLength,
2194
+ percentOfTotal: totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
2195
+ });
2196
+ continue;
2197
+ }
2198
+ if (entry.start === void 0) {
2199
+ return { error: "Each range requires either a start byte or a suffixLength" };
2200
+ }
2201
+ if (!Number.isFinite(entry.start) || entry.start < 0) {
2202
+ return { error: "start must be a non-negative number" };
2203
+ }
2204
+ const start = Math.floor(entry.start);
2205
+ if (totalSize !== void 0 && start >= totalSize) {
2206
+ return { error: `start byte ${start} is beyond totalSize (${totalSize})` };
2207
+ }
2208
+ if (entry.end !== void 0) {
2209
+ if (!Number.isFinite(entry.end) || entry.end < 0) {
2210
+ return { error: "end must be a non-negative number" };
2211
+ }
2212
+ const end = Math.floor(entry.end);
2213
+ if (end < start) {
2214
+ return { error: `range end (${end}) must be >= start (${start})` };
2215
+ }
2216
+ if (totalSize !== void 0 && end >= totalSize) {
2217
+ return { error: `end byte ${end} is beyond totalSize (${totalSize})` };
2218
+ }
2219
+ const byteLength = end - start + 1;
2220
+ parsed.push({
2221
+ spec: `${start}-${end}`,
2222
+ start,
2223
+ end,
2224
+ suffixLength: null,
2225
+ byteLength,
2226
+ percentOfTotal: totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
2227
+ });
2228
+ } else {
2229
+ const byteLength = totalSize !== void 0 ? totalSize - start : null;
2230
+ parsed.push({
2231
+ spec: `${start}-`,
2232
+ start,
2233
+ end: null,
2234
+ suffixLength: null,
2235
+ byteLength,
2236
+ percentOfTotal: byteLength !== null && totalSize !== void 0 ? _round2(byteLength / totalSize * 100) : null
2237
+ });
2238
+ }
2239
+ }
2240
+ const warnings = [];
2241
+ const resolvable = parsed.map((r, i) => ({ i, start: r.start ?? (totalSize !== void 0 && r.suffixLength !== null ? totalSize - Math.min(r.suffixLength, totalSize) : null), end: r.end ?? (totalSize !== void 0 ? totalSize - 1 : null) })).filter((r) => r.start !== null && r.end !== null).sort((a, b) => a.start - b.start);
2242
+ for (let i = 1; i < resolvable.length; i++) {
2243
+ if (resolvable[i].start <= resolvable[i - 1].end) {
2244
+ warnings.push(`ranges "${parsed[resolvable[i - 1].i].spec}" and "${parsed[resolvable[i].i].spec}" overlap - servers may reject overlapping multi-range requests`);
2245
+ }
2246
+ }
2247
+ if (parsed.length > 1 && parsed.some((r) => r.byteLength === null)) {
2248
+ warnings.push("totalSize was not provided, so open-ended ranges cannot be checked for overlap or total byte count");
2249
+ }
2250
+ const totalBytesRequested = parsed.every((r) => r.byteLength !== null) ? parsed.reduce((sum, r) => sum + (r.byteLength ?? 0), 0) : null;
2251
+ const headerValue = `${unit}=${parsed.map((r) => r.spec).join(",")}`;
2252
+ return {
2253
+ header: `Range: ${headerValue}`,
2254
+ headerValue,
2255
+ ranges: parsed,
2256
+ totalBytesRequested,
2257
+ warnings
2258
+ };
2259
+ }
2260
+ function parseContentRangeHeader(header) {
2261
+ if (!header || header.trim() === "") return { error: "Input is empty" };
2262
+ const match = header.trim().match(/^(\S+)\s+(\*|\d+-\d+)\/(\*|\d+)$/);
2263
+ if (!match) {
2264
+ return { error: 'Could not parse Content-Range header. Expected a format like "bytes 200-1000/67589" or "bytes */67589"' };
2265
+ }
2266
+ const [, unit, range, totalRaw] = match;
2267
+ const isUnsatisfiable = range === "*";
2268
+ const isTotalUnknown = totalRaw === "*";
2269
+ const total = isTotalUnknown ? null : Number(totalRaw);
2270
+ if (isUnsatisfiable) {
2271
+ return { unit, start: null, end: null, total, isUnsatisfiable, isTotalUnknown, byteLength: null };
2272
+ }
2273
+ const [startRaw, endRaw] = range.split("-");
2274
+ const start = Number(startRaw);
2275
+ const end = Number(endRaw);
2276
+ if (end < start) {
2277
+ return { error: `Invalid range: end (${end}) is before start (${start})` };
2278
+ }
2279
+ return { unit, start, end, total, isUnsatisfiable, isTotalUnknown, byteLength: end - start + 1 };
2280
+ }
2168
2281
 
2169
2282
  exports.DNS_RECORD_TYPES = DNS_RECORD_TYPES;
2170
2283
  exports.HTTP_HEADERS = HTTP_HEADERS;
@@ -2177,6 +2290,7 @@ exports.buildDnsQueryUrl = buildDnsQueryUrl;
2177
2290
  exports.buildGeoUrl = buildGeoUrl;
2178
2291
  exports.buildLinkHeader = buildLinkHeader;
2179
2292
  exports.buildMapUrl = buildMapUrl;
2293
+ exports.buildRangeHeader = buildRangeHeader;
2180
2294
  exports.buildReferrerPolicy = buildReferrerPolicy;
2181
2295
  exports.checkSetCookieHeader = checkSetCookieHeader;
2182
2296
  exports.countryCodeToFlag = countryCodeToFlag;
@@ -2193,6 +2307,7 @@ exports.isSuccess = isSuccess;
2193
2307
  exports.isValidIp = isValidIp;
2194
2308
  exports.isValidIpv4 = isValidIpv4;
2195
2309
  exports.isValidIpv6 = isValidIpv6;
2310
+ exports.parseContentRangeHeader = parseContentRangeHeader;
2196
2311
  exports.parseDnsResponse = parseDnsResponse;
2197
2312
  exports.parseGeoResponse = parseGeoResponse;
2198
2313
  exports.parseHar = parseHar;
@@ -1 +1 @@
1
- export { A as AuthResultEntry, C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, c as CookieAttributes, d as CookieCheckResult, D as DNS_RECORD_TYPES, e as DnsRecord, f as DnsRecordType, g as DnsResponse, E as EmailHeaderAnalysis, h as EmailHeaderField, G as GeoResult, H as HTTP_HEADERS, i as HarEntry, j as HarParseResult, k as HarSummary, l as HeaderCategory, m as HttpHeader, I as Ipv6AddressType, o as Ipv6ParseResult, L as LINK_REL_VALUES, p as LinkHeaderEntry, q as LinkHeaderEntryInput, r as LinkHeaderResult, s as LinkRel, P as ParsedDnsResult, t as ParsedGeoResult, R as REFERRER_POLICY_VALUES, u as ReceivedHop, v as ReferrerPolicyEntry, w as ReferrerPolicyResult, x as ReferrerPolicyValue, y as RobotsGroup, z as RobotsIssue, B as RobotsRule, F as RobotsValidationResult, S as STATUS_CODES, J as SameSiteValue, K as SitemapIndexEntry, M as SitemapIssue, N as SitemapUrlEntry, O as SitemapValidationResult, Q as StatusCode, U as UaDeviceType, T as UserAgentInfo, V as analyzeEmailHeaders, W as buildCacheControl, X as buildDnsQueryUrl, Y as buildGeoUrl, Z as buildLinkHeader, _ as buildMapUrl, $ as buildReferrerPolicy, a0 as checkSetCookieHeader, a1 as countryCodeToFlag, a2 as formatCoordinates, a3 as formatTtl, a4 as getByCategory, a5 as getHeader, a6 as getHeadersByCategory, a7 as getStatusByCategory, a8 as getStatusCode, a9 as isClientError, aa as isServerError, ab as isSuccess, ac as isValidIp, ad as isValidIpv4, ae as isValidIpv6, af as parseDnsResponse, ag as parseGeoResponse, ah as parseHar, ai as parseIpv6Address, aj as parseUserAgent, ak as searchHeaders, al as searchStatusCodes, am as statusCodeToText, an as typeNumberToLabel, ao as validateDomain, ap as validateHeaderName, aq as validateHeaderValue, ar as validateRobotsTxt, as as validateSitemap } from '../network-CKPoesdD.cjs';
1
+ export { A as AuthResultEntry, B as BuildRangeHeaderOptions, C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, c as ContentRangeResult, d as CookieAttributes, e as CookieCheckResult, D as DNS_RECORD_TYPES, f as DnsRecord, g as DnsRecordType, h as DnsResponse, E as EmailHeaderAnalysis, i as EmailHeaderField, G as GeoResult, H as HTTP_HEADERS, j as HarEntry, k as HarParseResult, l as HarSummary, m as HeaderCategory, o as HttpHeader, I as Ipv6AddressType, p as Ipv6ParseResult, L as LINK_REL_VALUES, q as LinkHeaderEntry, r as LinkHeaderEntryInput, s as LinkHeaderResult, t as LinkRel, P as ParsedDnsResult, u as ParsedGeoResult, R as REFERRER_POLICY_VALUES, v as RangeEntry, w as RangeEntryInput, x as RangeHeaderResult, y as ReceivedHop, z as ReferrerPolicyEntry, F as ReferrerPolicyResult, J as ReferrerPolicyValue, K as RobotsGroup, M as RobotsIssue, N as RobotsRule, O as RobotsValidationResult, S as STATUS_CODES, Q as SameSiteValue, T as SitemapIndexEntry, U as SitemapIssue, V as SitemapUrlEntry, W as SitemapValidationResult, X as StatusCode, Y as UaDeviceType, Z as UserAgentInfo, _ as analyzeEmailHeaders, $ as buildCacheControl, a0 as buildDnsQueryUrl, a1 as buildGeoUrl, a2 as buildLinkHeader, a3 as buildMapUrl, a4 as buildRangeHeader, a5 as buildReferrerPolicy, a6 as checkSetCookieHeader, a7 as countryCodeToFlag, a8 as formatCoordinates, a9 as formatTtl, aa as getByCategory, ab as getHeader, ac as getHeadersByCategory, ad as getStatusByCategory, ae as getStatusCode, af as isClientError, ag as isServerError, ah as isSuccess, ai as isValidIp, aj as isValidIpv4, ak as isValidIpv6, al as parseContentRangeHeader, am as parseDnsResponse, an as parseGeoResponse, ao as parseHar, ap as parseIpv6Address, aq as parseUserAgent, ar as searchHeaders, as as searchStatusCodes, at as statusCodeToText, au as typeNumberToLabel, av as validateDomain, aw as validateHeaderName, ax as validateHeaderValue, ay as validateRobotsTxt, az as validateSitemap } from '../network-BC8McQOh.cjs';
@@ -1 +1 @@
1
- export { A as AuthResultEntry, C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, c as CookieAttributes, d as CookieCheckResult, D as DNS_RECORD_TYPES, e as DnsRecord, f as DnsRecordType, g as DnsResponse, E as EmailHeaderAnalysis, h as EmailHeaderField, G as GeoResult, H as HTTP_HEADERS, i as HarEntry, j as HarParseResult, k as HarSummary, l as HeaderCategory, m as HttpHeader, I as Ipv6AddressType, o as Ipv6ParseResult, L as LINK_REL_VALUES, p as LinkHeaderEntry, q as LinkHeaderEntryInput, r as LinkHeaderResult, s as LinkRel, P as ParsedDnsResult, t as ParsedGeoResult, R as REFERRER_POLICY_VALUES, u as ReceivedHop, v as ReferrerPolicyEntry, w as ReferrerPolicyResult, x as ReferrerPolicyValue, y as RobotsGroup, z as RobotsIssue, B as RobotsRule, F as RobotsValidationResult, S as STATUS_CODES, J as SameSiteValue, K as SitemapIndexEntry, M as SitemapIssue, N as SitemapUrlEntry, O as SitemapValidationResult, Q as StatusCode, U as UaDeviceType, T as UserAgentInfo, V as analyzeEmailHeaders, W as buildCacheControl, X as buildDnsQueryUrl, Y as buildGeoUrl, Z as buildLinkHeader, _ as buildMapUrl, $ as buildReferrerPolicy, a0 as checkSetCookieHeader, a1 as countryCodeToFlag, a2 as formatCoordinates, a3 as formatTtl, a4 as getByCategory, a5 as getHeader, a6 as getHeadersByCategory, a7 as getStatusByCategory, a8 as getStatusCode, a9 as isClientError, aa as isServerError, ab as isSuccess, ac as isValidIp, ad as isValidIpv4, ae as isValidIpv6, af as parseDnsResponse, ag as parseGeoResponse, ah as parseHar, ai as parseIpv6Address, aj as parseUserAgent, ak as searchHeaders, al as searchStatusCodes, am as statusCodeToText, an as typeNumberToLabel, ao as validateDomain, ap as validateHeaderName, aq as validateHeaderValue, ar as validateRobotsTxt, as as validateSitemap } from '../network-CKPoesdD.js';
1
+ export { A as AuthResultEntry, B as BuildRangeHeaderOptions, C as CacheControlDirective, a as CacheControlOptions, b as CacheControlResult, c as ContentRangeResult, d as CookieAttributes, e as CookieCheckResult, D as DNS_RECORD_TYPES, f as DnsRecord, g as DnsRecordType, h as DnsResponse, E as EmailHeaderAnalysis, i as EmailHeaderField, G as GeoResult, H as HTTP_HEADERS, j as HarEntry, k as HarParseResult, l as HarSummary, m as HeaderCategory, o as HttpHeader, I as Ipv6AddressType, p as Ipv6ParseResult, L as LINK_REL_VALUES, q as LinkHeaderEntry, r as LinkHeaderEntryInput, s as LinkHeaderResult, t as LinkRel, P as ParsedDnsResult, u as ParsedGeoResult, R as REFERRER_POLICY_VALUES, v as RangeEntry, w as RangeEntryInput, x as RangeHeaderResult, y as ReceivedHop, z as ReferrerPolicyEntry, F as ReferrerPolicyResult, J as ReferrerPolicyValue, K as RobotsGroup, M as RobotsIssue, N as RobotsRule, O as RobotsValidationResult, S as STATUS_CODES, Q as SameSiteValue, T as SitemapIndexEntry, U as SitemapIssue, V as SitemapUrlEntry, W as SitemapValidationResult, X as StatusCode, Y as UaDeviceType, Z as UserAgentInfo, _ as analyzeEmailHeaders, $ as buildCacheControl, a0 as buildDnsQueryUrl, a1 as buildGeoUrl, a2 as buildLinkHeader, a3 as buildMapUrl, a4 as buildRangeHeader, a5 as buildReferrerPolicy, a6 as checkSetCookieHeader, a7 as countryCodeToFlag, a8 as formatCoordinates, a9 as formatTtl, aa as getByCategory, ab as getHeader, ac as getHeadersByCategory, ad as getStatusByCategory, ae as getStatusCode, af as isClientError, ag as isServerError, ah as isSuccess, ai as isValidIp, aj as isValidIpv4, ak as isValidIpv6, al as parseContentRangeHeader, am as parseDnsResponse, an as parseGeoResponse, ao as parseHar, ap as parseIpv6Address, aq as parseUserAgent, ar as searchHeaders, as as searchStatusCodes, at as statusCodeToText, au as typeNumberToLabel, av as validateDomain, aw as validateHeaderName, ax as validateHeaderValue, ay as validateRobotsTxt, az as validateSitemap } from '../network-BC8McQOh.js';
@@ -1,2 +1,2 @@
1
- export { DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, REFERRER_POLICY_VALUES, STATUS_CODES, analyzeEmailHeaders, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildReferrerPolicy, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parseUserAgent, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateRobotsTxt, validateSitemap } from '../chunk-Y4BVU76A.js';
1
+ export { DNS_RECORD_TYPES, HTTP_HEADERS, LINK_REL_VALUES, REFERRER_POLICY_VALUES, STATUS_CODES, analyzeEmailHeaders, buildCacheControl, buildDnsQueryUrl, buildGeoUrl, buildLinkHeader, buildMapUrl, buildRangeHeader, buildReferrerPolicy, checkSetCookieHeader, countryCodeToFlag, formatCoordinates, formatTtl, getByCategory, getHeader, getHeadersByCategory, getStatusByCategory, getStatusCode, isClientError, isServerError, isSuccess, isValidIp, isValidIpv4, isValidIpv6, parseContentRangeHeader, parseDnsResponse, parseGeoResponse, parseHar, parseIpv6Address, parseUserAgent, searchHeaders, searchStatusCodes, statusCodeToText, typeNumberToLabel, validateDomain, validateHeaderName, validateHeaderValue, validateRobotsTxt, validateSitemap } from '../chunk-7WSFJTYP.js';
2
2
  import '../chunk-MLKGABMK.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utilix-tech/sdk",
3
- "version": "0.40.0",
3
+ "version": "0.41.0",
4
4
  "description": "154+ developer utility tools for Node.js: JSON, encoding, hashing, color, CSS, network and more. Runs locally, no API key required.",
5
5
  "author": "Utilix <hello@utilix.tech>",
6
6
  "license": "MIT",