hbsig 0.0.1

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 (44) hide show
  1. package/cjs/bin_to_str.js +44 -0
  2. package/cjs/collect-body-keys.js +470 -0
  3. package/cjs/encode-array-item.js +110 -0
  4. package/cjs/encode-utils.js +236 -0
  5. package/cjs/encode.js +1318 -0
  6. package/cjs/erl_json.js +317 -0
  7. package/cjs/erl_str.js +1037 -0
  8. package/cjs/flat.js +222 -0
  9. package/cjs/http-message-signatures/httpbis.js +489 -0
  10. package/cjs/http-message-signatures/index.js +25 -0
  11. package/cjs/http-message-signatures/structured-header.js +129 -0
  12. package/cjs/httpsig.js +716 -0
  13. package/cjs/httpsig2.js +1160 -0
  14. package/cjs/id.js +470 -0
  15. package/cjs/index.js +63 -0
  16. package/cjs/send.js +194 -0
  17. package/cjs/signer-utils.js +617 -0
  18. package/cjs/signer.js +606 -0
  19. package/cjs/structured.js +296 -0
  20. package/cjs/test.js +27 -0
  21. package/cjs/utils.js +42 -0
  22. package/esm/bin_to_str.js +46 -0
  23. package/esm/collect-body-keys.js +436 -0
  24. package/esm/encode-array-item.js +112 -0
  25. package/esm/encode-utils.js +185 -0
  26. package/esm/encode.js +1219 -0
  27. package/esm/erl_json.js +289 -0
  28. package/esm/erl_str.js +1139 -0
  29. package/esm/flat.js +196 -0
  30. package/esm/http-message-signatures/httpbis.js +438 -0
  31. package/esm/http-message-signatures/index.js +4 -0
  32. package/esm/http-message-signatures/structured-header.js +105 -0
  33. package/esm/httpsig.js +658 -0
  34. package/esm/httpsig2.js +1097 -0
  35. package/esm/id.js +459 -0
  36. package/esm/index.js +4 -0
  37. package/esm/package.json +3 -0
  38. package/esm/send.js +124 -0
  39. package/esm/signer-utils.js +494 -0
  40. package/esm/signer.js +452 -0
  41. package/esm/structured.js +269 -0
  42. package/esm/test.js +6 -0
  43. package/esm/utils.js +28 -0
  44. package/package.json +28 -0
