wao 0.27.2 → 0.27.3

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.
Files changed (3) hide show
  1. package/cjs/encode.js +445 -64
  2. package/esm/encode.js +364 -26
  3. package/package.json +1 -1
package/cjs/encode.js CHANGED
@@ -356,11 +356,8 @@ function collectBodyKeys(obj) {
356
356
  nestedPaths.push(fullPath);
357
357
  }
358
358
  }
359
- } else if (isBytes(value)) {
360
- var buffer = toBuffer(value);
361
- if (buffer.length > 0) {
362
- hasSimpleFields = true;
363
- }
359
+ } else if (isBytes(value) && value.length > 0) {
360
+ hasSimpleFields = true;
364
361
  } else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || value === undefined || _typeof(value) === "symbol") {
365
362
  hasSimpleFields = true;
366
363
  }
@@ -590,15 +587,24 @@ function collectBodyKeys(obj) {
590
587
  }
591
588
  }
592
589
  } else if (isPojo(value)) {
593
- console.log("[main loop] Processing object at key: \"".concat(key, "\""));
594
- // Objects should be traversed, not have their fields individually added
595
- traverse(value, key);
596
- } else if (isBytes(value)) {
597
- var buffer = toBuffer(value);
598
- if (buffer.length > 0) {
599
- console.log("[main loop] Adding key for non-empty bytes: \"".concat(key, "\""));
600
- keys.push(key);
590
+ console.log("[main loop] Traversing object at key: \"".concat(key, "\""));
591
+ // Check if this object contains arrays with only empty elements
592
+ var hasArraysWithOnlyEmptyElements = false;
593
+ for (var _i7 = 0, _Object$entries6 = Object.entries(value); _i7 < _Object$entries6.length; _i7++) {
594
+ var _Object$entries6$_i = _slicedToArray(_Object$entries6[_i7], 2),
595
+ k = _Object$entries6$_i[0],
596
+ v = _Object$entries6$_i[1];
597
+ if (Array.isArray(v) && v.length > 0 && v.every(function (item) {
598
+ return Array.isArray(item) && item.length === 0 || isPojo(item) && Object.keys(item).length === 0 || typeof item === "string" && item === "";
599
+ })) {
600
+ hasArraysWithOnlyEmptyElements = true;
601
+ keys.push("".concat(key, "/").concat(k));
602
+ }
601
603
  }
604
+ traverse(value, key);
605
+ } else if (isBytes(value) && value.length > 0) {
606
+ console.log("[main loop] Adding key for non-empty bytes: \"".concat(key, "\""));
607
+ keys.push(key);
602
608
  } else if (typeof value === "string" && value.includes("\n")) {
603
609
  console.log("[main loop] Adding key for string with newline: \"".concat(key, "\""));
604
610
  keys.push(key);
@@ -667,9 +673,9 @@ function _encode() {
667
673
  var obj,
668
674
  _processValue,
669
675
  processedObj,
670
- _i8,
671
- _Object$entries7,
672
- _Object$entries7$_i,
676
+ _i9,
677
+ _Object$entries8,
678
+ _Object$entries8$_i,
673
679
  k,
674
680
  v,
675
681
  objKeys,
@@ -701,15 +707,15 @@ function _encode() {
701
707
  _encoded,
702
708
  _contentDigest3,
703
709
  _base3,
704
- bodyKeys,
705
710
  headers,
706
711
  headerTypes,
712
+ bodyKeys,
707
713
  _loop3,
708
- _i9,
709
- _Object$entries8,
710
- _loop4,
711
714
  _i10,
712
715
  _Object$entries9,
716
+ _loop4,
717
+ _i11,
718
+ _Object$entries10,
713
719
  allBodyKeysAreEmptyBinaries,
714
720
  singleKey,
715
721
  pathParts,
@@ -755,10 +761,10 @@ function _encode() {
755
761
  return value.map(_processValue);
756
762
  } else if (isPojo(value)) {
757
763
  var result = {};
758
- for (var _i7 = 0, _Object$entries6 = Object.entries(value); _i7 < _Object$entries6.length; _i7++) {
759
- var _Object$entries6$_i = _slicedToArray(_Object$entries6[_i7], 2),
760
- k = _Object$entries6$_i[0],
761
- v = _Object$entries6$_i[1];
764
+ for (var _i8 = 0, _Object$entries7 = Object.entries(value); _i8 < _Object$entries7.length; _i8++) {
765
+ var _Object$entries7$_i = _slicedToArray(_Object$entries7[_i8], 2),
766
+ k = _Object$entries7$_i[0],
767
+ v = _Object$entries7$_i[1];
762
768
  result[k] = _processValue(v);
763
769
  }
764
770
  return result;
@@ -766,8 +772,8 @@ function _encode() {
766
772
  return value;
767
773
  };
768
774
  processedObj = {};
769
- for (_i8 = 0, _Object$entries7 = Object.entries(obj); _i8 < _Object$entries7.length; _i8++) {
770
- _Object$entries7$_i = _slicedToArray(_Object$entries7[_i8], 2), k = _Object$entries7$_i[0], v = _Object$entries7$_i[1];
775
+ for (_i9 = 0, _Object$entries8 = Object.entries(obj); _i9 < _Object$entries8.length; _i9++) {
776
+ _Object$entries8$_i = _slicedToArray(_Object$entries8[_i9], 2), k = _Object$entries8$_i[0], v = _Object$entries8$_i[1];
771
777
  processedObj[k] = _processValue(v);
772
778
  }
773
779
  if (!(Object.keys(obj).length === 0)) {
@@ -907,15 +913,15 @@ function _encode() {
907
913
  body: _fieldValue
908
914
  });
909
915
  case 71:
910
- bodyKeys = collectBodyKeys(obj);
911
916
  headers = {};
912
917
  headerTypes = [];
918
+ bodyKeys = collectBodyKeys(obj);
913
919
  _loop3 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop3() {
914
- var _Object$entries8$_i, key, value, needsBody, hasNonAsciiItems, encodedItems;
920
+ var _Object$entries9$_i, key, value, needsBody, hasNonAsciiItems, encodedItems;
915
921
  return _regeneratorRuntime().wrap(function _loop3$(_context3) {
916
922
  while (1) switch (_context3.prev = _context3.next) {
917
923
  case 0:
918
- _Object$entries8$_i = _slicedToArray(_Object$entries8[_i9], 2), key = _Object$entries8$_i[0], value = _Object$entries8$_i[1];
924
+ _Object$entries9$_i = _slicedToArray(_Object$entries9[_i10], 2), key = _Object$entries9$_i[0], value = _Object$entries9$_i[1];
919
925
  needsBody = bodyKeys.includes(key) || bodyKeys.some(function (k) {
920
926
  return k.startsWith("".concat(key, "/"));
921
927
  });
@@ -1034,9 +1040,9 @@ function _encode() {
1034
1040
  }
1035
1041
  }, _loop3);
1036
1042
  });
1037
- _i9 = 0, _Object$entries8 = Object.entries(obj);
1043
+ _i10 = 0, _Object$entries9 = Object.entries(obj);
1038
1044
  case 76:
1039
- if (!(_i9 < _Object$entries8.length)) {
1045
+ if (!(_i10 < _Object$entries9.length)) {
1040
1046
  _context6.next = 83;
1041
1047
  break;
1042
1048
  }
@@ -1048,16 +1054,16 @@ function _encode() {
1048
1054
  }
1049
1055
  return _context6.abrupt("continue", 80);
1050
1056
  case 80:
1051
- _i9++;
1057
+ _i10++;
1052
1058
  _context6.next = 76;
1053
1059
  break;
1054
1060
  case 83:
1055
1061
  _loop4 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop4() {
1056
- var _Object$entries9$_i, key, value;
1062
+ var _Object$entries10$_i, key, value;
1057
1063
  return _regeneratorRuntime().wrap(function _loop4$(_context4) {
1058
1064
  while (1) switch (_context4.prev = _context4.next) {
1059
1065
  case 0:
1060
- _Object$entries9$_i = _slicedToArray(_Object$entries9[_i10], 2), key = _Object$entries9$_i[0], value = _Object$entries9$_i[1];
1066
+ _Object$entries10$_i = _slicedToArray(_Object$entries10[_i11], 2), key = _Object$entries10$_i[0], value = _Object$entries10$_i[1];
1061
1067
  if (Array.isArray(value)) {
1062
1068
  if (bodyKeys.includes(key) || bodyKeys.some(function (k) {
1063
1069
  return k.startsWith("".concat(key, "/"));
@@ -1075,15 +1081,15 @@ function _encode() {
1075
1081
  }
1076
1082
  }, _loop4);
1077
1083
  });
1078
- _i10 = 0, _Object$entries9 = Object.entries(obj);
1084
+ _i11 = 0, _Object$entries10 = Object.entries(obj);
1079
1085
  case 85:
1080
- if (!(_i10 < _Object$entries9.length)) {
1086
+ if (!(_i11 < _Object$entries10.length)) {
1081
1087
  _context6.next = 90;
1082
1088
  break;
1083
1089
  }
1084
1090
  return _context6.delegateYield(_loop4(), "t1", 87);
1085
1091
  case 87:
1086
- _i10++;
1092
+ _i11++;
1087
1093
  _context6.next = 85;
1088
1094
  break;
1089
1095
  case 90:
@@ -1231,7 +1237,7 @@ function _encode() {
1231
1237
  _iterator5 = _createForOfIteratorHelper(sortedBodyKeys);
1232
1238
  _context6.prev = 123;
1233
1239
  _loop5 = /*#__PURE__*/_regeneratorRuntime().mark(function _loop5() {
1234
- var bodyKey, lines, pathParts, value, parent, _i11, _part, _buffer, headerText, hasOnlyEmptyElements, hasOnlyNonEmptyObjects, hasOnlyEmptyObjects, hasObjects, hasArrays, nonObjectItems, _fieldLines, _partTypes, _isInline, orderedLines, _orderedLines, isLastBodyPart, hasOnlyTypes, indicesWithOwnParts, hasNestedObjectParts, fieldLines, partTypes, hasEmptyStrings, hasEmptyObjects, hasObjectsWithOnlyEmptyValues, isMixedArray, _isInline2, _orderedLines2, _iterator6, _step6, line, _orderedLines3, _iterator7, _step7, _line, isInline, content;
1240
+ var bodyKey, lines, pathParts, value, parent, _i12, _part, hasOnlyEmptyElements, hasOnlyNonEmptyObjects, hasOnlyEmptyObjects, hasObjects, hasArrays, nonObjectItems, _fieldLines, _partTypes, _isInline, orderedLines, _orderedLines, isLastBodyPart, hasOnlyTypes, indicesWithOwnParts, hasNestedObjectParts, fieldLines, partTypes, hasEmptyStrings, hasEmptyObjects, hasObjectsWithOnlyEmptyValues, isMixedArray, _isInline2, _orderedLines2, _iterator6, _step6, line, _orderedLines3, _iterator7, _step7, _line, parentPath, parentValue, _iterator8, _step8, _part2, _hasEmptyStrings, _hasEmptyObjects, _hasObjects, _isInline3, objectTypes, _fieldLines2, binaryFields, hasOnlyEmptyCollections, hasArraysWithOnlyEmptyElements, arrayTypes, _i13, _Object$entries11, _Object$entries11$_i, _k, _v, _i14, _Object$entries12, _Object$entries12$_i, _k2, _v2, childPath, hasOnlyEmpty, desc, _buffer3, _childPath, _hasObjects2, encodedItems, allTypes, shouldSkipObject, onlyEmptyCollections, _orderedLines4, _iterator9, _step9, _line2, binaryFieldsForInline, parts, _iterator10, _step10, _step10$value, key, _buffer4, fullBody, _isLastBodyPart, _hasOnlyTypes, _orderedLines5, hasBinaryFields, _iterator11, _step11, _line3, _parts, headerText, _i15, _binaryFields$_i, _key, _buffer5, _fullBody, isInline, _buffer6, _headerText, content;
1235
1241
  return _regeneratorRuntime().wrap(function _loop5$(_context5) {
1236
1242
  while (1) switch (_context5.prev = _context5.next) {
1237
1243
  case 0:
@@ -1241,9 +1247,9 @@ function _encode() {
1241
1247
  pathParts = bodyKey.split("/");
1242
1248
  value = obj;
1243
1249
  parent = null;
1244
- for (_i11 = 0; _i11 < pathParts.length; _i11++) {
1250
+ for (_i12 = 0; _i12 < pathParts.length; _i12++) {
1245
1251
  parent = value;
1246
- _part = pathParts[_i11];
1252
+ _part = pathParts[_i12];
1247
1253
  if (/^\d+$/.test(_part)) {
1248
1254
  value = value[parseInt(_part) - 1];
1249
1255
  } else {
@@ -1264,19 +1270,8 @@ function _encode() {
1264
1270
  bodyParts.push(new Blob([lines.join("\r\n")]));
1265
1271
  return _context5.abrupt("return", 0);
1266
1272
  case 15:
1267
- if (!isBytes(value)) {
1268
- _context5.next = 22;
1269
- break;
1270
- }
1271
- console.log("[Body part] Creating part for binary at ".concat(bodyKey));
1272
- lines.push("content-disposition: form-data;name=\"".concat(bodyKey, "\""));
1273
- _buffer = toBuffer(value);
1274
- headerText = lines.join("\r\n") + "\r\n\r\n";
1275
- bodyParts.push(new Blob([headerText, _buffer]));
1276
- return _context5.abrupt("return", 0);
1277
- case 22:
1278
1273
  if (!Array.isArray(value)) {
1279
- _context5.next = 52;
1274
+ _context5.next = 45;
1280
1275
  break;
1281
1276
  }
1282
1277
  hasOnlyEmptyElements = value.length > 0 && value.every(function (item) {
@@ -1304,13 +1299,13 @@ function _encode() {
1304
1299
  return !isPojo(item);
1305
1300
  });
1306
1301
  if (!hasOnlyNonEmptyObjects) {
1307
- _context5.next = 31;
1302
+ _context5.next = 24;
1308
1303
  break;
1309
1304
  }
1310
1305
  return _context5.abrupt("return", 0);
1311
- case 31:
1306
+ case 24:
1312
1307
  if (!hasOnlyEmptyElements) {
1313
- _context5.next = 38;
1308
+ _context5.next = 31;
1314
1309
  break;
1315
1310
  }
1316
1311
  _fieldLines = [];
@@ -1361,7 +1356,7 @@ function _encode() {
1361
1356
  }
1362
1357
  }
1363
1358
  return _context5.abrupt("return", 0);
1364
- case 38:
1359
+ case 31:
1365
1360
  // Build list of which indices have their own parts
1366
1361
  indicesWithOwnParts = new Set();
1367
1362
  sortedBodyKeys.forEach(function (key) {
@@ -1457,8 +1452,8 @@ function _encode() {
1457
1452
  // Use the full encodeArrayItem for nested arrays
1458
1453
  return encodeArrayItem(subItem);
1459
1454
  } else if (isBytes(subItem)) {
1460
- var _buffer2 = toBuffer(subItem);
1461
- if (_buffer2.length === 0 || _buffer2.byteLength === 0) {
1455
+ var _buffer = toBuffer(subItem);
1456
+ if (_buffer.length === 0 || _buffer.byteLength === 0) {
1462
1457
  return "\"\"";
1463
1458
  }
1464
1459
  return "\"(ao-type-binary)\"";
@@ -1496,8 +1491,8 @@ function _encode() {
1496
1491
  fieldLines.push("".concat(index, ": ").concat(item));
1497
1492
  }
1498
1493
  } else if (isBytes(item)) {
1499
- var _buffer3 = toBuffer(item);
1500
- if (_buffer3.length === 0) {
1494
+ var _buffer2 = toBuffer(item);
1495
+ if (_buffer2.length === 0) {
1501
1496
  partTypes.push("".concat(index, "=\"empty-binary\""));
1502
1497
  } else {
1503
1498
  partTypes.push("".concat(index, "=\"binary\""));
@@ -1563,15 +1558,401 @@ function _encode() {
1563
1558
  }
1564
1559
  }
1565
1560
  return _context5.abrupt("return", 0);
1566
- case 52:
1567
- // This should not be reached for binary values as they're handled above
1561
+ case 45:
1562
+ if (!isPojo(value)) {
1563
+ _context5.next = 126;
1564
+ break;
1565
+ }
1566
+ if (!(Object.keys(value).length === 0)) {
1567
+ _context5.next = 60;
1568
+ break;
1569
+ }
1570
+ // Check if this is a parent array context where empty objects should get parts
1571
+ parentPath = pathParts.slice(0, -1).join("/");
1572
+ parentValue = obj;
1573
+ _iterator8 = _createForOfIteratorHelper(pathParts.slice(0, -1));
1574
+ try {
1575
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
1576
+ _part2 = _step8.value;
1577
+ if (/^\d+$/.test(_part2)) {
1578
+ parentValue = parentValue[parseInt(_part2) - 1];
1579
+ } else {
1580
+ parentValue = parentValue[_part2];
1581
+ }
1582
+ }
1583
+ } catch (err) {
1584
+ _iterator8.e(err);
1585
+ } finally {
1586
+ _iterator8.f();
1587
+ }
1588
+ if (!Array.isArray(parentValue)) {
1589
+ _context5.next = 58;
1590
+ break;
1591
+ }
1592
+ // Check if parent array has mixed content
1593
+ _hasEmptyStrings = parentValue.some(function (item) {
1594
+ return typeof item === "string" && item === "";
1595
+ });
1596
+ _hasEmptyObjects = parentValue.some(function (item) {
1597
+ return isPojo(item) && Object.keys(item).length === 0;
1598
+ });
1599
+ _hasObjects = parentValue.some(function (item) {
1600
+ return isPojo(item);
1601
+ });
1602
+ if (!(_hasObjects && (_hasEmptyStrings || _hasEmptyObjects))) {
1603
+ _context5.next = 58;
1604
+ break;
1605
+ }
1606
+ // Special mixed array case - empty objects don't get parts
1607
+ console.log("[Body part] Skipping empty object in mixed array at ".concat(bodyKey));
1608
+ return _context5.abrupt("return", 0);
1609
+ case 58:
1610
+ // Normal case - empty objects might get parts
1611
+ console.log("[Body part] Empty object at ".concat(bodyKey));
1612
+ // For now, skip empty objects
1613
+ return _context5.abrupt("return", 0);
1614
+ case 60:
1615
+ if (!(hasSpecialDataBody && bodyKey === "data" && Object.keys(value).length === 1 && value.body && isBytes(value.body))) {
1616
+ _context5.next = 62;
1617
+ break;
1618
+ }
1619
+ return _context5.abrupt("return", 0);
1620
+ case 62:
1621
+ // Handle non-empty objects
1622
+ _isInline3 = bodyKey === "body" && headers["inline-body-key"] === "body";
1623
+ if (_isInline3) {
1624
+ lines.push("content-disposition: inline");
1625
+ } else {
1626
+ lines.push("content-disposition: form-data;name=\"".concat(bodyKey, "\""));
1627
+ }
1628
+
1629
+ // Continue with object processing...
1630
+ objectTypes = [];
1631
+ _fieldLines2 = [];
1632
+ binaryFields = []; // First check if this object only contains empty collections
1633
+ hasOnlyEmptyCollections = Object.entries(value).every(function (_ref8) {
1634
+ var _ref9 = _slicedToArray(_ref8, 2),
1635
+ k = _ref9[0],
1636
+ v = _ref9[1];
1637
+ return Array.isArray(v) && v.length === 0 || isPojo(v) && Object.keys(v).length === 0 || isBytes(v) && (v.length === 0 || v.byteLength === 0) || typeof v === "string" && v.length === 0;
1638
+ }); // Also check if it contains arrays with only empty elements
1639
+ hasArraysWithOnlyEmptyElements = Object.entries(value).some(function (_ref10) {
1640
+ var _ref11 = _slicedToArray(_ref10, 2),
1641
+ k = _ref11[0],
1642
+ v = _ref11[1];
1643
+ return Array.isArray(v) && v.length > 0 && v.every(function (item) {
1644
+ return Array.isArray(item) && item.length === 0 || isPojo(item) && Object.keys(item).length === 0 || typeof item === "string" && item === "";
1645
+ });
1646
+ }); // Collect type information for arrays in the object BEFORE processing fields
1647
+ arrayTypes = [];
1648
+ for (_i13 = 0, _Object$entries11 = Object.entries(value); _i13 < _Object$entries11.length; _i13++) {
1649
+ _Object$entries11$_i = _slicedToArray(_Object$entries11[_i13], 2), _k = _Object$entries11$_i[0], _v = _Object$entries11$_i[1];
1650
+ if (Array.isArray(_v)) {
1651
+ arrayTypes.push("".concat(_k.toLowerCase(), "=\"").concat(_v.length === 0 ? "empty-list" : "list", "\""));
1652
+ }
1653
+ }
1654
+ _i14 = 0, _Object$entries12 = Object.entries(value);
1655
+ case 72:
1656
+ if (!(_i14 < _Object$entries12.length)) {
1657
+ _context5.next = 119;
1658
+ break;
1659
+ }
1660
+ _Object$entries12$_i = _slicedToArray(_Object$entries12[_i14], 2), _k2 = _Object$entries12$_i[0], _v2 = _Object$entries12$_i[1];
1661
+ childPath = "".concat(bodyKey, "/").concat(_k2);
1662
+ if (!sortedBodyKeys.includes(childPath)) {
1663
+ _context5.next = 77;
1664
+ break;
1665
+ }
1666
+ return _context5.abrupt("continue", 116);
1667
+ case 77:
1668
+ if (!(Array.isArray(_v2) && _v2.some(function (item) {
1669
+ return isPojo(item);
1670
+ }))) {
1671
+ _context5.next = 83;
1672
+ break;
1673
+ }
1674
+ if (!sortedBodyKeys.includes(childPath)) {
1675
+ _context5.next = 80;
1676
+ break;
1677
+ }
1678
+ return _context5.abrupt("continue", 116);
1679
+ case 80:
1680
+ // Check if array has only empty elements
1681
+ hasOnlyEmpty = _v2.every(function (item) {
1682
+ return Array.isArray(item) && item.length === 0 || isPojo(item) && Object.keys(item).length === 0 || typeof item === "string" && item === "";
1683
+ });
1684
+ if (!hasOnlyEmpty) {
1685
+ _context5.next = 83;
1686
+ break;
1687
+ }
1688
+ return _context5.abrupt("continue", 116);
1689
+ case 83:
1690
+ if (Array.isArray(_v2)) {
1691
+ // Type info already added above in arrayTypes
1692
+ } else if (_v2 === null || _v2 === undefined || _typeof(_v2) === "symbol" || typeof _v2 === "boolean") {
1693
+ objectTypes.push("".concat(_k2.toLowerCase(), "=\"atom\""));
1694
+ } else if (typeof _v2 === "number") {
1695
+ objectTypes.push("".concat(_k2.toLowerCase(), "=\"").concat(Number.isInteger(_v2) ? "integer" : "float", "\""));
1696
+ } else if (typeof _v2 === "string" && _v2.length === 0) {
1697
+ objectTypes.push("".concat(_k2.toLowerCase(), "=\"empty-binary\""));
1698
+ } else if (isBytes(_v2) && (_v2.length === 0 || _v2.byteLength === 0)) {
1699
+ objectTypes.push("".concat(_k2.toLowerCase(), "=\"empty-binary\""));
1700
+ } else if (isPojo(_v2) && Object.keys(_v2).length === 0) {
1701
+ objectTypes.push("".concat(_k2.toLowerCase(), "=\"empty-message\""));
1702
+ }
1703
+ if (!(typeof _v2 === "string")) {
1704
+ _context5.next = 88;
1705
+ break;
1706
+ }
1707
+ if (_v2.length === 0) {
1708
+ // Empty strings are shown as "empty: " (with trailing space)
1709
+ _fieldLines2.push("".concat(_k2, ": "));
1710
+ } else {
1711
+ _fieldLines2.push("".concat(_k2, ": ").concat(_v2));
1712
+ }
1713
+ _context5.next = 116;
1714
+ break;
1715
+ case 88:
1716
+ if (!(typeof _v2 === "number")) {
1717
+ _context5.next = 92;
1718
+ break;
1719
+ }
1720
+ _fieldLines2.push("".concat(_k2, ": ").concat(_v2));
1721
+ _context5.next = 116;
1722
+ break;
1723
+ case 92:
1724
+ if (!(typeof _v2 === "boolean")) {
1725
+ _context5.next = 96;
1726
+ break;
1727
+ }
1728
+ _fieldLines2.push("".concat(_k2, ": \"").concat(_v2, "\""));
1729
+ _context5.next = 116;
1730
+ break;
1731
+ case 96:
1732
+ if (!(_v2 === null)) {
1733
+ _context5.next = 100;
1734
+ break;
1735
+ }
1736
+ _fieldLines2.push("".concat(_k2, ": \"null\""));
1737
+ _context5.next = 116;
1738
+ break;
1739
+ case 100:
1740
+ if (!(_v2 === undefined)) {
1741
+ _context5.next = 104;
1742
+ break;
1743
+ }
1744
+ _fieldLines2.push("".concat(_k2, ": \"undefined\""));
1745
+ _context5.next = 116;
1746
+ break;
1747
+ case 104:
1748
+ if (!(_typeof(_v2) === "symbol")) {
1749
+ _context5.next = 109;
1750
+ break;
1751
+ }
1752
+ desc = _v2.description || "Symbol.for()";
1753
+ _fieldLines2.push("".concat(_k2, ": \"").concat(desc, "\""));
1754
+ _context5.next = 116;
1755
+ break;
1756
+ case 109:
1757
+ if (!isBytes(_v2)) {
1758
+ _context5.next = 115;
1759
+ break;
1760
+ }
1761
+ _buffer3 = toBuffer(_v2);
1762
+ binaryFields.push({
1763
+ key: _k2,
1764
+ buffer: _buffer3
1765
+ });
1766
+ return _context5.abrupt("continue", 116);
1767
+ case 115:
1768
+ if (Array.isArray(_v2)) {
1769
+ if (_v2.length === 0) {
1770
+ // Don't add field line for empty array
1771
+ } else {
1772
+ // Check if this array will have its own body part
1773
+ _childPath = "".concat(bodyKey, "/").concat(_k2);
1774
+ if (!sortedBodyKeys.includes(_childPath)) {
1775
+ // Check if this array contains objects - if so, don't add field line
1776
+ _hasObjects2 = _v2.some(function (item) {
1777
+ return isPojo(item);
1778
+ });
1779
+ if (!_hasObjects2) {
1780
+ encodedItems = _v2.map(function (item) {
1781
+ return encodeArrayItem(item);
1782
+ }).join(", ");
1783
+ _fieldLines2.push("".concat(_k2, ": ").concat(encodedItems));
1784
+ }
1785
+ }
1786
+ }
1787
+ } else if (isPojo(_v2) && Object.keys(_v2).length === 0) {
1788
+ // Empty object - don't add field line
1789
+ }
1790
+ case 116:
1791
+ _i14++;
1792
+ _context5.next = 72;
1793
+ break;
1794
+ case 119:
1795
+ // Combine arrayTypes with objectTypes
1796
+ allTypes = [].concat(arrayTypes, objectTypes); // Check if this object should be skipped entirely
1797
+ shouldSkipObject = Object.entries(value).every(function (_ref12) {
1798
+ var _ref13 = _slicedToArray(_ref12, 2),
1799
+ k = _ref13[0],
1800
+ v = _ref13[1];
1801
+ var childPath = "".concat(bodyKey, "/").concat(k);
1802
+ if (sortedBodyKeys.includes(childPath)) return true;
1803
+ if (Array.isArray(v) && v.some(function (item) {
1804
+ return isPojo(item);
1805
+ })) {
1806
+ // Check if array has only empty elements
1807
+ var _hasOnlyEmpty = v.every(function (item) {
1808
+ return Array.isArray(item) && item.length === 0 || isPojo(item) && Object.keys(item).length === 0 || typeof item === "string" && item === "";
1809
+ });
1810
+ return _hasOnlyEmpty || sortedBodyKeys.includes(childPath);
1811
+ }
1812
+ return false;
1813
+ });
1814
+ if (!(shouldSkipObject && !hasOnlyEmptyCollections && !hasArraysWithOnlyEmptyElements)) {
1815
+ _context5.next = 123;
1816
+ break;
1817
+ }
1818
+ return _context5.abrupt("return", 0);
1819
+ case 123:
1820
+ onlyEmptyCollections = Object.entries(value).every(function (_ref14) {
1821
+ var _ref15 = _slicedToArray(_ref14, 2),
1822
+ k = _ref15[0],
1823
+ v = _ref15[1];
1824
+ var childPath = "".concat(bodyKey, "/").concat(k);
1825
+ if (sortedBodyKeys.includes(childPath)) return true;
1826
+ if (Array.isArray(v) && v.some(function (item) {
1827
+ return isPojo(item);
1828
+ })) return true;
1829
+ return Array.isArray(v) && v.length === 0 || isPojo(v) && Object.keys(v).length === 0 || isBytes(v) && (v.length === 0 || v.byteLength === 0);
1830
+ });
1831
+ if (_isInline3) {
1832
+ _orderedLines4 = []; // FIXED: For inline body, put field lines FIRST
1833
+ _iterator9 = _createForOfIteratorHelper(_fieldLines2);
1834
+ try {
1835
+ for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
1836
+ _line2 = _step9.value;
1837
+ _orderedLines4.push(_line2);
1838
+ }
1839
+ } catch (err) {
1840
+ _iterator9.e(err);
1841
+ } finally {
1842
+ _iterator9.f();
1843
+ }
1844
+ if (allTypes.length > 0) {
1845
+ _orderedLines4.push("ao-types: ".concat(allTypes.sort().join(", ")));
1846
+ }
1847
+ _orderedLines4.push("content-disposition: inline");
1848
+ binaryFieldsForInline = Object.entries(value).filter(function (_ref16) {
1849
+ var _ref17 = _slicedToArray(_ref16, 2),
1850
+ k = _ref17[0],
1851
+ v = _ref17[1];
1852
+ return isBytes(v) && !sortedBodyKeys.includes("".concat(bodyKey, "/").concat(k));
1853
+ }).map(function (_ref18) {
1854
+ var _ref19 = _slicedToArray(_ref18, 2),
1855
+ k = _ref19[0],
1856
+ v = _ref19[1];
1857
+ return {
1858
+ key: k,
1859
+ buffer: toBuffer(v)
1860
+ };
1861
+ });
1862
+ if (binaryFieldsForInline.length > 0) {
1863
+ parts = [];
1864
+ parts.push(Buffer.from(_orderedLines4.join("\r\n")));
1865
+ _iterator10 = _createForOfIteratorHelper(binaryFieldsForInline);
1866
+ try {
1867
+ for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
1868
+ _step10$value = _step10.value, key = _step10$value.key, _buffer4 = _step10$value.buffer;
1869
+ parts.push(Buffer.from("\r\n".concat(key, ": ")));
1870
+ parts.push(_buffer4);
1871
+ }
1872
+ } catch (err) {
1873
+ _iterator10.e(err);
1874
+ } finally {
1875
+ _iterator10.f();
1876
+ }
1877
+ parts.push(Buffer.from("\r\n"));
1878
+ fullBody = Buffer.concat(parts);
1879
+ bodyParts.push(new Blob([fullBody]));
1880
+ } else {
1881
+ // Check if this is the last body part for special handling
1882
+ _isLastBodyPart = sortedBodyKeys.indexOf(bodyKey) === sortedBodyKeys.length - 1;
1883
+ _hasOnlyTypes = allTypes.length > 0 && _fieldLines2.length === 0;
1884
+ if (_isLastBodyPart && _hasOnlyTypes) {
1885
+ // Don't add empty line for last part with only types
1886
+ bodyParts.push(new Blob([_orderedLines4.join("\r\n")]));
1887
+ } else if (_fieldLines2.length === 0) {
1888
+ bodyParts.push(new Blob([_orderedLines4.join("\r\n")]));
1889
+ } else {
1890
+ bodyParts.push(new Blob([_orderedLines4.join("\r\n") + "\r\n"]));
1891
+ }
1892
+ }
1893
+ } else {
1894
+ // Put ao-types first, then content-disposition, then field lines
1895
+ _orderedLines5 = [];
1896
+ if (allTypes.length > 0) {
1897
+ _orderedLines5.push("ao-types: ".concat(allTypes.sort().join(", ")));
1898
+ }
1899
+ _orderedLines5.push("content-disposition: form-data;name=\"".concat(bodyKey, "\""));
1900
+
1901
+ // Check if we have any binary fields
1902
+ hasBinaryFields = binaryFields && binaryFields.length > 0; // Add blank line before field lines if we have binary fields or no field lines
1903
+ if (hasBinaryFields || _fieldLines2.length === 0) {
1904
+ _orderedLines5.push("");
1905
+ }
1906
+
1907
+ // Add field lines
1908
+ _iterator11 = _createForOfIteratorHelper(_fieldLines2);
1909
+ try {
1910
+ for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
1911
+ _line3 = _step11.value;
1912
+ _orderedLines5.push(_line3);
1913
+ }
1914
+ } catch (err) {
1915
+ _iterator11.e(err);
1916
+ } finally {
1917
+ _iterator11.f();
1918
+ }
1919
+ if (binaryFields && binaryFields.length > 0) {
1920
+ _parts = [];
1921
+ headerText = _orderedLines5.join("\r\n");
1922
+ _parts.push(Buffer.from(headerText));
1923
+ for (_i15 = 0; _i15 < binaryFields.length; _i15++) {
1924
+ _binaryFields$_i = binaryFields[_i15], _key = _binaryFields$_i.key, _buffer5 = _binaryFields$_i.buffer;
1925
+ if (_i15 > 0) {
1926
+ _parts.push(Buffer.from("\r\n"));
1927
+ }
1928
+ _parts.push(Buffer.from("".concat(_key, ": ")));
1929
+ _parts.push(_buffer5);
1930
+ }
1931
+ _parts.push(Buffer.from("\r\n"));
1932
+ _fullBody = Buffer.concat(_parts);
1933
+ bodyParts.push(new Blob([_fullBody]));
1934
+ } else {
1935
+ // Add trailing blank line if we have field lines
1936
+ if (_fieldLines2.length > 0) {
1937
+ bodyParts.push(new Blob([_orderedLines5.join("\r\n") + "\r\n"]));
1938
+ } else {
1939
+ bodyParts.push(new Blob([_orderedLines5.join("\r\n")]));
1940
+ }
1941
+ }
1942
+ }
1943
+ return _context5.abrupt("return", 0);
1944
+ case 126:
1568
1945
  isInline = bodyKey === "body" && headers["inline-body-key"] === "body";
1569
1946
  if (isInline) {
1570
1947
  lines.push("content-disposition: inline");
1571
1948
  } else {
1572
1949
  lines.push("content-disposition: form-data;name=\"".concat(bodyKey, "\""));
1573
1950
  }
1574
- if (typeof value === "string") {
1951
+ if (isBytes(value)) {
1952
+ _buffer6 = toBuffer(value);
1953
+ _headerText = lines.join("\r\n") + "\r\n\r\n";
1954
+ bodyParts.push(new Blob([_headerText, _buffer6]));
1955
+ } else if (typeof value === "string") {
1575
1956
  lines.push("");
1576
1957
  lines.push(value);
1577
1958
  bodyParts.push(new Blob([lines.join("\r\n")]));
@@ -1591,7 +1972,7 @@ function _encode() {
1591
1972
  lines.push(content);
1592
1973
  bodyParts.push(new Blob([lines.join("\r\n")]));
1593
1974
  }
1594
- case 55:
1975
+ case 129:
1595
1976
  case "end":
1596
1977
  return _context5.stop();
1597
1978
  }
package/esm/encode.js CHANGED
@@ -339,11 +339,8 @@ function collectBodyKeys(obj, prefix = "") {
339
339
  nestedPaths.push(fullPath)
340
340
  }
341
341
  }
342
- } else if (isBytes(value)) {
343
- const buffer = toBuffer(value)
344
- if (buffer.length > 0) {
345
- hasSimpleFields = true
346
- }
342
+ } else if (isBytes(value) && value.length > 0) {
343
+ hasSimpleFields = true
347
344
  } else if (
348
345
  typeof value === "string" ||
349
346
  typeof value === "number" ||
@@ -631,15 +628,28 @@ function collectBodyKeys(obj, prefix = "") {
631
628
  }
632
629
  }
633
630
  } else if (isPojo(value)) {
634
- console.log(`[main loop] Processing object at key: "${key}"`)
635
- // Objects should be traversed, not have their fields individually added
636
- traverse(value, key)
637
- } else if (isBytes(value)) {
638
- const buffer = toBuffer(value)
639
- if (buffer.length > 0) {
640
- console.log(`[main loop] Adding key for non-empty bytes: "${key}"`)
641
- keys.push(key)
631
+ console.log(`[main loop] Traversing object at key: "${key}"`)
632
+ // Check if this object contains arrays with only empty elements
633
+ let hasArraysWithOnlyEmptyElements = false
634
+ for (const [k, v] of Object.entries(value)) {
635
+ if (
636
+ Array.isArray(v) &&
637
+ v.length > 0 &&
638
+ v.every(
639
+ item =>
640
+ (Array.isArray(item) && item.length === 0) ||
641
+ (isPojo(item) && Object.keys(item).length === 0) ||
642
+ (typeof item === "string" && item === "")
643
+ )
644
+ ) {
645
+ hasArraysWithOnlyEmptyElements = true
646
+ keys.push(`${key}/${k}`)
647
+ }
642
648
  }
649
+ traverse(value, key)
650
+ } else if (isBytes(value) && value.length > 0) {
651
+ console.log(`[main loop] Adding key for non-empty bytes: "${key}"`)
652
+ keys.push(key)
643
653
  } else if (typeof value === "string" && value.includes("\n")) {
644
654
  console.log(`[main loop] Adding key for string with newline: "${key}"`)
645
655
  keys.push(key)
@@ -852,10 +862,11 @@ async function encode(obj = {}) {
852
862
  }
853
863
  }
854
864
 
855
- const bodyKeys = collectBodyKeys(obj)
856
865
  const headers = {}
857
866
  const headerTypes = []
858
867
 
868
+ const bodyKeys = collectBodyKeys(obj)
869
+
859
870
  for (const [key, value] of Object.entries(obj)) {
860
871
  const needsBody =
861
872
  bodyKeys.includes(key) || bodyKeys.some(k => k.startsWith(`${key}/`))
@@ -1106,16 +1117,6 @@ async function encode(obj = {}) {
1106
1117
  continue
1107
1118
  }
1108
1119
 
1109
- // Handle direct binary values
1110
- if (isBytes(value)) {
1111
- console.log(`[Body part] Creating part for binary at ${bodyKey}`)
1112
- lines.push(`content-disposition: form-data;name="${bodyKey}"`)
1113
- const buffer = toBuffer(value)
1114
- const headerText = lines.join("\r\n") + "\r\n\r\n"
1115
- bodyParts.push(new Blob([headerText, buffer]))
1116
- continue
1117
- }
1118
-
1119
1120
  if (Array.isArray(value)) {
1120
1121
  const hasOnlyEmptyElements =
1121
1122
  value.length > 0 &&
@@ -1439,7 +1440,340 @@ async function encode(obj = {}) {
1439
1440
  continue
1440
1441
  }
1441
1442
 
1442
- // This should not be reached for binary values as they're handled above
1443
+ if (isPojo(value)) {
1444
+ // Handle non-empty objects - skip empty ones
1445
+ if (Object.keys(value).length === 0) {
1446
+ // Check if this is a parent array context where empty objects should get parts
1447
+ const parentPath = pathParts.slice(0, -1).join("/")
1448
+ let parentValue = obj
1449
+ for (const part of pathParts.slice(0, -1)) {
1450
+ if (/^\d+$/.test(part)) {
1451
+ parentValue = parentValue[parseInt(part) - 1]
1452
+ } else {
1453
+ parentValue = parentValue[part]
1454
+ }
1455
+ }
1456
+
1457
+ if (Array.isArray(parentValue)) {
1458
+ // Check if parent array has mixed content
1459
+ const hasEmptyStrings = parentValue.some(
1460
+ item => typeof item === "string" && item === ""
1461
+ )
1462
+ const hasEmptyObjects = parentValue.some(
1463
+ item => isPojo(item) && Object.keys(item).length === 0
1464
+ )
1465
+ const hasObjects = parentValue.some(item => isPojo(item))
1466
+
1467
+ if (hasObjects && (hasEmptyStrings || hasEmptyObjects)) {
1468
+ // Special mixed array case - empty objects don't get parts
1469
+ console.log(
1470
+ `[Body part] Skipping empty object in mixed array at ${bodyKey}`
1471
+ )
1472
+ continue
1473
+ }
1474
+ }
1475
+
1476
+ // Normal case - empty objects might get parts
1477
+ console.log(`[Body part] Empty object at ${bodyKey}`)
1478
+ // For now, skip empty objects
1479
+ continue
1480
+ }
1481
+
1482
+ // Skip the special case where bodyKey is "data" and has only body:Buffer
1483
+ if (
1484
+ hasSpecialDataBody &&
1485
+ bodyKey === "data" &&
1486
+ Object.keys(value).length === 1 &&
1487
+ value.body &&
1488
+ isBytes(value.body)
1489
+ ) {
1490
+ continue
1491
+ }
1492
+
1493
+ // Handle non-empty objects
1494
+ const isInline =
1495
+ bodyKey === "body" && headers["inline-body-key"] === "body"
1496
+ if (isInline) {
1497
+ lines.push(`content-disposition: inline`)
1498
+ } else {
1499
+ lines.push(`content-disposition: form-data;name="${bodyKey}"`)
1500
+ }
1501
+
1502
+ // Continue with object processing...
1503
+ const objectTypes = []
1504
+ const fieldLines = []
1505
+ const binaryFields = []
1506
+
1507
+ // First check if this object only contains empty collections
1508
+ const hasOnlyEmptyCollections = Object.entries(value).every(([k, v]) => {
1509
+ return (
1510
+ (Array.isArray(v) && v.length === 0) ||
1511
+ (isPojo(v) && Object.keys(v).length === 0) ||
1512
+ (isBytes(v) && (v.length === 0 || v.byteLength === 0)) ||
1513
+ (typeof v === "string" && v.length === 0)
1514
+ )
1515
+ })
1516
+
1517
+ // Also check if it contains arrays with only empty elements
1518
+ const hasArraysWithOnlyEmptyElements = Object.entries(value).some(
1519
+ ([k, v]) => {
1520
+ return (
1521
+ Array.isArray(v) &&
1522
+ v.length > 0 &&
1523
+ v.every(
1524
+ item =>
1525
+ (Array.isArray(item) && item.length === 0) ||
1526
+ (isPojo(item) && Object.keys(item).length === 0) ||
1527
+ (typeof item === "string" && item === "")
1528
+ )
1529
+ )
1530
+ }
1531
+ )
1532
+
1533
+ // Collect type information for arrays in the object BEFORE processing fields
1534
+ const arrayTypes = []
1535
+ for (const [k, v] of Object.entries(value)) {
1536
+ if (Array.isArray(v)) {
1537
+ arrayTypes.push(
1538
+ `${k.toLowerCase()}="${v.length === 0 ? "empty-list" : "list"}"`
1539
+ )
1540
+ }
1541
+ }
1542
+
1543
+ for (const [k, v] of Object.entries(value)) {
1544
+ const childPath = `${bodyKey}/${k}`
1545
+
1546
+ if (sortedBodyKeys.includes(childPath)) {
1547
+ continue
1548
+ }
1549
+
1550
+ if (Array.isArray(v) && v.some(item => isPojo(item))) {
1551
+ // Check if this array will have its own body part
1552
+ if (sortedBodyKeys.includes(childPath)) {
1553
+ continue
1554
+ }
1555
+ // Check if array has only empty elements
1556
+ const hasOnlyEmpty = v.every(
1557
+ item =>
1558
+ (Array.isArray(item) && item.length === 0) ||
1559
+ (isPojo(item) && Object.keys(item).length === 0) ||
1560
+ (typeof item === "string" && item === "")
1561
+ )
1562
+ if (hasOnlyEmpty) {
1563
+ continue
1564
+ }
1565
+ }
1566
+
1567
+ if (Array.isArray(v)) {
1568
+ // Type info already added above in arrayTypes
1569
+ } else if (
1570
+ v === null ||
1571
+ v === undefined ||
1572
+ typeof v === "symbol" ||
1573
+ typeof v === "boolean"
1574
+ ) {
1575
+ objectTypes.push(`${k.toLowerCase()}="atom"`)
1576
+ } else if (typeof v === "number") {
1577
+ objectTypes.push(
1578
+ `${k.toLowerCase()}="${Number.isInteger(v) ? "integer" : "float"}"`
1579
+ )
1580
+ } else if (typeof v === "string" && v.length === 0) {
1581
+ objectTypes.push(`${k.toLowerCase()}="empty-binary"`)
1582
+ } else if (isBytes(v) && (v.length === 0 || v.byteLength === 0)) {
1583
+ objectTypes.push(`${k.toLowerCase()}="empty-binary"`)
1584
+ } else if (isPojo(v) && Object.keys(v).length === 0) {
1585
+ objectTypes.push(`${k.toLowerCase()}="empty-message"`)
1586
+ }
1587
+
1588
+ if (typeof v === "string") {
1589
+ if (v.length === 0) {
1590
+ // Empty strings are shown as "empty: " (with trailing space)
1591
+ fieldLines.push(`${k}: `)
1592
+ } else {
1593
+ fieldLines.push(`${k}: ${v}`)
1594
+ }
1595
+ } else if (typeof v === "number") {
1596
+ fieldLines.push(`${k}: ${v}`)
1597
+ } else if (typeof v === "boolean") {
1598
+ fieldLines.push(`${k}: "${v}"`)
1599
+ } else if (v === null) {
1600
+ fieldLines.push(`${k}: "null"`)
1601
+ } else if (v === undefined) {
1602
+ fieldLines.push(`${k}: "undefined"`)
1603
+ } else if (typeof v === "symbol") {
1604
+ const desc = v.description || "Symbol.for()"
1605
+ fieldLines.push(`${k}: "${desc}"`)
1606
+ } else if (isBytes(v)) {
1607
+ const buffer = toBuffer(v)
1608
+ binaryFields.push({ key: k, buffer })
1609
+ continue
1610
+ } else if (Array.isArray(v)) {
1611
+ if (v.length === 0) {
1612
+ // Don't add field line for empty array
1613
+ } else {
1614
+ // Check if this array will have its own body part
1615
+ const childPath = `${bodyKey}/${k}`
1616
+ if (!sortedBodyKeys.includes(childPath)) {
1617
+ // Check if this array contains objects - if so, don't add field line
1618
+ const hasObjects = v.some(item => isPojo(item))
1619
+ if (!hasObjects) {
1620
+ const encodedItems = v
1621
+ .map(item => encodeArrayItem(item))
1622
+ .join(", ")
1623
+ fieldLines.push(`${k}: ${encodedItems}`)
1624
+ }
1625
+ }
1626
+ }
1627
+ } else if (isPojo(v) && Object.keys(v).length === 0) {
1628
+ // Empty object - don't add field line
1629
+ }
1630
+ }
1631
+
1632
+ // Combine arrayTypes with objectTypes
1633
+ const allTypes = [...arrayTypes, ...objectTypes]
1634
+
1635
+ // Check if this object should be skipped entirely
1636
+ const shouldSkipObject = Object.entries(value).every(([k, v]) => {
1637
+ const childPath = `${bodyKey}/${k}`
1638
+ if (sortedBodyKeys.includes(childPath)) return true
1639
+ if (Array.isArray(v) && v.some(item => isPojo(item))) {
1640
+ // Check if array has only empty elements
1641
+ const hasOnlyEmpty = v.every(
1642
+ item =>
1643
+ (Array.isArray(item) && item.length === 0) ||
1644
+ (isPojo(item) && Object.keys(item).length === 0) ||
1645
+ (typeof item === "string" && item === "")
1646
+ )
1647
+ return hasOnlyEmpty || sortedBodyKeys.includes(childPath)
1648
+ }
1649
+ return false
1650
+ })
1651
+
1652
+ if (
1653
+ shouldSkipObject &&
1654
+ !hasOnlyEmptyCollections &&
1655
+ !hasArraysWithOnlyEmptyElements
1656
+ ) {
1657
+ continue
1658
+ }
1659
+
1660
+ const onlyEmptyCollections = Object.entries(value).every(([k, v]) => {
1661
+ const childPath = `${bodyKey}/${k}`
1662
+ if (sortedBodyKeys.includes(childPath)) return true
1663
+ if (Array.isArray(v) && v.some(item => isPojo(item))) return true
1664
+
1665
+ return (
1666
+ (Array.isArray(v) && v.length === 0) ||
1667
+ (isPojo(v) && Object.keys(v).length === 0) ||
1668
+ (isBytes(v) && (v.length === 0 || v.byteLength === 0))
1669
+ )
1670
+ })
1671
+
1672
+ if (isInline) {
1673
+ const orderedLines = []
1674
+
1675
+ // FIXED: For inline body, put field lines FIRST
1676
+ for (const line of fieldLines) {
1677
+ orderedLines.push(line)
1678
+ }
1679
+
1680
+ if (allTypes.length > 0) {
1681
+ orderedLines.push(`ao-types: ${allTypes.sort().join(", ")}`)
1682
+ }
1683
+
1684
+ orderedLines.push("content-disposition: inline")
1685
+
1686
+ const binaryFieldsForInline = Object.entries(value)
1687
+ .filter(
1688
+ ([k, v]) =>
1689
+ isBytes(v) && !sortedBodyKeys.includes(`${bodyKey}/${k}`)
1690
+ )
1691
+ .map(([k, v]) => ({
1692
+ key: k,
1693
+ buffer: toBuffer(v),
1694
+ }))
1695
+
1696
+ if (binaryFieldsForInline.length > 0) {
1697
+ const parts = []
1698
+ parts.push(Buffer.from(orderedLines.join("\r\n")))
1699
+
1700
+ for (const { key, buffer } of binaryFieldsForInline) {
1701
+ parts.push(Buffer.from(`\r\n${key}: `))
1702
+ parts.push(buffer)
1703
+ }
1704
+
1705
+ parts.push(Buffer.from("\r\n"))
1706
+
1707
+ const fullBody = Buffer.concat(parts)
1708
+ bodyParts.push(new Blob([fullBody]))
1709
+ } else {
1710
+ // Check if this is the last body part for special handling
1711
+ const isLastBodyPart =
1712
+ sortedBodyKeys.indexOf(bodyKey) === sortedBodyKeys.length - 1
1713
+ const hasOnlyTypes = allTypes.length > 0 && fieldLines.length === 0
1714
+
1715
+ if (isLastBodyPart && hasOnlyTypes) {
1716
+ // Don't add empty line for last part with only types
1717
+ bodyParts.push(new Blob([orderedLines.join("\r\n")]))
1718
+ } else if (fieldLines.length === 0) {
1719
+ bodyParts.push(new Blob([orderedLines.join("\r\n")]))
1720
+ } else {
1721
+ bodyParts.push(new Blob([orderedLines.join("\r\n") + "\r\n"]))
1722
+ }
1723
+ }
1724
+ } else {
1725
+ // Put ao-types first, then content-disposition, then field lines
1726
+ const orderedLines = []
1727
+
1728
+ if (allTypes.length > 0) {
1729
+ orderedLines.push(`ao-types: ${allTypes.sort().join(", ")}`)
1730
+ }
1731
+
1732
+ orderedLines.push(`content-disposition: form-data;name="${bodyKey}"`)
1733
+
1734
+ // Check if we have any binary fields
1735
+ const hasBinaryFields = binaryFields && binaryFields.length > 0
1736
+
1737
+ // Add blank line before field lines if we have binary fields or no field lines
1738
+ if (hasBinaryFields || fieldLines.length === 0) {
1739
+ orderedLines.push("")
1740
+ }
1741
+
1742
+ // Add field lines
1743
+ for (const line of fieldLines) {
1744
+ orderedLines.push(line)
1745
+ }
1746
+
1747
+ if (binaryFields && binaryFields.length > 0) {
1748
+ const parts = []
1749
+ const headerText = orderedLines.join("\r\n")
1750
+ parts.push(Buffer.from(headerText))
1751
+
1752
+ for (let i = 0; i < binaryFields.length; i++) {
1753
+ const { key, buffer } = binaryFields[i]
1754
+ if (i > 0) {
1755
+ parts.push(Buffer.from("\r\n"))
1756
+ }
1757
+ parts.push(Buffer.from(`${key}: `))
1758
+ parts.push(buffer)
1759
+ }
1760
+
1761
+ parts.push(Buffer.from("\r\n"))
1762
+ const fullBody = Buffer.concat(parts)
1763
+ bodyParts.push(new Blob([fullBody]))
1764
+ } else {
1765
+ // Add trailing blank line if we have field lines
1766
+ if (fieldLines.length > 0) {
1767
+ bodyParts.push(new Blob([orderedLines.join("\r\n") + "\r\n"]))
1768
+ } else {
1769
+ bodyParts.push(new Blob([orderedLines.join("\r\n")]))
1770
+ }
1771
+ }
1772
+ }
1773
+
1774
+ continue
1775
+ }
1776
+
1443
1777
  const isInline = bodyKey === "body" && headers["inline-body-key"] === "body"
1444
1778
  if (isInline) {
1445
1779
  lines.push(`content-disposition: inline`)
@@ -1447,7 +1781,11 @@ async function encode(obj = {}) {
1447
1781
  lines.push(`content-disposition: form-data;name="${bodyKey}"`)
1448
1782
  }
1449
1783
 
1450
- if (typeof value === "string") {
1784
+ if (isBytes(value)) {
1785
+ const buffer = toBuffer(value)
1786
+ const headerText = lines.join("\r\n") + "\r\n\r\n"
1787
+ bodyParts.push(new Blob([headerText, buffer]))
1788
+ } else if (typeof value === "string") {
1451
1789
  lines.push("")
1452
1790
  lines.push(value)
1453
1791
  bodyParts.push(new Blob([lines.join("\r\n")]))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wao",
3
- "version": "0.27.2",
3
+ "version": "0.27.3",
4
4
  "bin": {
5
5
  "wao": "./cjs/cli.js",
6
6
  "wao-esm": "./esm/cli.js"