@utilix-tech/sdk 0.27.0 → 0.29.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/dist/index.cjs CHANGED
@@ -8833,6 +8833,7 @@ __export(network_exports, {
8833
8833
  parseDnsResponse: () => parseDnsResponse,
8834
8834
  parseGeoResponse: () => parseGeoResponse,
8835
8835
  parseHar: () => parseHar,
8836
+ parseIpv6Address: () => parseIpv6Address,
8836
8837
  parseUserAgent: () => parseUserAgent,
8837
8838
  searchHeaders: () => searchHeaders,
8838
8839
  searchStatusCodes: () => searchStatusCodes,
@@ -10620,6 +10621,94 @@ function buildCacheControl(options = {}) {
10620
10621
  const snippet = `Cache-Control: ${header}`;
10621
10622
  return { header, headerName: "Cache-Control", snippet, directives, warnings };
10622
10623
  }
10624
+ function isValidIpv6HexGroup(g) {
10625
+ return /^[0-9a-fA-F]{1,4}$/.test(g);
10626
+ }
10627
+ function isValidIpv6Ipv4Quad(quad) {
10628
+ const parts = quad.split(".");
10629
+ if (parts.length !== 4) return false;
10630
+ return parts.every((p) => /^\d{1,3}$/.test(p) && Number(p) <= 255);
10631
+ }
10632
+ function classifyIpv6(groups) {
10633
+ const first = parseInt(groups[0], 16);
10634
+ if (groups.every((g) => g === "0000")) return "unspecified";
10635
+ if (groups.slice(0, 7).every((g) => g === "0000") && groups[7] === "0001") return "loopback";
10636
+ if (groups.slice(0, 4).every((g) => g === "0000") && groups[4] === "0000" && groups[5] === "ffff") return "ipv4-mapped";
10637
+ if (groups[0] === "2001" && groups[1] === "0db8") return "documentation";
10638
+ if ((first & 65280) === 65280) return "multicast";
10639
+ if ((first & 65472) === 65152) return "link-local";
10640
+ if ((first & 65024) === 64512) return "unique-local";
10641
+ return "global-unicast";
10642
+ }
10643
+ function compressIpv6Groups(groups) {
10644
+ const short = groups.map((g) => g.replace(/^0+(?=.)/, ""));
10645
+ let bestStart = -1;
10646
+ let bestLen = 0;
10647
+ let curStart = -1;
10648
+ let curLen = 0;
10649
+ for (let i = 0; i < short.length; i++) {
10650
+ if (short[i] === "0") {
10651
+ if (curStart === -1) curStart = i;
10652
+ curLen++;
10653
+ if (curLen > bestLen) {
10654
+ bestLen = curLen;
10655
+ bestStart = curStart;
10656
+ }
10657
+ } else {
10658
+ curStart = -1;
10659
+ curLen = 0;
10660
+ }
10661
+ }
10662
+ if (bestLen < 2) return short.join(":");
10663
+ const before = short.slice(0, bestStart).join(":");
10664
+ const after = short.slice(bestStart + bestLen).join(":");
10665
+ return `${before}::${after}`;
10666
+ }
10667
+ function parseIpv6Address(input) {
10668
+ let s = input.trim();
10669
+ if (s.startsWith("[") && s.includes("]")) s = s.slice(1, s.indexOf("]"));
10670
+ let zoneId = null;
10671
+ const pctIdx = s.indexOf("%");
10672
+ if (pctIdx !== -1) {
10673
+ zoneId = s.slice(pctIdx + 1);
10674
+ s = s.slice(0, pctIdx);
10675
+ }
10676
+ if (!s) return { error: "Empty address" };
10677
+ const doubleColonCount = (s.match(/::/g) ?? []).length;
10678
+ if (doubleColonCount > 1) return { error: 'Address contains more than one "::"' };
10679
+ const ipv4Match = s.match(/(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
10680
+ if (ipv4Match) {
10681
+ const quad = ipv4Match[1];
10682
+ if (!isValidIpv6Ipv4Quad(quad)) return { error: `Invalid embedded IPv4 address: ${quad}` };
10683
+ const parts = quad.split(".").map(Number);
10684
+ const hi = (parts[0] << 8 | parts[1]).toString(16);
10685
+ const lo = (parts[2] << 8 | parts[3]).toString(16);
10686
+ s = s.slice(0, s.length - quad.length) + `${hi}:${lo}`;
10687
+ }
10688
+ let groups;
10689
+ if (s.includes("::")) {
10690
+ const [left, right] = s.split("::");
10691
+ const leftGroups = left ? left.split(":") : [];
10692
+ const rightGroups = right ? right.split(":") : [];
10693
+ const missing = 8 - (leftGroups.length + rightGroups.length);
10694
+ if (missing < 1) return { error: 'The "::" shorthand must represent at least one group of zeros' };
10695
+ if (![...leftGroups, ...rightGroups].every(isValidIpv6HexGroup)) return { error: "Invalid hex group in address" };
10696
+ groups = [...leftGroups, ...Array(missing).fill("0"), ...rightGroups];
10697
+ } else {
10698
+ groups = s.split(":");
10699
+ if (groups.length !== 8) return { error: `Expected 8 groups, got ${groups.length}` };
10700
+ if (!groups.every(isValidIpv6HexGroup)) return { error: "Invalid hex group in address" };
10701
+ }
10702
+ const expandedGroups = groups.map((g) => g.padStart(4, "0").toLowerCase());
10703
+ const suffix = zoneId ? `%${zoneId}` : "";
10704
+ return {
10705
+ expanded: expandedGroups.join(":") + suffix,
10706
+ compressed: compressIpv6Groups(expandedGroups) + suffix,
10707
+ groups: expandedGroups,
10708
+ zoneId,
10709
+ addressType: classifyIpv6(expandedGroups)
10710
+ };
10711
+ }
10623
10712
 
10624
10713
  // src/tools/api.ts
10625
10714
  var api_exports = {};
@@ -19237,6 +19326,8 @@ __export(media_exports, {
19237
19326
  readId3Tags: () => readId3Tags,
19238
19327
  readImageInfo: () => readImageInfo,
19239
19328
  readPdfMetadata: () => readPdfMetadata,
19329
+ readPdfPageDimensions: () => readPdfPageDimensions,
19330
+ readVideoInfo: () => readVideoInfo,
19240
19331
  readWavInfo: () => readWavInfo
19241
19332
  });
19242
19333
  function readU32BE(bytes, offset) {
@@ -19695,6 +19786,116 @@ function readPdfMetadata(bytes) {
19695
19786
  encrypted
19696
19787
  };
19697
19788
  }
19789
+ var PDF_COMMON_PAPER_SIZES = [
19790
+ { name: "Letter", widthPt: 612, heightPt: 792 },
19791
+ { name: "Legal", widthPt: 612, heightPt: 1008 },
19792
+ { name: "Tabloid", widthPt: 792, heightPt: 1224 },
19793
+ { name: "A3", widthPt: 842, heightPt: 1191 },
19794
+ { name: "A4", widthPt: 595, heightPt: 842 },
19795
+ { name: "A5", widthPt: 420, heightPt: 595 },
19796
+ { name: "B5", widthPt: 499, heightPt: 709 }
19797
+ ];
19798
+ function matchPaperSize(widthPt, heightPt) {
19799
+ for (const size of PDF_COMMON_PAPER_SIZES) {
19800
+ const w = Math.abs(widthPt - size.widthPt) <= 1;
19801
+ const h = Math.abs(heightPt - size.heightPt) <= 1;
19802
+ const wSwapped = Math.abs(widthPt - size.heightPt) <= 1;
19803
+ const hSwapped = Math.abs(heightPt - size.widthPt) <= 1;
19804
+ if (w && h || wSwapped && hSwapped) return size.name;
19805
+ }
19806
+ return null;
19807
+ }
19808
+ function parsePdfMediaBox(dict) {
19809
+ const m = dict.match(/\/MediaBox\s*\[\s*(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s*\]/);
19810
+ if (!m) return null;
19811
+ return [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];
19812
+ }
19813
+ function parsePdfRotate(dict) {
19814
+ const m = dict.match(/\/Rotate\s+(-?\d+)/);
19815
+ return m ? Number(m[1]) : null;
19816
+ }
19817
+ function buildPdfPageDimension(pageNumber, mediaBox, rotate) {
19818
+ const rotation = (rotate % 360 + 360) % 360;
19819
+ if (!mediaBox) {
19820
+ return { pageNumber, widthPt: null, heightPt: null, widthIn: null, heightIn: null, rotation, orientation: null, paperSize: null };
19821
+ }
19822
+ const [llx, lly, urx, ury] = mediaBox;
19823
+ let widthPt = Math.abs(urx - llx);
19824
+ let heightPt = Math.abs(ury - lly);
19825
+ if (rotation === 90 || rotation === 270) [widthPt, heightPt] = [heightPt, widthPt];
19826
+ const orientation = widthPt === heightPt ? "square" : widthPt > heightPt ? "landscape" : "portrait";
19827
+ return {
19828
+ pageNumber,
19829
+ widthPt: round22(widthPt),
19830
+ heightPt: round22(heightPt),
19831
+ widthIn: round22(widthPt / 72),
19832
+ heightIn: round22(heightPt / 72),
19833
+ rotation,
19834
+ orientation,
19835
+ paperSize: matchPaperSize(widthPt, heightPt)
19836
+ };
19837
+ }
19838
+ function walkPdfPageTree(objMap, nodeBody, inherited, visited, nodeKey, out) {
19839
+ if (visited.has(nodeKey)) return;
19840
+ visited.add(nodeKey);
19841
+ const mediaBox = parsePdfMediaBox(nodeBody) ?? inherited.mediaBox;
19842
+ const rotateMatch = parsePdfRotate(nodeBody);
19843
+ const rotate = rotateMatch !== null ? rotateMatch : inherited.rotate;
19844
+ if (/\/Type\s*\/Page(?!s)\b/.test(nodeBody)) {
19845
+ out.push(buildPdfPageDimension(out.length + 1, mediaBox, rotate));
19846
+ return;
19847
+ }
19848
+ const kidsMatch = nodeBody.match(/\/Kids\s*\[([^\]]*)\]/);
19849
+ if (!kidsMatch) return;
19850
+ const kidRefs = [...kidsMatch[1].matchAll(/(\d+)\s+(\d+)\s+R/g)];
19851
+ for (const ref of kidRefs) {
19852
+ const key = `${ref[1]} ${ref[2]}`;
19853
+ const body = objMap.get(key);
19854
+ if (body) walkPdfPageTree(objMap, body, { mediaBox, rotate }, visited, key, out);
19855
+ }
19856
+ }
19857
+ function readPdfPageDimensions(bytes) {
19858
+ if (bytes.length < 8) return { error: "File too small to be a PDF" };
19859
+ const header = bytesToLatin1(bytes.subarray(0, 16));
19860
+ const versionMatch = header.match(/%PDF-(\d\.\d)/);
19861
+ if (!versionMatch) return { error: "Not a valid PDF file (missing %PDF header)" };
19862
+ const version2 = versionMatch[1];
19863
+ const text = bytesToLatin1(bytes);
19864
+ const objBlocks = [...text.matchAll(/(\d+)\s+(\d+)\s+obj([\s\S]*?)endobj/g)];
19865
+ const objMap = /* @__PURE__ */ new Map();
19866
+ for (const b of objBlocks) objMap.set(`${b[1]} ${b[2]}`, b[3]);
19867
+ const out = [];
19868
+ const visited = /* @__PURE__ */ new Set();
19869
+ let pagesRootBody = null;
19870
+ const trailerMatches = [...text.matchAll(/trailer\s*<<([\s\S]*?)>>/g)];
19871
+ if (trailerMatches.length > 0) {
19872
+ const trailer = trailerMatches[trailerMatches.length - 1][1];
19873
+ const rootRef = trailer.match(/\/Root\s+(\d+)\s+(\d+)\s+R/);
19874
+ if (rootRef) {
19875
+ const catalogBody = objMap.get(`${rootRef[1]} ${rootRef[2]}`);
19876
+ const pagesRef = catalogBody?.match(/\/Pages\s+(\d+)\s+(\d+)\s+R/);
19877
+ if (pagesRef) pagesRootBody = objMap.get(`${pagesRef[1]} ${pagesRef[2]}`) ?? null;
19878
+ }
19879
+ }
19880
+ if (!pagesRootBody) {
19881
+ for (const b of objBlocks) {
19882
+ if (/\/Type\s*\/Pages\b/.test(b[3]) && !/\/Parent\s+\d+\s+\d+\s+R/.test(b[3])) {
19883
+ pagesRootBody = b[3];
19884
+ break;
19885
+ }
19886
+ }
19887
+ }
19888
+ if (pagesRootBody) walkPdfPageTree(objMap, pagesRootBody, { mediaBox: null, rotate: 0 }, visited, "root", out);
19889
+ if (out.length === 0) {
19890
+ for (const b of objBlocks) {
19891
+ if (/\/Type\s*\/Page(?!s)\b/.test(b[3])) {
19892
+ out.push(buildPdfPageDimension(out.length + 1, parsePdfMediaBox(b[3]), parsePdfRotate(b[3]) ?? 0));
19893
+ }
19894
+ }
19895
+ }
19896
+ if (out.length === 0) return { error: "Could not locate any page objects in this PDF" };
19897
+ return { version: version2, pageCount: out.length, pages: out };
19898
+ }
19698
19899
  var AUDIO_FORMAT_LABELS = {
19699
19900
  1: "PCM",
19700
19901
  3: "IEEE float",
@@ -20088,6 +20289,254 @@ function readFlacInfo(bytes) {
20088
20289
  }
20089
20290
  return result;
20090
20291
  }
20292
+ function readU64BE(bytes, offset) {
20293
+ return readU32BE(bytes, offset) * 4294967296 + readU32BE(bytes, offset + 4);
20294
+ }
20295
+ function readMp4Boxes(bytes, start, end) {
20296
+ const boxes = [];
20297
+ let offset = start;
20298
+ while (offset + 8 <= end) {
20299
+ let size = readU32BE(bytes, offset);
20300
+ const type = readAscii4(bytes, offset + 4);
20301
+ let headerSize = 8;
20302
+ if (size === 1) {
20303
+ if (offset + 16 > end) break;
20304
+ size = readU64BE(bytes, offset + 8);
20305
+ headerSize = 16;
20306
+ } else if (size === 0) {
20307
+ size = end - offset;
20308
+ }
20309
+ if (size < headerSize || offset + size > end) break;
20310
+ boxes.push({ type, start: offset + headerSize, end: offset + size });
20311
+ offset += size;
20312
+ }
20313
+ return boxes;
20314
+ }
20315
+ function findMp4Box(boxes, type) {
20316
+ return boxes.find((b) => b.type === type);
20317
+ }
20318
+ function parseMp4Mvhd(bytes, box) {
20319
+ const o = box.start;
20320
+ if (o >= box.end) return null;
20321
+ const version2 = bytes[o];
20322
+ if (version2 === 1) {
20323
+ if (o + 32 > box.end) return null;
20324
+ return { timescale: readU32BE(bytes, o + 20), duration: readU64BE(bytes, o + 24) };
20325
+ }
20326
+ if (o + 20 > box.end) return null;
20327
+ return { timescale: readU32BE(bytes, o + 12), duration: readU32BE(bytes, o + 16) };
20328
+ }
20329
+ function parseMp4Tkhd(bytes, box) {
20330
+ const o = box.start;
20331
+ if (o >= box.end) return null;
20332
+ const version2 = bytes[o];
20333
+ const fixedFieldsSize = version2 === 1 ? 4 + 8 + 8 + 4 + 4 + 8 : 4 + 4 + 4 + 4 + 4 + 4;
20334
+ const afterDuration = o + fixedFieldsSize;
20335
+ const matrixStart = afterDuration + 8 + 2 + 2 + 2 + 2;
20336
+ const widthOffset = matrixStart + 36;
20337
+ if (widthOffset + 8 > box.end) return null;
20338
+ return { width: readU32BE(bytes, widthOffset) / 65536, height: readU32BE(bytes, widthOffset + 4) / 65536 };
20339
+ }
20340
+ function parseMp4Hdlr(bytes, box) {
20341
+ const o = box.start;
20342
+ if (o + 12 > box.end) return null;
20343
+ return readAscii4(bytes, o + 8);
20344
+ }
20345
+ function parseMp4StsdCodec(bytes, box) {
20346
+ const o = box.start;
20347
+ if (o + 8 > box.end) return null;
20348
+ const entryCount = readU32BE(bytes, o + 4);
20349
+ if (entryCount < 1) return null;
20350
+ const entryStart = o + 8;
20351
+ if (entryStart + 8 > box.end) return null;
20352
+ return readAscii4(bytes, entryStart + 4);
20353
+ }
20354
+ function parseMp4StsdVideoDims(bytes, box) {
20355
+ const o = box.start;
20356
+ if (o + 8 > box.end) return null;
20357
+ const entryCount = readU32BE(bytes, o + 4);
20358
+ if (entryCount < 1) return null;
20359
+ const entryStart = o + 8;
20360
+ if (entryStart + 36 > box.end) return null;
20361
+ return {
20362
+ width: bytes[entryStart + 32] << 8 | bytes[entryStart + 33],
20363
+ height: bytes[entryStart + 34] << 8 | bytes[entryStart + 35]
20364
+ };
20365
+ }
20366
+ function parseMp4(bytes) {
20367
+ const topBoxes = readMp4Boxes(bytes, 0, bytes.length);
20368
+ const ftyp = findMp4Box(topBoxes, "ftyp");
20369
+ const moov = findMp4Box(topBoxes, "moov");
20370
+ if (!moov) return { error: "No moov box found (not a valid or fully-downloaded MP4 file)" };
20371
+ const result = { format: "mp4" };
20372
+ if (ftyp && ftyp.start + 4 <= ftyp.end) result.majorBrand = readAscii4(bytes, ftyp.start);
20373
+ const moovBoxes = readMp4Boxes(bytes, moov.start, moov.end);
20374
+ const mvhd = findMp4Box(moovBoxes, "mvhd");
20375
+ if (mvhd) {
20376
+ const info = parseMp4Mvhd(bytes, mvhd);
20377
+ if (info && info.timescale > 0) result.durationSeconds = Math.round(info.duration / info.timescale * 1e3) / 1e3;
20378
+ }
20379
+ for (const trak of moovBoxes.filter((b) => b.type === "trak")) {
20380
+ const trakBoxes = readMp4Boxes(bytes, trak.start, trak.end);
20381
+ const mdia = findMp4Box(trakBoxes, "mdia");
20382
+ if (!mdia) continue;
20383
+ const mdiaBoxes = readMp4Boxes(bytes, mdia.start, mdia.end);
20384
+ const hdlr = findMp4Box(mdiaBoxes, "hdlr");
20385
+ const handlerType = hdlr ? parseMp4Hdlr(bytes, hdlr) : null;
20386
+ const minf = findMp4Box(mdiaBoxes, "minf");
20387
+ if (!minf) continue;
20388
+ const stbl = findMp4Box(readMp4Boxes(bytes, minf.start, minf.end), "stbl");
20389
+ if (!stbl) continue;
20390
+ const stsd = findMp4Box(readMp4Boxes(bytes, stbl.start, stbl.end), "stsd");
20391
+ const codec = stsd ? parseMp4StsdCodec(bytes, stsd) : null;
20392
+ if (handlerType === "vide") {
20393
+ if (codec) result.videoCodec = codec;
20394
+ const tkhd = findMp4Box(trakBoxes, "tkhd");
20395
+ const dims = tkhd ? parseMp4Tkhd(bytes, tkhd) : null;
20396
+ if (dims && dims.width > 0 && dims.height > 0) {
20397
+ result.width = Math.round(dims.width);
20398
+ result.height = Math.round(dims.height);
20399
+ } else if (stsd) {
20400
+ const pixelDims = parseMp4StsdVideoDims(bytes, stsd);
20401
+ if (pixelDims && pixelDims.width > 0 && pixelDims.height > 0) {
20402
+ result.width = pixelDims.width;
20403
+ result.height = pixelDims.height;
20404
+ }
20405
+ }
20406
+ } else if (handlerType === "soun") {
20407
+ if (codec) result.audioCodec = codec;
20408
+ }
20409
+ }
20410
+ if (result.durationSeconds === void 0 && !result.videoCodec && !result.audioCodec) {
20411
+ return { error: "Could not find any usable track metadata in this MP4 file's moov box" };
20412
+ }
20413
+ return result;
20414
+ }
20415
+ function ebmlVintLength(firstByte) {
20416
+ if (firstByte === 0) return 0;
20417
+ let mask = 128;
20418
+ let length = 1;
20419
+ while (length <= 8 && (firstByte & mask) === 0) {
20420
+ mask >>= 1;
20421
+ length++;
20422
+ }
20423
+ return length;
20424
+ }
20425
+ function readEbmlId(bytes, offset) {
20426
+ if (offset >= bytes.length) return null;
20427
+ const length = ebmlVintLength(bytes[offset]);
20428
+ if (length === 0 || offset + length > bytes.length) return null;
20429
+ let id = 0;
20430
+ for (let i = 0; i < length; i++) id = id * 256 + bytes[offset + i];
20431
+ return { id, length };
20432
+ }
20433
+ function readEbmlSize(bytes, offset) {
20434
+ if (offset >= bytes.length) return null;
20435
+ const length = ebmlVintLength(bytes[offset]);
20436
+ if (length === 0 || offset + length > bytes.length) return null;
20437
+ const mask = 255 >> length;
20438
+ let value = bytes[offset] & mask;
20439
+ let allOnes = value === mask;
20440
+ for (let i = 1; i < length; i++) {
20441
+ value = value * 256 + bytes[offset + i];
20442
+ if (bytes[offset + i] !== 255) allOnes = false;
20443
+ }
20444
+ return { value, length, unknown: allOnes };
20445
+ }
20446
+ function readEbmlUint(bytes, offset, length) {
20447
+ let value = 0;
20448
+ for (let i = 0; i < length; i++) value = value * 256 + bytes[offset + i];
20449
+ return value;
20450
+ }
20451
+ function readEbmlFloat(bytes, offset, length) {
20452
+ if (offset + length > bytes.length) return 0;
20453
+ const view = new DataView(bytes.buffer, bytes.byteOffset + offset, length);
20454
+ if (length === 4) return view.getFloat32(0, false);
20455
+ if (length === 8) return view.getFloat64(0, false);
20456
+ return 0;
20457
+ }
20458
+ function ebmlChildren(bytes, start, end) {
20459
+ const children = [];
20460
+ let offset = start;
20461
+ while (offset < end) {
20462
+ const idInfo = readEbmlId(bytes, offset);
20463
+ if (!idInfo) break;
20464
+ const sizeInfo = readEbmlSize(bytes, offset + idInfo.length);
20465
+ if (!sizeInfo) break;
20466
+ const dataStart = offset + idInfo.length + sizeInfo.length;
20467
+ const dataEnd = sizeInfo.unknown ? end : Math.min(dataStart + sizeInfo.value, end);
20468
+ children.push({ id: idInfo.id, dataStart, dataEnd });
20469
+ offset = dataEnd;
20470
+ }
20471
+ return children;
20472
+ }
20473
+ var EBML_ID_SEGMENT = 408125543;
20474
+ var EBML_ID_INFO = 357149030;
20475
+ var EBML_ID_TIMECODE_SCALE = 2807729;
20476
+ var EBML_ID_DURATION = 17545;
20477
+ var EBML_ID_TRACKS = 374648427;
20478
+ var EBML_ID_TRACK_ENTRY = 174;
20479
+ var EBML_ID_TRACK_TYPE = 131;
20480
+ var EBML_ID_CODEC_ID = 134;
20481
+ var EBML_ID_VIDEO = 224;
20482
+ var EBML_ID_PIXEL_WIDTH = 176;
20483
+ var EBML_ID_PIXEL_HEIGHT = 186;
20484
+ var EBML_ID_CLUSTER = 524531317;
20485
+ function readVideoInfo(bytes) {
20486
+ if (bytes.length < 12) return { error: "File is too small to be a valid video file" };
20487
+ if (readAscii4(bytes, 4) === "ftyp") return parseMp4(bytes);
20488
+ if (bytes[0] === 26 && bytes[1] === 69 && bytes[2] === 223 && bytes[3] === 163) return parseWebm(bytes);
20489
+ return { error: 'Not a recognized MP4 or WebM file (missing an "ftyp" box or an EBML header signature)' };
20490
+ }
20491
+ function parseWebm(bytes) {
20492
+ const top = ebmlChildren(bytes, 0, bytes.length);
20493
+ const segment = top.find((c) => c.id === EBML_ID_SEGMENT);
20494
+ if (!segment) return { error: "No Segment element found (not a valid WebM/Matroska file)" };
20495
+ const result = { format: "webm" };
20496
+ let timecodeScale = 1e6;
20497
+ let rawDuration;
20498
+ for (const child of ebmlChildren(bytes, segment.dataStart, segment.dataEnd)) {
20499
+ if (child.id === EBML_ID_CLUSTER) break;
20500
+ if (child.id === EBML_ID_INFO) {
20501
+ for (const f of ebmlChildren(bytes, child.dataStart, child.dataEnd)) {
20502
+ if (f.id === EBML_ID_TIMECODE_SCALE) timecodeScale = readEbmlUint(bytes, f.dataStart, f.dataEnd - f.dataStart) || 1e6;
20503
+ else if (f.id === EBML_ID_DURATION) rawDuration = readEbmlFloat(bytes, f.dataStart, f.dataEnd - f.dataStart);
20504
+ }
20505
+ } else if (child.id === EBML_ID_TRACKS) {
20506
+ for (const entry of ebmlChildren(bytes, child.dataStart, child.dataEnd)) {
20507
+ if (entry.id !== EBML_ID_TRACK_ENTRY) continue;
20508
+ let trackType;
20509
+ let codecId;
20510
+ let pixelWidth;
20511
+ let pixelHeight;
20512
+ for (const f of ebmlChildren(bytes, entry.dataStart, entry.dataEnd)) {
20513
+ if (f.id === EBML_ID_TRACK_TYPE) trackType = readEbmlUint(bytes, f.dataStart, f.dataEnd - f.dataStart);
20514
+ else if (f.id === EBML_ID_CODEC_ID) codecId = Buffer.from(bytes.subarray(f.dataStart, f.dataEnd)).toString("ascii").replace(/\0+$/, "");
20515
+ else if (f.id === EBML_ID_VIDEO) {
20516
+ for (const v of ebmlChildren(bytes, f.dataStart, f.dataEnd)) {
20517
+ if (v.id === EBML_ID_PIXEL_WIDTH) pixelWidth = readEbmlUint(bytes, v.dataStart, v.dataEnd - v.dataStart);
20518
+ else if (v.id === EBML_ID_PIXEL_HEIGHT) pixelHeight = readEbmlUint(bytes, v.dataStart, v.dataEnd - v.dataStart);
20519
+ }
20520
+ }
20521
+ }
20522
+ if (trackType === 1) {
20523
+ if (codecId) result.videoCodec = codecId;
20524
+ if (pixelWidth) result.width = pixelWidth;
20525
+ if (pixelHeight) result.height = pixelHeight;
20526
+ } else if (trackType === 2) {
20527
+ if (codecId) result.audioCodec = codecId;
20528
+ }
20529
+ }
20530
+ }
20531
+ }
20532
+ if (rawDuration !== void 0 && timecodeScale > 0) {
20533
+ result.durationSeconds = Math.round(rawDuration * timecodeScale / 1e9 * 1e3) / 1e3;
20534
+ }
20535
+ if (result.durationSeconds === void 0 && !result.videoCodec && !result.audioCodec) {
20536
+ return { error: "Could not find any usable metadata in this WebM file's Segment element" };
20537
+ }
20538
+ return result;
20539
+ }
20091
20540
 
20092
20541
  // src/index.ts
20093
20542
  var version = "0.1.0";
package/dist/index.d.cts CHANGED
@@ -6,14 +6,14 @@ export { d as data } from './data-XRb0D7Zn.cjs';
6
6
  export { g as generators } from './generators-BGtRGpJZ.cjs';
7
7
  export { t as time } from './time-KqJjdqII.cjs';
8
8
  export { u as units } from './units-COt5uI20.cjs';
9
- export { n as network } from './network-BJOjJnmY.cjs';
9
+ export { n as network } from './network-D7Epuerc.cjs';
10
10
  export { a as api } from './api-DmTNE4c1.cjs';
11
11
  export { c as code } from './code-DaRvff2v.cjs';
12
12
  export { c as color } from './color-tPwZCr9H.cjs';
13
13
  export { c as css } from './css-Cf7AMGM-.cjs';
14
14
  export { m as misc } from './misc-CA3N198T.cjs';
15
15
  export { a as ai_agent } from './ai_agent-B-c59NXD.cjs';
16
- export { m as media } from './media-CN17a3MM.cjs';
16
+ export { m as media } from './media-fD8dJ5qR.cjs';
17
17
 
18
18
  declare const version = "0.1.0";
19
19
 
package/dist/index.d.ts CHANGED
@@ -6,14 +6,14 @@ export { d as data } from './data-XRb0D7Zn.js';
6
6
  export { g as generators } from './generators-BGtRGpJZ.js';
7
7
  export { t as time } from './time-KqJjdqII.js';
8
8
  export { u as units } from './units-COt5uI20.js';
9
- export { n as network } from './network-BJOjJnmY.js';
9
+ export { n as network } from './network-D7Epuerc.js';
10
10
  export { a as api } from './api-DmTNE4c1.js';
11
11
  export { c as code } from './code-DaRvff2v.js';
12
12
  export { c as color } from './color-tPwZCr9H.js';
13
13
  export { c as css } from './css-Cf7AMGM-.js';
14
14
  export { m as misc } from './misc-CA3N198T.js';
15
15
  export { a as ai_agent } from './ai_agent-B-c59NXD.js';
16
- export { m as media } from './media-CN17a3MM.js';
16
+ export { m as media } from './media-fD8dJ5qR.js';
17
17
 
18
18
  declare const version = "0.1.0";
19
19
 
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { media_exports as media } from './chunk-Q3M23WNJ.js';
1
+ export { media_exports as media } from './chunk-L6V4W4SU.js';
2
2
  export { units_exports as units } from './chunk-I63BCOAG.js';
3
- export { network_exports as network } from './chunk-Y5OOP6WN.js';
3
+ export { network_exports as network } from './chunk-CSNTHZHF.js';
4
4
  export { api_exports as api } from './chunk-52ZDKSIX.js';
5
5
  export { code_exports as code } from './chunk-LXKIPPDG.js';
6
6
  export { color_exports as color } from './chunk-BPVAB4P2.js';
@@ -64,6 +64,29 @@ interface PdfMetadataError {
64
64
  * pdf.js or other PDF rendering library required.
65
65
  */
66
66
  declare function readPdfMetadata(bytes: Uint8Array): PdfMetadata | PdfMetadataError;
67
+ type PdfPageOrientation = 'portrait' | 'landscape' | 'square' | null;
68
+ interface PdfPageDimension {
69
+ pageNumber: number;
70
+ widthPt: number | null;
71
+ heightPt: number | null;
72
+ widthIn: number | null;
73
+ heightIn: number | null;
74
+ rotation: number;
75
+ orientation: PdfPageOrientation;
76
+ paperSize: string | null;
77
+ }
78
+ interface PdfPageDimensionsResult {
79
+ version: string | null;
80
+ pageCount: number;
81
+ pages: PdfPageDimension[];
82
+ }
83
+ /**
84
+ * List each page's MediaBox width/height (in points and inches), rotation,
85
+ * and orientation, in document order — walking the Root -> Pages -> Kids
86
+ * tree and inheriting /MediaBox / /Rotate from ancestor nodes the way the
87
+ * PDF spec requires. No PDF rendering library required.
88
+ */
89
+ declare function readPdfPageDimensions(bytes: Uint8Array): PdfPageDimensionsResult | PdfMetadataError;
67
90
  interface WavInfo {
68
91
  audioFormat: number;
69
92
  audioFormatLabel: string;
@@ -160,6 +183,25 @@ interface FlacInfoError {
160
183
  * metadata-block headers. No audio frame decoding is performed.
161
184
  */
162
185
  declare function readFlacInfo(bytes: Uint8Array): FlacInfo | FlacInfoError;
186
+ interface VideoInfo {
187
+ format: 'mp4' | 'webm';
188
+ durationSeconds?: number;
189
+ width?: number;
190
+ height?: number;
191
+ videoCodec?: string;
192
+ audioCodec?: string;
193
+ majorBrand?: string;
194
+ }
195
+ interface VideoInfoError {
196
+ error: string;
197
+ }
198
+ /**
199
+ * Read an MP4 (ISO BMFF) or WebM (EBML/Matroska) container's header boxes
200
+ * to report duration, resolution, and video/audio codec identifiers.
201
+ * No frame decoding, demuxing of sample data, or transcoding is performed;
202
+ * only the moov box (MP4) or Segment/Info/Tracks elements (WebM) are read.
203
+ */
204
+ declare function readVideoInfo(bytes: Uint8Array): VideoInfo | VideoInfoError;
163
205
 
164
206
  type media_ExifData = ExifData;
165
207
  type media_ExifError = ExifError;
@@ -175,6 +217,11 @@ type media_ImageInfo = ImageInfo;
175
217
  type media_ImageInfoError = ImageInfoError;
176
218
  type media_PdfMetadata = PdfMetadata;
177
219
  type media_PdfMetadataError = PdfMetadataError;
220
+ type media_PdfPageDimension = PdfPageDimension;
221
+ type media_PdfPageDimensionsResult = PdfPageDimensionsResult;
222
+ type media_PdfPageOrientation = PdfPageOrientation;
223
+ type media_VideoInfo = VideoInfo;
224
+ type media_VideoInfoError = VideoInfoError;
178
225
  type media_WavInfo = WavInfo;
179
226
  type media_WavInfoError = WavInfoError;
180
227
  declare const media_readExifData: typeof readExifData;
@@ -183,9 +230,11 @@ declare const media_readIcoInfo: typeof readIcoInfo;
183
230
  declare const media_readId3Tags: typeof readId3Tags;
184
231
  declare const media_readImageInfo: typeof readImageInfo;
185
232
  declare const media_readPdfMetadata: typeof readPdfMetadata;
233
+ declare const media_readPdfPageDimensions: typeof readPdfPageDimensions;
234
+ declare const media_readVideoInfo: typeof readVideoInfo;
186
235
  declare const media_readWavInfo: typeof readWavInfo;
187
236
  declare namespace media {
188
- export { type media_ExifData as ExifData, type media_ExifError as ExifError, type media_FlacInfo as FlacInfo, type media_FlacInfoError as FlacInfoError, type media_IcoImageEntry as IcoImageEntry, type media_IcoInfo as IcoInfo, type media_IcoInfoError as IcoInfoError, type media_Id3Tags as Id3Tags, type media_Id3TagsError as Id3TagsError, type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, type media_PdfMetadata as PdfMetadata, type media_PdfMetadataError as PdfMetadataError, type media_WavInfo as WavInfo, type media_WavInfoError as WavInfoError, media_readExifData as readExifData, media_readFlacInfo as readFlacInfo, media_readIcoInfo as readIcoInfo, media_readId3Tags as readId3Tags, media_readImageInfo as readImageInfo, media_readPdfMetadata as readPdfMetadata, media_readWavInfo as readWavInfo };
237
+ export { type media_ExifData as ExifData, type media_ExifError as ExifError, type media_FlacInfo as FlacInfo, type media_FlacInfoError as FlacInfoError, type media_IcoImageEntry as IcoImageEntry, type media_IcoInfo as IcoInfo, type media_IcoInfoError as IcoInfoError, type media_Id3Tags as Id3Tags, type media_Id3TagsError as Id3TagsError, type media_ImageFormat as ImageFormat, type media_ImageInfo as ImageInfo, type media_ImageInfoError as ImageInfoError, type media_PdfMetadata as PdfMetadata, type media_PdfMetadataError as PdfMetadataError, type media_PdfPageDimension as PdfPageDimension, type media_PdfPageDimensionsResult as PdfPageDimensionsResult, type media_PdfPageOrientation as PdfPageOrientation, type media_VideoInfo as VideoInfo, type media_VideoInfoError as VideoInfoError, type media_WavInfo as WavInfo, type media_WavInfoError as WavInfoError, media_readExifData as readExifData, media_readFlacInfo as readFlacInfo, media_readIcoInfo as readIcoInfo, media_readId3Tags as readId3Tags, media_readImageInfo as readImageInfo, media_readPdfMetadata as readPdfMetadata, media_readPdfPageDimensions as readPdfPageDimensions, media_readVideoInfo as readVideoInfo, media_readWavInfo as readWavInfo };
189
238
  }
190
239
 
191
- export { type ExifData as E, type FlacInfo as F, type IcoImageEntry as I, type PdfMetadata as P, type WavInfo as W, type ExifError as a, type FlacInfoError as b, type IcoInfo as c, type IcoInfoError as d, type Id3Tags as e, type Id3TagsError as f, type ImageFormat as g, type ImageInfo as h, type ImageInfoError as i, type PdfMetadataError as j, type WavInfoError as k, readFlacInfo as l, media as m, readIcoInfo as n, readId3Tags as o, readImageInfo as p, readPdfMetadata as q, readExifData as r, readWavInfo as s };
240
+ export { type ExifData as E, type FlacInfo as F, type IcoImageEntry as I, type PdfMetadata as P, type VideoInfo as V, type WavInfo as W, type ExifError as a, type FlacInfoError as b, type IcoInfo as c, type IcoInfoError as d, type Id3Tags as e, type Id3TagsError as f, type ImageFormat as g, type ImageInfo as h, type ImageInfoError as i, type PdfMetadataError as j, type PdfPageDimension as k, type PdfPageDimensionsResult as l, media as m, type PdfPageOrientation as n, type VideoInfoError as o, type WavInfoError as p, readFlacInfo as q, readExifData as r, readIcoInfo as s, readId3Tags as t, readImageInfo as u, readPdfMetadata as v, readPdfPageDimensions as w, readVideoInfo as x, readWavInfo as y };