package/cjs/httpsig.js ADDED
@@ -0,0 +1,716 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.httpsig_from = httpsig_from;
7
+ exports.httpsig_to = httpsig_to;
8
+ var _crypto = _interopRequireDefault(require("crypto"));
9
+ var _flat = require("./flat.js");
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
11
+ function _toArray(r) { return _arrayWithHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableRest(); }
12
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
13
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
14
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
15
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
16
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
17
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
18
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
19
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
20
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
21
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
22
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
23
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
24
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
25
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
26
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
27
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
28
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } // httpsig.js - JavaScript implementation of HTTP Signature codec
29
+ var CRLF = "\r\n";
30
+ var DOUBLE_CRLF = CRLF + CRLF;
31
+ var MAX_HEADER_LENGTH = 4096;
32
+
33
+ // Helper to normalize keys (lowercase only, no underscore conversion)
34
+ function normalizeKey(key) {
35
+ if (typeof key === "string") {
36
+ return key.toLowerCase();
37
+ }
38
+ return String(key).toLowerCase();
39
+ }
40
+
41
+ // Helper to check if a value is an ID (43 character base64url string)
42
+ function isId(value) {
43
+ return typeof value === "string" && value.length === 43 && /^[A-Za-z0-9_-]+$/.test(value);
44
+ }
45
+
46
+ // Helper to encode structured field dictionary
47
+ function encodeSfDict(dict) {
48
+ var items = [];
49
+ for (var _i = 0, _Object$entries = Object.entries(dict); _i < _Object$entries.length; _i++) {
50
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
51
+ key = _Object$entries$_i[0],
52
+ value = _Object$entries$_i[1];
53
+ if (typeof value === "string") {
54
+ items.push("".concat(key, "=\"").concat(value, "\""));
55
+ } else {
56
+ items.push("".concat(key, "=").concat(value));
57
+ }
58
+ }
59
+ return items.join(", ");
60
+ }
61
+
62
+ // Helper to parse structured field dictionary
63
+ function parseSfDict(str) {
64
+ var dict = {};
65
+ if (!str) return dict;
66
+ var parts = str.split(/,\s*/);
67
+ var _iterator = _createForOfIteratorHelper(parts),
68
+ _step;
69
+ try {
70
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
71
+ var part = _step.value;
72
+ var match = part.match(/^([^=]+)=(.+)$/);
73
+ if (match) {
74
+ var key = match[1].trim();
75
+ var value = match[2].trim();
76
+ if (value.startsWith('"') && value.endsWith('"')) {
77
+ value = value.slice(1, -1);
78
+ }
79
+ dict[key] = value;
80
+ }
81
+ }
82
+ } catch (err) {
83
+ _iterator.e(err);
84
+ } finally {
85
+ _iterator.f();
86
+ }
87
+ return dict;
88
+ }
89
+
90
+ // Helper to generate boundary from parts
91
+ function boundaryFromParts(parts) {
92
+ var bodyBin = parts.map(function (p) {
93
+ return p.body;
94
+ }).join(CRLF);
95
+ var hash = _crypto["default"].createHash("sha256");
96
+ hash.update(bodyBin);
97
+ return hash.digest("base64url");
98
+ }
99
+
100
+ // Helper to determine inline key
101
+ function inlineKey(msg) {
102
+ var inlineBodyKey = msg["inline-body-key"];
103
+ if (inlineBodyKey) {
104
+ return [{}, inlineBodyKey];
105
+ }
106
+ if ("body" in msg) {
107
+ return [{}, "body"];
108
+ }
109
+ if ("data" in msg) {
110
+ return [{
111
+ "inline-body-key": "data"
112
+ }, "data"];
113
+ }
114
+ return [{}, "body"];
115
+ }
116
+
117
+ // Group IDs into ao-ids field
118
+ function groupIds(map) {
119
+ var idDict = {};
120
+ var stripped = {};
121
+ for (var _i2 = 0, _Object$entries2 = Object.entries(map); _i2 < _Object$entries2.length; _i2++) {
122
+ var _Object$entries2$_i = _slicedToArray(_Object$entries2[_i2], 2),
123
+ key = _Object$entries2$_i[0],
124
+ value = _Object$entries2$_i[1];
125
+ if (isId(key) && typeof value === "string") {
126
+ // Store with lowercase key as in Erlang
127
+ idDict[key.toLowerCase()] = value;
128
+ } else {
129
+ stripped[key] = value;
130
+ }
131
+ }
132
+ if (Object.keys(idDict).length > 0) {
133
+ var items = [];
134
+ for (var _i3 = 0, _Object$entries3 = Object.entries(idDict); _i3 < _Object$entries3.length; _i3++) {
135
+ var _Object$entries3$_i = _slicedToArray(_Object$entries3[_i3], 2),
136
+ k = _Object$entries3$_i[0],
137
+ v = _Object$entries3$_i[1];
138
+ items.push("".concat(k, "=\"").concat(v, "\""));
139
+ }
140
+ stripped["ao-ids"] = items.join(", ");
141
+ }
142
+
143
+ // Return IDs as lowercase in the result since they will be normalized
144
+ // when processed as headers
145
+ for (var _i4 = 0, _Object$entries4 = Object.entries(idDict); _i4 < _Object$entries4.length; _i4++) {
146
+ var _Object$entries4$_i = _slicedToArray(_Object$entries4[_i4], 2),
147
+ _k = _Object$entries4$_i[0],
148
+ _v = _Object$entries4$_i[1];
149
+ stripped[_k] = _v;
150
+ }
151
+ return stripped;
152
+ }
153
+
154
+ // Ungroup IDs from ao-ids field
155
+ function ungroupIds(msg) {
156
+ if (!msg["ao-ids"]) return msg;
157
+ var result = _objectSpread({}, msg);
158
+ delete result["ao-ids"];
159
+ var dict = parseSfDict(msg["ao-ids"]);
160
+ for (var _i5 = 0, _Object$entries5 = Object.entries(dict); _i5 < _Object$entries5.length; _i5++) {
161
+ var _Object$entries5$_i = _slicedToArray(_Object$entries5[_i5], 2),
162
+ key = _Object$entries5$_i[0],
163
+ value = _Object$entries5$_i[1];
164
+ // ao-ids keys are lowercase, use them as-is
165
+ result[key] = value;
166
+ }
167
+ return result;
168
+ }
169
+
170
+ // Group maps for body encoding - following Erlang logic exactly
171
+ function groupMaps(map) {
172
+ var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
173
+ var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
174
+ if (_typeof(map) !== "object" || map === null || Array.isArray(map) || Buffer.isBuffer(map)) {
175
+ return top;
176
+ }
177
+ var flattened = {};
178
+ var newTop = _objectSpread({}, top);
179
+
180
+ // Process entries in sorted order for consistency
181
+ var entries = Object.entries(map).sort(function (_ref, _ref2) {
182
+ var _ref3 = _slicedToArray(_ref, 1),
183
+ a = _ref3[0];
184
+ var _ref4 = _slicedToArray(_ref2, 1),
185
+ b = _ref4[0];
186
+ return a.localeCompare(b);
187
+ });
188
+ var _iterator2 = _createForOfIteratorHelper(entries),
189
+ _step2;
190
+ try {
191
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
192
+ var _step2$value = _slicedToArray(_step2.value, 2),
193
+ key = _step2$value[0],
194
+ value = _step2$value[1];
195
+ // Normalize keys to lowercase
196
+ var normKey = normalizeKey(key);
197
+ var flatK = parent ? "".concat(parent, "/").concat(normKey) : normKey;
198
+ if (_typeof(value) === "object" && value !== null && !Array.isArray(value) && !Buffer.isBuffer(value)) {
199
+ // Recursively process nested objects
200
+ newTop = groupMaps(value, flatK, newTop);
201
+ } else if (typeof value === "string" && value.length > MAX_HEADER_LENGTH) {
202
+ // Value too large for header, lift to top level
203
+ newTop[flatK] = value;
204
+ } else if (Buffer.isBuffer(value) && value.length > MAX_HEADER_LENGTH) {
205
+ // Large buffers also get lifted to top level
206
+ newTop[flatK] = value;
207
+ } else {
208
+ // Keep in current flattened map
209
+ flattened[normKey] = value;
210
+ }
211
+ }
212
+ } catch (err) {
213
+ _iterator2.e(err);
214
+ } finally {
215
+ _iterator2.f();
216
+ }
217
+ if (Object.keys(flattened).length === 0) {
218
+ return newTop;
219
+ } else if (parent) {
220
+ // Add flattened map under parent key
221
+ return _objectSpread(_objectSpread({}, newTop), {}, _defineProperty({}, parent, flattened));
222
+ } else {
223
+ // Merge flattened with top level
224
+ return _objectSpread(_objectSpread({}, newTop), flattened);
225
+ }
226
+ }
227
+
228
+ // Encode multipart body part
229
+ function encodeBodyPart(partName, bodyPart, inlineKey) {
230
+ var disposition = partName === inlineKey ? "inline" : "form-data;name=\"".concat(partName, "\"");
231
+ var isInline = partName === inlineKey;
232
+ if (_typeof(bodyPart) === "object" && bodyPart !== null && !Array.isArray(bodyPart) && !Buffer.isBuffer(bodyPart)) {
233
+ // Check if this part has ao-types
234
+ var hasAoTypes = "ao-types" in bodyPart;
235
+ if (hasAoTypes) {
236
+ // For parts WITH ao-types: sort all entries alphabetically
237
+ var allEntries = [];
238
+
239
+ // Collect all entries except body
240
+ for (var _i6 = 0, _Object$entries6 = Object.entries(bodyPart); _i6 < _Object$entries6.length; _i6++) {
241
+ var _Object$entries6$_i = _slicedToArray(_Object$entries6[_i6], 2),
242
+ key = _Object$entries6$_i[0],
243
+ value = _Object$entries6$_i[1];
244
+ if (key === "body") continue;
245
+ if (key === "ao-types") {
246
+ allEntries.push({
247
+ key: "ao-types",
248
+ line: "ao-types: ".concat(value)
249
+ });
250
+ } else {
251
+ // Handle Buffer values properly
252
+ var valueStr = value;
253
+ if (Buffer.isBuffer(value)) {
254
+ // Use binary/latin1 encoding to preserve all byte values 0-255
255
+ valueStr = value.toString("binary");
256
+ }
257
+ allEntries.push({
258
+ key: key,
259
+ line: "".concat(key, ": ").concat(valueStr)
260
+ });
261
+ }
262
+ }
263
+
264
+ // Add content-disposition
265
+ allEntries.push({
266
+ key: "content-disposition",
267
+ line: "content-disposition: ".concat(disposition)
268
+ });
269
+
270
+ // Sort alphabetically by key
271
+ allEntries.sort(function (a, b) {
272
+ return a.key.localeCompare(b.key);
273
+ });
274
+
275
+ // Build the lines
276
+ var lines = allEntries.map(function (entry) {
277
+ return entry.line;
278
+ });
279
+
280
+ // Body handling
281
+ var body = bodyPart.body || "";
282
+ if (body) {
283
+ lines.push(""); // Always add empty line before body
284
+ lines.push(body);
285
+ }
286
+ return lines.join(CRLF);
287
+ } else {
288
+ // For parts WITHOUT ao-types
289
+ var _allEntries = [];
290
+ for (var _i7 = 0, _Object$entries7 = Object.entries(bodyPart); _i7 < _Object$entries7.length; _i7++) {
291
+ var _Object$entries7$_i = _slicedToArray(_Object$entries7[_i7], 2),
292
+ _key = _Object$entries7$_i[0],
293
+ _value = _Object$entries7$_i[1];
294
+ if (_key === "body") continue;
295
+ // Handle Buffer values properly
296
+ var _valueStr = _value;
297
+ if (Buffer.isBuffer(_value)) {
298
+ // Use binary/latin1 encoding to preserve all byte values 0-255
299
+ _valueStr = _value.toString("binary");
300
+ }
301
+ _allEntries.push({
302
+ key: _key,
303
+ line: "".concat(_key, ": ").concat(_valueStr)
304
+ });
305
+ }
306
+ var _lines = [];
307
+ if (isInline) {
308
+ // Inline parts without ao-types: sort ALL fields alphabetically including content-disposition
309
+ _allEntries.push({
310
+ key: "content-disposition",
311
+ line: "content-disposition: ".concat(disposition)
312
+ });
313
+
314
+ // Sort by key
315
+ _allEntries.sort(function (a, b) {
316
+ return a.key.localeCompare(b.key);
317
+ });
318
+
319
+ // Extract the lines
320
+ _lines.push.apply(_lines, _toConsumableArray(_allEntries.map(function (entry) {
321
+ return entry.line;
322
+ })));
323
+ } else {
324
+ // Regular parts: content-disposition first, then fields
325
+ _lines.push("content-disposition: ".concat(disposition));
326
+ _lines.push.apply(_lines, _toConsumableArray(_allEntries.map(function (entry) {
327
+ return entry.line;
328
+ })));
329
+ }
330
+
331
+ // Body handling
332
+ var _body = bodyPart.body || "";
333
+ if (_body) {
334
+ _lines.push(""); // Always add empty line before body
335
+ _lines.push(_body);
336
+ }
337
+ return _lines.join(CRLF);
338
+ }
339
+ } else if (typeof bodyPart === "string" || Buffer.isBuffer(bodyPart)) {
340
+ return "content-disposition: ".concat(disposition).concat(DOUBLE_CRLF).concat(bodyPart);
341
+ }
342
+ return "";
343
+ }
344
+
345
+ // Parse multipart body
346
+ function parseMultipart(contentType, body) {
347
+ var boundaryMatch = contentType.match(/boundary="?([^";\s]+)"?/);
348
+ if (!boundaryMatch) return {};
349
+ var boundary = boundaryMatch[1];
350
+ var boundaryDelim = "--".concat(boundary);
351
+ var endBoundary = "--".concat(boundary, "--");
352
+
353
+ // Remove the final boundary terminator if present
354
+ var bodyContent = body;
355
+ if (bodyContent.endsWith(endBoundary)) {
356
+ bodyContent = bodyContent.substring(0, bodyContent.lastIndexOf(endBoundary));
357
+ }
358
+ var parts = bodyContent.split(new RegExp("\\r?\\n?".concat(boundaryDelim, "\\r?\\n"))).filter(function (p) {
359
+ return p && p.trim() && !p.startsWith("--");
360
+ });
361
+ var result = {};
362
+ var bodyKeysList = [];
363
+ var _iterator3 = _createForOfIteratorHelper(parts),
364
+ _step3;
365
+ try {
366
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
367
+ var part = _step3.value;
368
+ var _part$split = part.split(DOUBLE_CRLF),
369
+ _part$split2 = _toArray(_part$split),
370
+ headerBlock = _part$split2[0],
371
+ bodyParts = _part$split2.slice(1);
372
+ var partBody = bodyParts.join(DOUBLE_CRLF);
373
+
374
+ // Remove trailing CRLF
375
+ partBody = partBody.replace(/\r?\n?$/, "");
376
+ var headers = {};
377
+ var headerLines = headerBlock.split(/\r?\n/);
378
+ var _iterator4 = _createForOfIteratorHelper(headerLines),
379
+ _step4;
380
+ try {
381
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
382
+ var line = _step4.value;
383
+ var colonIndex = line.indexOf(": ");
384
+ if (colonIndex > 0) {
385
+ var name = line.substring(0, colonIndex).toLowerCase();
386
+ var value = line.substring(colonIndex + 2);
387
+ headers[name] = value;
388
+ }
389
+ }
390
+ } catch (err) {
391
+ _iterator4.e(err);
392
+ } finally {
393
+ _iterator4.f();
394
+ }
395
+ var disposition = headers["content-disposition"];
396
+ if (!disposition) continue;
397
+ var partName = void 0;
398
+ if (disposition === "inline") {
399
+ partName = "body";
400
+ bodyKeysList.push("body");
401
+ } else {
402
+ var nameMatch = disposition.match(/name="([^"]+)"/);
403
+ partName = nameMatch ? nameMatch[1] : null;
404
+ if (partName) {
405
+ // Add the top-level key for this part
406
+ var topLevelKey = partName.split("/")[0];
407
+ bodyKeysList.push(topLevelKey);
408
+ }
409
+ }
410
+ if (!partName) continue;
411
+ var restHeaders = _objectSpread({}, headers);
412
+ delete restHeaders["content-disposition"];
413
+ if (Object.keys(restHeaders).length === 0) {
414
+ result[partName] = partBody;
415
+ } else if (!partBody) {
416
+ result[partName] = restHeaders;
417
+ } else {
418
+ result[partName] = _objectSpread(_objectSpread({}, restHeaders), {}, {
419
+ body: partBody
420
+ });
421
+ }
422
+ }
423
+ } catch (err) {
424
+ _iterator3.e(err);
425
+ } finally {
426
+ _iterator3.f();
427
+ }
428
+ if (bodyKeysList.length > 0) {
429
+ // Format as structured field list, preserving order and duplicates
430
+ result["body-keys"] = bodyKeysList.map(function (k) {
431
+ return "\"".concat(k, "\"");
432
+ }).join(", ");
433
+ }
434
+ return result;
435
+ }
436
+
437
+ // Add content-digest header
438
+ function addContentDigest(msg) {
439
+ if (!msg.body) return msg;
440
+ var hash = _crypto["default"].createHash("sha256");
441
+
442
+ // Handle both string and Buffer bodies
443
+ if (Buffer.isBuffer(msg.body)) {
444
+ hash.update(msg.body);
445
+ } else {
446
+ // For strings, use binary encoding to match how the multipart body is encoded
447
+ hash.update(msg.body, "binary");
448
+ }
449
+ var digest = hash.digest("base64");
450
+ return _objectSpread(_objectSpread({}, msg), {}, {
451
+ "content-digest": "sha-256=:".concat(digest, ":")
452
+ });
453
+ }
454
+
455
+ /**
456
+ * Convert HTTP message to TABM
457
+ */
458
+ function httpsig_from(http) {
459
+ if (typeof http === "string") return http;
460
+ var body = http.body || "";
461
+ var _inlineKey = inlineKey(http),
462
+ _inlineKey2 = _slicedToArray(_inlineKey, 2),
463
+ inlinedFieldHdrs = _inlineKey2[0],
464
+ inlinedKey = _inlineKey2[1];
465
+ var headers = _objectSpread({}, http);
466
+ delete headers.body;
467
+ delete headers["body-keys"];
468
+ var contentType = headers["content-type"];
469
+ var withBodyKeys = headers;
470
+
471
+ // Parse multipart body if present
472
+ if (body && contentType && contentType.includes("multipart")) {
473
+ var parsed = parseMultipart(contentType, body);
474
+
475
+ // Handle the body-keys from the original HTTP message
476
+ if (http["body-keys"]) {
477
+ // Parse the existing body-keys and ensure they're in quoted format
478
+ var bodyKeys = http["body-keys"];
479
+ if (typeof bodyKeys === "string") {
480
+ if (!bodyKeys.includes('"')) {
481
+ // Convert unquoted format to quoted format
482
+ parsed["body-keys"] = bodyKeys.split(/,\s*/).map(function (k) {
483
+ return "\"".concat(k.trim(), "\"");
484
+ }).join(", ");
485
+ } else {
486
+ // Already quoted, use as-is
487
+ parsed["body-keys"] = bodyKeys;
488
+ }
489
+ }
490
+ }
491
+ withBodyKeys = _objectSpread(_objectSpread({}, headers), parsed);
492
+
493
+ // Convert flat structure to nested using flat.js
494
+ var flat = {};
495
+ for (var _i8 = 0, _Object$entries8 = Object.entries(withBodyKeys); _i8 < _Object$entries8.length; _i8++) {
496
+ var _Object$entries8$_i = _slicedToArray(_Object$entries8[_i8], 2),
497
+ key = _Object$entries8$_i[0],
498
+ value = _Object$entries8$_i[1];
499
+ if (key.includes("/")) {
500
+ flat[key] = value;
501
+ }
502
+ }
503
+ if (Object.keys(flat).length > 0) {
504
+ // Use flat_from to convert flat structure to nested
505
+ var nested = (0, _flat.flat_from)(flat);
506
+ for (var _i9 = 0, _Object$entries9 = Object.entries(nested); _i9 < _Object$entries9.length; _i9++) {
507
+ var _Object$entries9$_i = _slicedToArray(_Object$entries9[_i9], 2),
508
+ _key2 = _Object$entries9$_i[0],
509
+ _value2 = _Object$entries9$_i[1];
510
+ withBodyKeys[_key2] = _value2;
511
+ }
512
+ for (var _i0 = 0, _Object$keys = Object.keys(flat); _i0 < _Object$keys.length; _i0++) {
513
+ var _key3 = _Object$keys[_i0];
514
+ delete withBodyKeys[_key3];
515
+ }
516
+ }
517
+ } else if (body) {
518
+ withBodyKeys[inlinedKey] = body;
519
+ }
520
+
521
+ // Ungroup IDs
522
+ var withIds = ungroupIds(withBodyKeys);
523
+
524
+ // Remove signature-related headers and content-digest
525
+ var result = _objectSpread({}, withIds);
526
+ delete result.signature;
527
+ delete result["signature-input"];
528
+ delete result.commitments;
529
+ delete result["content-digest"];
530
+
531
+ // Extract hashpaths if any
532
+ for (var _i1 = 0, _Object$keys2 = Object.keys(result); _i1 < _Object$keys2.length; _i1++) {
533
+ var _key4 = _Object$keys2[_i1];
534
+ if (_key4.startsWith("hashpath")) {
535
+ delete result[_key4];
536
+ }
537
+ }
538
+ return result;
539
+ }
540
+
541
+ /**
542
+ * Convert TABM to HTTP message
543
+ */
544
+ function httpsig_to(tabm) {
545
+ if (typeof tabm === "string") return tabm;
546
+
547
+ // Group IDs
548
+ var withGroupedIds = groupIds(tabm);
549
+
550
+ // Remove private and signature-related keys
551
+ var stripped = _objectSpread({}, withGroupedIds);
552
+ delete stripped.commitments;
553
+ delete stripped.signature;
554
+ delete stripped["signature-input"];
555
+ delete stripped.priv;
556
+ var _inlineKey3 = inlineKey(tabm),
557
+ _inlineKey4 = _slicedToArray(_inlineKey3, 2),
558
+ inlineFieldHdrs = _inlineKey4[0],
559
+ inlineKeyVal = _inlineKey4[1];
560
+
561
+ // Check if this is a flat structure that should stay as headers
562
+ // A flat structure has no nested objects (maps)
563
+ var hasNestedMaps = Object.values(stripped).some(function (value) {
564
+ return _typeof(value) === "object" && value !== null && !Array.isArray(value) && !Buffer.isBuffer(value);
565
+ });
566
+
567
+ // If it's just a flat map with strings/primitives, keep as headers
568
+ // This matches Erlang's behavior where flat maps don't become multipart
569
+ if (!hasNestedMaps) {
570
+ // For flat structures, just return with normalized keys
571
+ // This matches Erlang which returns the map unchanged
572
+ var result = _objectSpread({}, inlineFieldHdrs);
573
+ for (var _i10 = 0, _Object$entries0 = Object.entries(stripped); _i10 < _Object$entries0.length; _i10++) {
574
+ var _Object$entries0$_i = _slicedToArray(_Object$entries0[_i10], 2),
575
+ key = _Object$entries0$_i[0],
576
+ value = _Object$entries0$_i[1];
577
+ // Convert Buffers to strings if they're UTF-8 text
578
+ if (Buffer.isBuffer(value)) {
579
+ try {
580
+ var str = value.toString("utf8");
581
+ // Check if it's valid UTF-8 that can be safely converted
582
+ if (Buffer.from(str, "utf8").equals(value)) {
583
+ // Check if all characters are printable
584
+ var isPrintable = true;
585
+ for (var i = 0; i < str.length; i++) {
586
+ var code = str.charCodeAt(i);
587
+ if (!(code >= 32 && code <= 126) && code !== 9 && code !== 10 && code !== 13) {
588
+ isPrintable = false;
589
+ break;
590
+ }
591
+ }
592
+ if (isPrintable) {
593
+ result[key] = str;
594
+ } else {
595
+ result[key] = value;
596
+ }
597
+ } else {
598
+ result[key] = value;
599
+ }
600
+ } catch (e) {
601
+ result[key] = value;
602
+ }
603
+ } else {
604
+ result[key] = value;
605
+ }
606
+ }
607
+
608
+ // Handle inline body key - move data from inline key to body
609
+ if (inlineKeyVal && inlineKeyVal !== "body" && result[inlineKeyVal]) {
610
+ result.body = result[inlineKeyVal];
611
+ delete result[inlineKeyVal];
612
+ }
613
+
614
+ // If there's a body, add content-digest
615
+ if (result.body) {
616
+ return addContentDigest(result);
617
+ }
618
+ return result;
619
+ }
620
+
621
+ // Original multipart logic for nested structures
622
+ var bodyMap = {};
623
+ var headers = _objectSpread({}, inlineFieldHdrs);
624
+
625
+ // Process each field - ao-types at top level should go to headers
626
+ for (var _i11 = 0, _Object$entries1 = Object.entries(stripped); _i11 < _Object$entries1.length; _i11++) {
627
+ var _Object$entries1$_i = _slicedToArray(_Object$entries1[_i11], 2),
628
+ _key5 = _Object$entries1$_i[0],
629
+ _value3 = _Object$entries1$_i[1];
630
+ if (_key5 === "ao-types") {
631
+ // Top-level ao-types goes to headers only
632
+ // Convert Buffer to string if needed
633
+ if (Buffer.isBuffer(_value3)) {
634
+ headers[_key5] = _value3.toString("utf8");
635
+ } else {
636
+ headers[_key5] = _value3;
637
+ }
638
+ } else if (_key5 === "body" || _key5 === inlineKeyVal) {
639
+ bodyMap[_key5 === inlineKeyVal ? inlineKeyVal : "body"] = _value3;
640
+ } else if (_typeof(_value3) === "object" && _value3 !== null && !Array.isArray(_value3) && !Buffer.isBuffer(_value3)) {
641
+ bodyMap[_key5] = _value3;
642
+ } else if (typeof _value3 === "string" && _value3.length <= MAX_HEADER_LENGTH && _key5 !== "ao-types") {
643
+ headers[normalizeKey(_key5)] = _value3;
644
+ } else if (Buffer.isBuffer(_value3) && _value3.length <= MAX_HEADER_LENGTH && _key5 !== "ao-types") {
645
+ // Convert Buffers to strings for headers
646
+ var _str = _value3.toString("utf8");
647
+ headers[normalizeKey(_key5)] = _str;
648
+ } else if (_key5 !== "ao-types") {
649
+ // Only add to bodyMap if it's not ao-types
650
+ bodyMap[_key5] = _value3;
651
+ }
652
+ }
653
+
654
+ // Handle body encoding
655
+ var groupedBodyMap = groupMaps(bodyMap);
656
+ if (Object.keys(groupedBodyMap).length === 0) {
657
+ return headers;
658
+ } else if (Object.keys(groupedBodyMap).length === 1 && groupedBodyMap[inlineKeyVal] && typeof groupedBodyMap[inlineKeyVal] === "string") {
659
+ var _result = _objectSpread(_objectSpread({}, headers), {}, {
660
+ body: groupedBodyMap[inlineKeyVal]
661
+ });
662
+ return addContentDigest(_result);
663
+ } else {
664
+ // Multipart body
665
+ var parts = [];
666
+ var bodyKeysList = [];
667
+ var sortedEntries = Object.entries(groupedBodyMap).sort(function (_ref5, _ref6) {
668
+ var _ref7 = _slicedToArray(_ref5, 1),
669
+ a = _ref7[0];
670
+ var _ref8 = _slicedToArray(_ref6, 1),
671
+ b = _ref8[0];
672
+ return a.localeCompare(b);
673
+ });
674
+ var _iterator5 = _createForOfIteratorHelper(sortedEntries),
675
+ _step5;
676
+ try {
677
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
678
+ var _step5$value = _slicedToArray(_step5.value, 2),
679
+ _key6 = _step5$value[0],
680
+ _value4 = _step5$value[1];
681
+ if (_typeof(_value4) === "object" && _value4 !== null && Object.keys(_value4).length === 1 && "body" in _value4) {
682
+ var encoded = encodeBodyPart("".concat(_key6, "/body"), _value4, "body");
683
+ parts.push({
684
+ name: "".concat(_key6, "/body"),
685
+ body: encoded
686
+ });
687
+ bodyKeysList.push(_key6);
688
+ } else {
689
+ var _encoded = encodeBodyPart(_key6, _value4, inlineKeyVal);
690
+ parts.push({
691
+ name: _key6,
692
+ body: _encoded
693
+ });
694
+ bodyKeysList.push(_key6);
695
+ }
696
+ }
697
+ } catch (err) {
698
+ _iterator5.e(err);
699
+ } finally {
700
+ _iterator5.f();
701
+ }
702
+ var boundary = boundaryFromParts(parts);
703
+ var bodyParts = parts.map(function (p) {
704
+ return "--".concat(boundary).concat(CRLF).concat(p.body);
705
+ });
706
+ var finalBody = bodyParts.join(CRLF) + "".concat(CRLF, "--").concat(boundary, "--");
707
+ var _result2 = _objectSpread(_objectSpread({}, headers), {}, {
708
+ "body-keys": bodyKeysList.map(function (k) {
709
+ return "\"".concat(k, "\"");
710
+ }).join(", "),
711
+ "content-type": "multipart/form-data; boundary=\"".concat(boundary, "\""),
712
+ body: finalBody
713
+ });
714
+ return addContentDigest(_result2);
715
+ }
716
+ }