@hamradio/meshcore 1.2.1 → 1.3.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.
package/dist/index.js CHANGED
@@ -1,44 +1,3 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var index_exports = {};
22
- __export(index_exports, {
23
- Contact: () => Contact,
24
- Contacts: () => Contacts,
25
- Group: () => Group,
26
- Identity: () => Identity,
27
- LocalIdentity: () => LocalIdentity,
28
- NodeType: () => NodeType,
29
- Packet: () => Packet,
30
- PayloadType: () => PayloadType,
31
- PrivateKey: () => PrivateKey,
32
- PublicKey: () => PublicKey,
33
- RequestType: () => RequestType,
34
- RouteType: () => RouteType,
35
- SharedSecret: () => SharedSecret,
36
- StaticSecret: () => StaticSecret,
37
- TextType: () => TextType,
38
- parseNodeHash: () => parseNodeHash
39
- });
40
- module.exports = __toCommonJS(index_exports);
41
-
42
1
  // src/packet.types.ts
43
2
  var RouteType = /* @__PURE__ */ ((RouteType2) => {
44
3
  RouteType2[RouteType2["TRANSPORT_FLOOD"] = 0] = "TRANSPORT_FLOOD";
@@ -86,127 +45,8 @@ var NodeType = /* @__PURE__ */ ((NodeType2) => {
86
45
  })(NodeType || {});
87
46
 
88
47
  // src/packet.ts
89
- var import_sha2 = require("@noble/hashes/sha2.js");
90
-
91
- // src/parser.ts
92
- var import_utils = require("@noble/ciphers/utils.js");
93
- var import_utils2 = require("@noble/hashes/utils.js");
94
- var base64ToBytes = (base64, size) => {
95
- let normalized = base64.replace(/-/g, "+").replace(/_/g, "/");
96
- while (normalized.length % 4 !== 0) {
97
- normalized += "=";
98
- }
99
- const binaryString = atob(normalized);
100
- const bytes = new Uint8Array(binaryString.length);
101
- for (let i = 0; i < binaryString.length; i++) {
102
- bytes[i] = binaryString.charCodeAt(i);
103
- }
104
- if (size !== void 0 && bytes.length !== size) {
105
- throw new Error(`Invalid base64 length: expected ${size} bytes, got ${bytes.length}`);
106
- }
107
- return bytes;
108
- };
109
- var hexToBytes = (hex, size) => {
110
- const bytes = (0, import_utils2.hexToBytes)(hex);
111
- if (size !== void 0 && bytes.length !== size) {
112
- throw new Error(`Invalid hex length: expected ${size} bytes, got ${bytes.length}`);
113
- }
114
- return bytes;
115
- };
116
- var BufferReader = class {
117
- constructor(buffer) {
118
- this.buffer = buffer;
119
- this.offset = 0;
120
- }
121
- readByte() {
122
- if (!this.hasMore()) throw new Error("read past end");
123
- return this.buffer[this.offset++];
124
- }
125
- readBytes(length) {
126
- if (length === void 0) {
127
- length = this.buffer.length - this.offset;
128
- }
129
- if (this.remainingBytes() < length) throw new Error("read past end");
130
- const bytes = this.buffer.slice(this.offset, this.offset + length);
131
- this.offset += length;
132
- return bytes;
133
- }
134
- hasMore() {
135
- return this.offset < this.buffer.length;
136
- }
137
- remainingBytes() {
138
- return this.buffer.length - this.offset;
139
- }
140
- peekByte() {
141
- if (!this.hasMore()) throw new Error("read past end");
142
- return this.buffer[this.offset];
143
- }
144
- readUint16LE() {
145
- if (this.remainingBytes() < 2) throw new Error("read past end");
146
- const value = this.buffer[this.offset] | this.buffer[this.offset + 1] << 8;
147
- this.offset += 2;
148
- return value;
149
- }
150
- readUint32LE() {
151
- if (this.remainingBytes() < 4) throw new Error("read past end");
152
- const value = (this.buffer[this.offset] | this.buffer[this.offset + 1] << 8 | this.buffer[this.offset + 2] << 16 | this.buffer[this.offset + 3] << 24) >>> 0;
153
- this.offset += 4;
154
- return value;
155
- }
156
- readInt16LE() {
157
- if (this.remainingBytes() < 2) throw new Error("read past end");
158
- const value = this.buffer[this.offset] | this.buffer[this.offset + 1] << 8;
159
- this.offset += 2;
160
- return value < 32768 ? value : value - 65536;
161
- }
162
- readInt32LE() {
163
- if (this.remainingBytes() < 4) throw new Error("read past end");
164
- const u = (this.buffer[this.offset] | this.buffer[this.offset + 1] << 8 | this.buffer[this.offset + 2] << 16 | this.buffer[this.offset + 3] << 24) >>> 0;
165
- this.offset += 4;
166
- return u < 2147483648 ? u : u - 4294967296;
167
- }
168
- readTimestamp() {
169
- const timestamp = this.readUint32LE();
170
- return new Date(timestamp * 1e3);
171
- }
172
- };
173
- var BufferWriter = class {
174
- constructor() {
175
- this.buffer = [];
176
- }
177
- writeByte(value) {
178
- this.buffer.push(value & 255);
179
- }
180
- writeBytes(bytes) {
181
- this.buffer.push(...bytes);
182
- }
183
- writeUint16LE(value) {
184
- this.buffer.push(value & 255, value >> 8 & 255);
185
- }
186
- writeUint32LE(value) {
187
- this.buffer.push(
188
- value & 255,
189
- value >> 8 & 255,
190
- value >> 16 & 255,
191
- value >> 24 & 255
192
- );
193
- }
194
- writeInt16LE(value) {
195
- this.writeUint16LE(value < 0 ? value + 65536 : value);
196
- }
197
- writeInt32LE(value) {
198
- this.writeUint32LE(value < 0 ? value + 4294967296 : value);
199
- }
200
- writeTimestamp(date) {
201
- const timestamp = Math.floor(date.getTime() / 1e3);
202
- this.writeUint32LE(timestamp);
203
- }
204
- toBytes() {
205
- return new Uint8Array(this.buffer);
206
- }
207
- };
208
-
209
- // src/packet.ts
48
+ import { sha256 } from "@noble/hashes/sha2.js";
49
+ import { base64ToBytes, bytesToHex, FieldType, Reader } from "@hamradio/packet";
210
50
  var Packet = class _Packet {
211
51
  constructor(header, transport, pathLength, path, payload) {
212
52
  this.header = header;
@@ -223,7 +63,7 @@ var Packet = class _Packet {
223
63
  this.pathHashes = [];
224
64
  for (let i = 0; i < this.pathHashBytes; i += this.pathHashSize) {
225
65
  const hashBytes = this.path.slice(i, i + this.pathHashSize);
226
- const hashHex = (0, import_utils2.bytesToHex)(hashBytes);
66
+ const hashHex = bytesToHex(hashBytes);
227
67
  this.pathHashes.push(hashHex);
228
68
  }
229
69
  }
@@ -250,14 +90,14 @@ var Packet = class _Packet {
250
90
  return routeType === 0 /* TRANSPORT_FLOOD */ || routeType === 3 /* TRANSPORT_DIRECT */;
251
91
  }
252
92
  hash() {
253
- const hash = import_sha2.sha256.create();
93
+ const hash = sha256.create();
254
94
  hash.update(new Uint8Array([this.payloadType]));
255
95
  if (this.payloadType === 9 /* TRACE */) {
256
96
  hash.update(new Uint8Array([this.pathLength]));
257
97
  }
258
98
  hash.update(this.payload);
259
99
  const digest = hash.digest();
260
- return (0, import_utils2.bytesToHex)(digest.slice(0, 8));
100
+ return bytesToHex(digest.slice(0, 8));
261
101
  }
262
102
  ensureStructure() {
263
103
  if (typeof this.structure !== "undefined") {
@@ -266,60 +106,83 @@ var Packet = class _Packet {
266
106
  let pathHashType;
267
107
  switch (this.pathHashSize) {
268
108
  case 1:
269
- pathHashType = 6 /* BYTES */;
109
+ pathHashType = FieldType.BYTES;
270
110
  break;
271
111
  case 2:
272
- pathHashType = 7 /* WORDS */;
112
+ pathHashType = FieldType.WORDS;
273
113
  break;
274
114
  case 4:
275
- pathHashType = 8 /* DWORDS */;
115
+ pathHashType = FieldType.DWORDS;
276
116
  break;
277
117
  default:
278
118
  throw new Error(`Unsupported path hash size: ${this.pathHashSize}`);
279
119
  }
280
120
  this.structure = [
281
121
  /* Header segment */
282
- { name: "header", data: new Uint8Array([this.header, this.pathLength, ...this.path]), fields: [
283
- /* Header flags */
122
+ {
123
+ name: "header",
124
+ data: new Uint8Array([this.header]).buffer,
125
+ fields: [
126
+ /* Header flags */
127
+ {
128
+ name: "flags",
129
+ type: FieldType.BITS,
130
+ length: 1,
131
+ bits: [
132
+ { name: "payload version", size: 2 },
133
+ { name: "payload type", size: 4 },
134
+ { name: "route type", size: 2 }
135
+ ]
136
+ }
137
+ ]
138
+ },
139
+ /* Transport codes */
140
+ ..._Packet.hasTransportCodes(this.routeType) ? [
284
141
  {
285
- name: "flags",
286
- type: 0 /* BITS */,
287
- size: 1,
288
- bits: [
289
- { name: "payload version", size: 2 },
290
- { name: "payload type", size: 4 },
291
- { name: "route type", size: 2 }
142
+ name: "transport codes",
143
+ data: new Uint8Array([
144
+ this.transport[0] >> 8 & 255,
145
+ this.transport[0] & 255,
146
+ this.transport[1] >> 8 & 255,
147
+ this.transport[1] & 255
148
+ ]).buffer,
149
+ fields: [
150
+ {
151
+ name: "transport code 1",
152
+ type: FieldType.UINT16_BE,
153
+ length: 2,
154
+ value: this.transport[0]
155
+ },
156
+ {
157
+ name: "transport code 2",
158
+ type: FieldType.UINT16_BE,
159
+ length: 2,
160
+ value: this.transport[1]
161
+ }
292
162
  ]
293
- },
294
- /* Transport codes */
295
- ..._Packet.hasTransportCodes(this.routeType) ? [
163
+ }
164
+ ] : [],
165
+ /* Path length and hashes */
166
+ {
167
+ name: "path",
168
+ data: new Uint8Array([this.pathLength, ...this.path]).buffer,
169
+ fields: [
296
170
  {
297
- name: "transport code 1",
298
- type: 3 /* UINT16_BE */,
299
- size: 2
171
+ name: "path length",
172
+ type: FieldType.UINT8,
173
+ length: 1,
174
+ bits: [
175
+ { name: "path hash size", size: 2 },
176
+ { name: "path hash count", size: 6 }
177
+ ]
300
178
  },
301
179
  {
302
- name: "transport code 2",
303
- type: 3 /* UINT16_BE */,
304
- size: 2
180
+ name: "path hashes",
181
+ type: pathHashType,
182
+ length: this.path.length
305
183
  }
306
- ] : [],
307
- /* Path length and hashes */
308
- {
309
- name: "path length",
310
- type: 1 /* UINT8 */,
311
- size: 1,
312
- bits: [
313
- { name: "path hash size", size: 2 },
314
- { name: "path hash count", size: 6 }
315
- ]
316
- },
317
- {
318
- name: "path hashes",
319
- type: pathHashType,
320
- size: this.path.length
321
- }
322
- ] }
184
+ ]
185
+ }
323
186
  ];
324
187
  }
325
188
  decode(withStructure) {
@@ -361,7 +224,6 @@ var Packet = class _Packet {
361
224
  default:
362
225
  throw new Error(`Unsupported payload type: ${this.payloadType}`);
363
226
  }
364
- console.log("packet decode with structure:", typeof withStructure, withStructure, { result });
365
227
  if (typeof withStructure === "boolean" && withStructure && "segment" in result && "payload" in result) {
366
228
  this.ensureStructure();
367
229
  const structure = [...this.structure, result.segment];
@@ -370,17 +232,17 @@ var Packet = class _Packet {
370
232
  return result;
371
233
  }
372
234
  decodeEncryptedPayload(reader) {
373
- const cipherMAC = reader.readBytes(2);
374
- const cipherText = reader.readBytes(reader.remainingBytes());
235
+ const cipherMAC = reader.bytes(2);
236
+ const cipherText = reader.bytes();
375
237
  return { cipherMAC, cipherText };
376
238
  }
377
239
  decodeRequest(withSegment) {
378
240
  if (this.payload.length < 4) {
379
241
  throw new Error("Invalid request payload: too short");
380
242
  }
381
- const reader = new BufferReader(this.payload);
382
- const dst = reader.readByte();
383
- const src = reader.readByte();
243
+ const reader = Reader.fromBytes(this.payload);
244
+ const dst = reader.uint8();
245
+ const src = reader.uint8();
384
246
  const encrypted = this.decodeEncryptedPayload(reader);
385
247
  const payload = {
386
248
  type: 0 /* REQUEST */,
@@ -391,12 +253,17 @@ var Packet = class _Packet {
391
253
  if (typeof withSegment === "boolean" && withSegment) {
392
254
  const segment = {
393
255
  name: "request payload",
394
- data: this.payload,
256
+ data: new Uint8Array(this.payload).buffer,
395
257
  fields: [
396
- { name: "destination hash", type: 1 /* UINT8 */, size: 1, value: dst },
397
- { name: "source hash", type: 1 /* UINT8 */, size: 1, value: src },
398
- { name: "cipher MAC", type: 6 /* BYTES */, size: 2, value: encrypted.cipherMAC },
399
- { name: "cipher text", type: 6 /* BYTES */, size: encrypted.cipherText.length, value: encrypted.cipherText }
258
+ { name: "destination hash", type: FieldType.UINT8, length: 1, value: dst },
259
+ { name: "source hash", type: FieldType.UINT8, length: 1, value: src },
260
+ { name: "cipher MAC", type: FieldType.BYTES, length: 2, value: encrypted.cipherMAC },
261
+ {
262
+ name: "cipher text",
263
+ type: FieldType.BYTES,
264
+ length: encrypted.cipherText.length,
265
+ value: encrypted.cipherText
266
+ }
400
267
  ]
401
268
  };
402
269
  return { payload, segment };
@@ -407,9 +274,9 @@ var Packet = class _Packet {
407
274
  if (this.payload.length < 4) {
408
275
  throw new Error("Invalid response payload: too short");
409
276
  }
410
- const reader = new BufferReader(this.payload);
411
- const dst = reader.readByte();
412
- const src = reader.readByte();
277
+ const reader = Reader.fromBytes(this.payload);
278
+ const dst = reader.uint8();
279
+ const src = reader.uint8();
413
280
  const encrypted = this.decodeEncryptedPayload(reader);
414
281
  const payload = {
415
282
  type: 1 /* RESPONSE */,
@@ -420,12 +287,17 @@ var Packet = class _Packet {
420
287
  if (typeof withSegment === "boolean" && withSegment) {
421
288
  const segment = {
422
289
  name: "response payload",
423
- data: this.payload,
290
+ data: new Uint8Array(this.payload).buffer,
424
291
  fields: [
425
- { name: "destination hash", type: 1 /* UINT8 */, size: 1, value: dst },
426
- { name: "source hash", type: 1 /* UINT8 */, size: 1, value: src },
427
- { name: "cipher MAC", type: 6 /* BYTES */, size: 2, value: encrypted.cipherMAC },
428
- { name: "cipher text", type: 6 /* BYTES */, size: encrypted.cipherText.length, value: encrypted.cipherText }
292
+ { name: "destination hash", type: FieldType.UINT8, length: 1, value: dst },
293
+ { name: "source hash", type: FieldType.UINT8, length: 1, value: src },
294
+ { name: "cipher MAC", type: FieldType.BYTES, length: 2, value: encrypted.cipherMAC },
295
+ {
296
+ name: "cipher text",
297
+ type: FieldType.BYTES,
298
+ length: encrypted.cipherText.length,
299
+ value: encrypted.cipherText
300
+ }
429
301
  ]
430
302
  };
431
303
  return { payload, segment };
@@ -436,9 +308,9 @@ var Packet = class _Packet {
436
308
  if (this.payload.length < 4) {
437
309
  throw new Error("Invalid text payload: too short");
438
310
  }
439
- const reader = new BufferReader(this.payload);
440
- const dst = reader.readByte();
441
- const src = reader.readByte();
311
+ const reader = Reader.fromBytes(this.payload);
312
+ const dst = reader.uint8();
313
+ const src = reader.uint8();
442
314
  const encrypted = this.decodeEncryptedPayload(reader);
443
315
  const payload = {
444
316
  type: 2 /* TEXT */,
@@ -449,12 +321,17 @@ var Packet = class _Packet {
449
321
  if (typeof withSegment === "boolean" && withSegment) {
450
322
  const segment = {
451
323
  name: "text payload",
452
- data: this.payload,
324
+ data: new Uint8Array(this.payload).buffer,
453
325
  fields: [
454
- { name: "destination hash", type: 1 /* UINT8 */, size: 1, value: dst },
455
- { name: "source hash", type: 1 /* UINT8 */, size: 1, value: src },
456
- { name: "cipher MAC", type: 6 /* BYTES */, size: 2, value: encrypted.cipherMAC },
457
- { name: "cipher text", type: 6 /* BYTES */, size: encrypted.cipherText.length, value: encrypted.cipherText }
326
+ { name: "destination hash", type: FieldType.UINT8, length: 1, value: dst },
327
+ { name: "source hash", type: FieldType.UINT8, length: 1, value: src },
328
+ { name: "cipher MAC", type: FieldType.BYTES, length: 2, value: encrypted.cipherMAC },
329
+ {
330
+ name: "cipher text",
331
+ type: FieldType.BYTES,
332
+ length: encrypted.cipherText.length,
333
+ value: encrypted.cipherText
334
+ }
458
335
  ]
459
336
  };
460
337
  return { payload, segment };
@@ -465,8 +342,8 @@ var Packet = class _Packet {
465
342
  if (this.payload.length < 4) {
466
343
  throw new Error("Invalid ack payload: too short");
467
344
  }
468
- const reader = new BufferReader(this.payload);
469
- const checksum = reader.readBytes(4);
345
+ const reader = Reader.fromBytes(this.payload);
346
+ const checksum = reader.bytes(4);
470
347
  const payload = {
471
348
  type: 3 /* ACK */,
472
349
  checksum
@@ -474,10 +351,8 @@ var Packet = class _Packet {
474
351
  if (typeof withSegment === "boolean" && withSegment) {
475
352
  const segment = {
476
353
  name: "ack payload",
477
- data: this.payload,
478
- fields: [
479
- { name: "checksum", type: 6 /* BYTES */, size: 4, value: checksum }
480
- ]
354
+ data: new Uint8Array(this.payload).buffer,
355
+ fields: [{ name: "checksum", type: FieldType.BYTES, length: 4, value: checksum }]
481
356
  };
482
357
  return { payload, segment };
483
358
  }
@@ -487,26 +362,26 @@ var Packet = class _Packet {
487
362
  if (this.payload.length < 4) {
488
363
  throw new Error("Invalid advert payload: too short");
489
364
  }
490
- const reader = new BufferReader(this.payload);
365
+ const reader = Reader.fromBytes(this.payload);
491
366
  const payload = {
492
367
  type: 4 /* ADVERT */,
493
- publicKey: reader.readBytes(32),
494
- timestamp: reader.readTimestamp(),
495
- signature: reader.readBytes(64)
368
+ publicKey: reader.bytes(32),
369
+ timestamp: reader.date32(),
370
+ signature: reader.bytes(64)
496
371
  };
497
372
  let segment;
498
373
  if (typeof withSegment === "boolean" && withSegment) {
499
374
  segment = {
500
375
  name: "advert payload",
501
- data: this.payload,
376
+ data: new Uint8Array(this.payload).buffer,
502
377
  fields: [
503
- { type: 6 /* BYTES */, name: "public key", size: 32 },
504
- { type: 4 /* UINT32_LE */, name: "timestamp", size: 4, value: payload.timestamp },
505
- { type: 6 /* BYTES */, name: "signature", size: 64 }
378
+ { type: FieldType.BYTES, name: "public key", length: 32 },
379
+ { type: FieldType.UINT32_LE, name: "timestamp", length: 4, value: payload.timestamp },
380
+ { type: FieldType.BYTES, name: "signature", length: 64 }
506
381
  ]
507
382
  };
508
383
  }
509
- const flags = reader.readByte();
384
+ const flags = reader.uint8();
510
385
  const appdata = {
511
386
  nodeType: flags & 15,
512
387
  hasLocation: (flags & 16 /* HAS_LOCATION */) !== 0,
@@ -515,44 +390,50 @@ var Packet = class _Packet {
515
390
  hasName: (flags & 128 /* HAS_NAME */) !== 0
516
391
  };
517
392
  if (typeof withSegment === "boolean" && withSegment) {
518
- segment.fields.push({ type: 0 /* BITS */, name: "flags", size: 1, value: flags, bits: [
519
- { size: 1, name: "name flag" },
520
- { size: 1, name: "feature2 flag" },
521
- { size: 1, name: "feature1 flag" },
522
- { size: 1, name: "location flag" },
523
- { size: 4, name: "node type" }
524
- ] });
393
+ segment.fields.push({
394
+ type: FieldType.BITS,
395
+ name: "flags",
396
+ length: 1,
397
+ value: flags,
398
+ bits: [
399
+ { size: 1, name: "name flag" },
400
+ { size: 1, name: "feature2 flag" },
401
+ { size: 1, name: "feature1 flag" },
402
+ { size: 1, name: "location flag" },
403
+ { size: 4, name: "node type" }
404
+ ]
405
+ });
525
406
  }
526
407
  if (appdata.hasLocation) {
527
- const lat = reader.readInt32LE() / 1e5;
528
- const lon = reader.readInt32LE() / 1e5;
408
+ const lat = reader.int32() / 1e6;
409
+ const lon = reader.int32() / 1e6;
529
410
  appdata.location = [lat, lon];
530
411
  if (typeof withSegment === "boolean" && withSegment) {
531
- segment.fields.push({ type: 4 /* UINT32_LE */, name: "latitude", size: 4, value: lat });
532
- segment.fields.push({ type: 4 /* UINT32_LE */, name: "longitude", size: 4, value: lon });
412
+ segment.fields.push({ type: FieldType.UINT32_LE, name: "latitude", length: 4, value: lat });
413
+ segment.fields.push({ type: FieldType.UINT32_LE, name: "longitude", length: 4, value: lon });
533
414
  }
534
415
  }
535
416
  if (appdata.hasFeature1) {
536
- appdata.feature1 = reader.readUint16LE();
417
+ appdata.feature1 = reader.uint16();
537
418
  if (typeof withSegment === "boolean" && withSegment) {
538
- segment.fields.push({ type: 2 /* UINT16_LE */, name: "feature1", size: 2, value: appdata.feature1 });
419
+ segment.fields.push({ type: FieldType.UINT16_LE, name: "feature1", length: 2, value: appdata.feature1 });
539
420
  }
540
421
  }
541
422
  if (appdata.hasFeature2) {
542
- appdata.feature2 = reader.readUint16LE();
423
+ appdata.feature2 = reader.uint16();
543
424
  if (typeof withSegment === "boolean" && withSegment) {
544
- segment.fields.push({ type: 2 /* UINT16_LE */, name: "feature2", size: 2, value: appdata.feature2 });
425
+ segment.fields.push({ type: FieldType.UINT16_LE, name: "feature2", length: 2, value: appdata.feature2 });
545
426
  }
546
427
  }
547
428
  if (appdata.hasName) {
548
- const nameBytes = reader.readBytes();
549
- let nullPos = nameBytes.indexOf(0);
550
- if (nullPos === -1) {
551
- nullPos = nameBytes.length;
552
- }
553
- appdata.name = new TextDecoder("utf-8").decode(nameBytes.subarray(0, nullPos));
429
+ appdata.name = reader.cString();
554
430
  if (typeof withSegment === "boolean" && withSegment) {
555
- segment.fields.push({ type: 10 /* C_STRING */, name: "name", size: nameBytes.length, value: appdata.name });
431
+ segment.fields.push({
432
+ type: FieldType.C_STRING,
433
+ name: "name",
434
+ length: appdata.name.length,
435
+ value: appdata.name
436
+ });
556
437
  }
557
438
  }
558
439
  if (typeof withSegment === "boolean" && withSegment && typeof segment !== "undefined") {
@@ -564,8 +445,8 @@ var Packet = class _Packet {
564
445
  if (this.payload.length < 3) {
565
446
  throw new Error("Invalid group text payload: too short");
566
447
  }
567
- const reader = new BufferReader(this.payload);
568
- const channelHash = reader.readByte();
448
+ const reader = Reader.fromBytes(this.payload);
449
+ const channelHash = reader.uint8();
569
450
  const encrypted = this.decodeEncryptedPayload(reader);
570
451
  const payload = {
571
452
  type: 5 /* GROUP_TEXT */,
@@ -575,11 +456,16 @@ var Packet = class _Packet {
575
456
  if (typeof withSegment === "boolean" && withSegment) {
576
457
  const segment = {
577
458
  name: "group text payload",
578
- data: this.payload,
459
+ data: new Uint8Array(this.payload).buffer,
579
460
  fields: [
580
- { name: "channel hash", type: 1 /* UINT8 */, size: 1, value: channelHash },
581
- { name: "cipher MAC", type: 6 /* BYTES */, size: 2, value: encrypted.cipherMAC },
582
- { name: "cipher text", type: 6 /* BYTES */, size: encrypted.cipherText.length, value: encrypted.cipherText }
461
+ { name: "channel hash", type: FieldType.UINT8, length: 1, value: channelHash },
462
+ { name: "cipher MAC", type: FieldType.BYTES, length: 2, value: encrypted.cipherMAC },
463
+ {
464
+ name: "cipher text",
465
+ type: FieldType.BYTES,
466
+ length: encrypted.cipherText.length,
467
+ value: encrypted.cipherText
468
+ }
583
469
  ]
584
470
  };
585
471
  return { payload, segment };
@@ -590,20 +476,25 @@ var Packet = class _Packet {
590
476
  if (this.payload.length < 3) {
591
477
  throw new Error("Invalid group data payload: too short");
592
478
  }
593
- const reader = new BufferReader(this.payload);
479
+ const reader = Reader.fromBytes(this.payload);
594
480
  const payload = {
595
481
  type: 6 /* GROUP_DATA */,
596
- channelHash: reader.readByte(),
482
+ channelHash: reader.uint8(),
597
483
  encrypted: this.decodeEncryptedPayload(reader)
598
484
  };
599
485
  if (typeof withSegment === "boolean" && withSegment) {
600
486
  const segment = {
601
487
  name: "group data payload",
602
- data: this.payload,
488
+ data: new Uint8Array(this.payload).buffer,
603
489
  fields: [
604
- { name: "channel hash", type: 1 /* UINT8 */, size: 1, value: payload.channelHash },
605
- { name: "cipher MAC", type: 6 /* BYTES */, size: 2, value: payload.encrypted.cipherMAC },
606
- { name: "cipher text", type: 6 /* BYTES */, size: payload.encrypted.cipherText.length, value: payload.encrypted.cipherText }
490
+ { name: "channel hash", type: FieldType.UINT8, length: 1, value: payload.channelHash },
491
+ { name: "cipher MAC", type: FieldType.BYTES, length: 2, value: payload.encrypted.cipherMAC },
492
+ {
493
+ name: "cipher text",
494
+ type: FieldType.BYTES,
495
+ length: payload.encrypted.cipherText.length,
496
+ value: payload.encrypted.cipherText
497
+ }
607
498
  ]
608
499
  };
609
500
  return { payload, segment };
@@ -614,22 +505,27 @@ var Packet = class _Packet {
614
505
  if (this.payload.length < 1 + 32 + 2) {
615
506
  throw new Error("Invalid anon req payload: too short");
616
507
  }
617
- const reader = new BufferReader(this.payload);
508
+ const reader = Reader.fromBytes(this.payload);
618
509
  const payload = {
619
510
  type: 7 /* ANON_REQ */,
620
- dst: reader.readByte(),
621
- publicKey: reader.readBytes(32),
511
+ dst: reader.uint8(),
512
+ publicKey: reader.bytes(32),
622
513
  encrypted: this.decodeEncryptedPayload(reader)
623
514
  };
624
515
  if (typeof withSegment === "boolean" && withSegment) {
625
516
  const segment = {
626
517
  name: "anon req payload",
627
- data: this.payload,
518
+ data: new Uint8Array(this.payload).buffer,
628
519
  fields: [
629
- { name: "destination hash", type: 1 /* UINT8 */, size: 1, value: payload.dst },
630
- { name: "public key", type: 6 /* BYTES */, size: 32, value: payload.publicKey },
631
- { name: "cipher MAC", type: 6 /* BYTES */, size: 2, value: payload.encrypted.cipherMAC },
632
- { name: "cipher text", type: 6 /* BYTES */, size: payload.encrypted.cipherText.length, value: payload.encrypted.cipherText }
520
+ { name: "destination hash", type: FieldType.UINT8, length: 1, value: payload.dst },
521
+ { name: "public key", type: FieldType.BYTES, length: 32, value: payload.publicKey },
522
+ { name: "cipher MAC", type: FieldType.BYTES, length: 2, value: payload.encrypted.cipherMAC },
523
+ {
524
+ name: "cipher text",
525
+ type: FieldType.BYTES,
526
+ length: payload.encrypted.cipherText.length,
527
+ value: payload.encrypted.cipherText
528
+ }
633
529
  ]
634
530
  };
635
531
  return { payload, segment };
@@ -640,19 +536,19 @@ var Packet = class _Packet {
640
536
  if (this.payload.length < 2) {
641
537
  throw new Error("Invalid path payload: too short");
642
538
  }
643
- const reader = new BufferReader(this.payload);
539
+ const reader = Reader.fromBytes(this.payload);
644
540
  const payload = {
645
541
  type: 8 /* PATH */,
646
- dst: reader.readByte(),
647
- src: reader.readByte()
542
+ dst: reader.uint8(),
543
+ src: reader.uint8()
648
544
  };
649
545
  if (typeof withSegment === "boolean" && withSegment) {
650
546
  const segment = {
651
547
  name: "path payload",
652
- data: this.payload,
548
+ data: new Uint8Array(this.payload).buffer,
653
549
  fields: [
654
- { name: "destination hash", type: 1 /* UINT8 */, size: 1, value: payload.dst },
655
- { name: "source hash", type: 1 /* UINT8 */, size: 1, value: payload.src }
550
+ { name: "destination hash", type: FieldType.UINT8, length: 1, value: payload.dst },
551
+ { name: "source hash", type: FieldType.UINT8, length: 1, value: payload.src }
656
552
  ]
657
553
  };
658
554
  return { payload, segment };
@@ -663,23 +559,23 @@ var Packet = class _Packet {
663
559
  if (this.payload.length < 9) {
664
560
  throw new Error("Invalid trace payload: too short");
665
561
  }
666
- const reader = new BufferReader(this.payload);
562
+ const reader = Reader.fromBytes(this.payload);
667
563
  const payload = {
668
564
  type: 9 /* TRACE */,
669
- tag: reader.readUint32LE() >>> 0,
670
- authCode: reader.readUint32LE() >>> 0,
671
- flags: reader.readByte() & 3,
672
- nodes: reader.readBytes()
565
+ tag: reader.uint32(),
566
+ authCode: reader.uint32(),
567
+ flags: reader.uint8() & 3,
568
+ nodes: reader.bytes()
673
569
  };
674
570
  if (typeof withSegment === "boolean" && withSegment) {
675
571
  const segment = {
676
572
  name: "trace payload",
677
- data: this.payload,
573
+ data: new Uint8Array(this.payload).buffer,
678
574
  fields: [
679
- { name: "tag", type: 8 /* DWORDS */, size: 4, value: payload.tag },
680
- { name: "auth code", type: 8 /* DWORDS */, size: 4, value: payload.authCode },
681
- { name: "flags", type: 1 /* UINT8 */, size: 1, value: payload.flags },
682
- { name: "nodes", type: 6 /* BYTES */, size: payload.nodes.length, value: payload.nodes }
575
+ { name: "tag", type: FieldType.DWORDS, length: 4, value: payload.tag },
576
+ { name: "auth code", type: FieldType.DWORDS, length: 4, value: payload.authCode },
577
+ { name: "flags", type: FieldType.UINT8, length: 1, value: payload.flags },
578
+ { name: "nodes", type: FieldType.BYTES, length: payload.nodes.length, value: payload.nodes }
683
579
  ]
684
580
  };
685
581
  return { payload, segment };
@@ -694,10 +590,8 @@ var Packet = class _Packet {
694
590
  if (typeof withSegment === "boolean" && withSegment) {
695
591
  const segment = {
696
592
  name: "raw custom payload",
697
- data: this.payload,
698
- fields: [
699
- { name: "data", type: 6 /* BYTES */, size: this.payload.length, value: this.payload }
700
- ]
593
+ data: new Uint8Array(this.payload).buffer,
594
+ fields: [{ name: "data", type: FieldType.BYTES, length: this.payload.length, value: this.payload }]
701
595
  };
702
596
  return { payload, segment };
703
597
  }
@@ -706,35 +600,39 @@ var Packet = class _Packet {
706
600
  };
707
601
 
708
602
  // src/crypto.ts
709
- var import_ed25519 = require("@noble/curves/ed25519.js");
710
- var import_sha22 = require("@noble/hashes/sha2.js");
711
- var import_hmac = require("@noble/hashes/hmac.js");
712
- var import_aes = require("@noble/ciphers/aes.js");
603
+ import { ed25519, x25519 } from "@noble/curves/ed25519.js";
604
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
605
+ import { hmac } from "@noble/hashes/hmac.js";
606
+ import { ecb } from "@noble/ciphers/aes.js";
607
+ import { bytesToHex as bytesToHex2, equalBytes, hexToBytes } from "@hamradio/packet";
713
608
  var PUBLIC_KEY_SIZE = 32;
714
609
  var SEED_SIZE = 32;
715
610
  var HMAC_SIZE = 2;
716
- var SHARED_SECRET_SIZE = 32;
611
+ var SHARED_SECRET_SIZE = 16;
717
612
  var SIGNATURE_SIZE = 64;
718
613
  var STATIC_SECRET_SIZE = 32;
719
- var publicSecret = hexToBytes("8b3387e9c5cdea6ac9e5edbaa115cd72", 16);
614
+ var publicSecret = hexToBytes("8b3387e9c5cdea6ac9e5edbaa115cd72");
720
615
  var PublicKey = class _PublicKey {
721
616
  constructor(key) {
722
617
  if (typeof key === "string") {
723
- this.key = hexToBytes(key, PUBLIC_KEY_SIZE);
618
+ this.key = hexToBytes(key);
724
619
  } else if (key instanceof Uint8Array) {
725
620
  this.key = key;
726
621
  } else {
727
622
  throw new Error("Invalid type for PublicKey constructor");
728
623
  }
624
+ if (this.key.length !== PUBLIC_KEY_SIZE) {
625
+ throw new Error(`Invalid public key length: expected ${PUBLIC_KEY_SIZE} bytes, got ${this.key.length}`);
626
+ }
729
627
  }
730
628
  toHash() {
731
- return import_sha22.sha256.create().update(this.key).digest()[0];
629
+ return sha2562.create().update(this.key).digest()[0];
732
630
  }
733
631
  toBytes() {
734
632
  return this.key;
735
633
  }
736
634
  toString() {
737
- return (0, import_utils2.bytesToHex)(this.key);
635
+ return bytesToHex2(this.key);
738
636
  }
739
637
  equals(other) {
740
638
  let otherKey;
@@ -743,28 +641,39 @@ var PublicKey = class _PublicKey {
743
641
  } else if (other instanceof Uint8Array) {
744
642
  otherKey = other;
745
643
  } else if (typeof other === "string") {
746
- otherKey = hexToBytes(other, PUBLIC_KEY_SIZE);
644
+ otherKey = hexToBytes(other);
747
645
  } else {
748
646
  throw new Error("Invalid type for PublicKey comparison");
749
647
  }
750
- return (0, import_utils.equalBytes)(this.key, otherKey);
648
+ if (otherKey.length !== PUBLIC_KEY_SIZE) {
649
+ throw new Error(
650
+ `Invalid public key length for comparison: expected ${PUBLIC_KEY_SIZE} bytes, got ${otherKey.length}`
651
+ );
652
+ }
653
+ return equalBytes(this.key, otherKey);
751
654
  }
752
655
  verify(message, signature) {
753
656
  if (signature.length !== SIGNATURE_SIZE) {
754
657
  throw new Error(`Invalid signature length: expected ${SIGNATURE_SIZE} bytes, got ${signature.length}`);
755
658
  }
756
- return import_ed25519.ed25519.verify(signature, message, this.key);
659
+ return ed25519.verify(signature, message, this.key);
660
+ }
661
+ static fromBytes(key) {
662
+ return new _PublicKey(key);
663
+ }
664
+ static fromString(key) {
665
+ return new _PublicKey(key);
757
666
  }
758
667
  };
759
668
  var PrivateKey = class _PrivateKey {
760
669
  constructor(seed) {
761
670
  if (typeof seed === "string") {
762
- seed = hexToBytes(seed, SEED_SIZE);
671
+ seed = hexToBytes(seed);
763
672
  }
764
673
  if (seed.length !== SEED_SIZE) {
765
674
  throw new Error(`Invalid seed length: expected ${SEED_SIZE} bytes, got ${seed.length}`);
766
675
  }
767
- const { secretKey, publicKey } = import_ed25519.ed25519.keygen(seed);
676
+ const { secretKey, publicKey } = ed25519.keygen(seed);
768
677
  this.secretKey = secretKey;
769
678
  this.publicKey = new PublicKey(publicKey);
770
679
  }
@@ -775,10 +684,10 @@ var PrivateKey = class _PrivateKey {
775
684
  return this.secretKey;
776
685
  }
777
686
  toString() {
778
- return (0, import_utils2.bytesToHex)(this.secretKey);
687
+ return bytesToHex2(this.secretKey);
779
688
  }
780
689
  sign(message) {
781
- return import_ed25519.ed25519.sign(message, this.secretKey);
690
+ return ed25519.sign(message, this.secretKey);
782
691
  }
783
692
  calculateSharedSecret(other) {
784
693
  let otherPublicKey;
@@ -791,43 +700,40 @@ var PrivateKey = class _PrivateKey {
791
700
  } else {
792
701
  throw new Error("Invalid type for calculateSharedSecret comparison");
793
702
  }
794
- return import_ed25519.x25519.getSharedSecret(this.secretKey, otherPublicKey.toBytes());
703
+ return x25519.getSharedSecret(this.secretKey, otherPublicKey.toBytes());
795
704
  }
796
705
  static generate() {
797
- const { secretKey } = import_ed25519.ed25519.keygen();
706
+ const { secretKey } = ed25519.keygen();
798
707
  return new _PrivateKey(secretKey);
799
708
  }
800
709
  };
801
710
  var SharedSecret = class _SharedSecret {
802
711
  constructor(secret) {
803
- if (secret.length === SHARED_SECRET_SIZE / 2) {
804
- const padded = new Uint8Array(SHARED_SECRET_SIZE);
805
- padded.set(secret, SHARED_SECRET_SIZE - secret.length);
806
- secret = padded;
807
- }
808
712
  if (secret.length !== SHARED_SECRET_SIZE) {
809
713
  throw new Error(`Invalid shared secret length: expected ${SHARED_SECRET_SIZE} bytes, got ${secret.length}`);
810
714
  }
811
- this.secret = secret;
715
+ this.secret = new Uint8Array(SHARED_SECRET_SIZE * 2);
716
+ this.secret.set(secret, 0);
812
717
  }
813
718
  toHash() {
814
- return this.secret[0];
719
+ const hash = sha2562.create().update(this.secret.slice(0, 16)).digest();
720
+ return hash[0];
815
721
  }
816
722
  toBytes() {
817
- return this.secret;
723
+ return this.secret.slice(0, 16);
818
724
  }
819
725
  toString() {
820
- return (0, import_utils2.bytesToHex)(this.secret);
726
+ return bytesToHex2(this.secret.slice(0, 16));
821
727
  }
822
728
  decrypt(hmac2, ciphertext) {
823
729
  if (hmac2.length !== HMAC_SIZE) {
824
730
  throw new Error(`Invalid HMAC length: expected ${HMAC_SIZE} bytes, got ${hmac2.length}`);
825
731
  }
826
732
  const expectedHmac = this.calculateHmac(ciphertext);
827
- if (!(0, import_utils.equalBytes)(hmac2, expectedHmac)) {
828
- throw new Error(`Invalid HMAC: decryption failed: expected ${(0, import_utils2.bytesToHex)(expectedHmac)}, got ${(0, import_utils2.bytesToHex)(hmac2)}`);
733
+ if (!equalBytes(hmac2, expectedHmac)) {
734
+ throw new Error(`Invalid HMAC: decryption failed: expected ${bytesToHex2(expectedHmac)}, got ${bytesToHex2(hmac2)}`);
829
735
  }
830
- const cipher = (0, import_aes.ecb)(this.secret.slice(0, 16), { disablePadding: true });
736
+ const cipher = ecb(this.secret.slice(0, 16), { disablePadding: true });
831
737
  const plaintext = new Uint8Array(ciphertext.length);
832
738
  for (let i = 0; i < ciphertext.length; i += 16) {
833
739
  const block = ciphertext.slice(i, i + 16);
@@ -842,7 +748,7 @@ var SharedSecret = class _SharedSecret {
842
748
  }
843
749
  encrypt(data) {
844
750
  const key = this.secret.slice(0, 16);
845
- const cipher = (0, import_aes.ecb)(key, { disablePadding: true });
751
+ const cipher = ecb(key, { disablePadding: true });
846
752
  const fullBlocks = Math.floor(data.length / 16);
847
753
  const remaining = data.length % 16;
848
754
  const ciphertext = new Uint8Array((fullBlocks + (remaining > 0 ? 1 : 0)) * 16);
@@ -861,7 +767,7 @@ var SharedSecret = class _SharedSecret {
861
767
  return { hmac: hmac2, ciphertext };
862
768
  }
863
769
  calculateHmac(data) {
864
- return (0, import_hmac.hmac)(import_sha22.sha256, this.secret, data).slice(0, HMAC_SIZE);
770
+ return hmac(sha2562, this.secret, data).slice(0, HMAC_SIZE);
865
771
  }
866
772
  static fromName(name) {
867
773
  if (name === "Public") {
@@ -869,14 +775,14 @@ var SharedSecret = class _SharedSecret {
869
775
  } else if (!/^#/.test(name)) {
870
776
  throw new Error("Only the 'Public' group or groups starting with '#' are supported");
871
777
  }
872
- const hash = import_sha22.sha256.create().update(new TextEncoder().encode(name)).digest();
778
+ const hash = sha2562.create().update(new TextEncoder().encode(name)).digest();
873
779
  return new _SharedSecret(hash.slice(0, SHARED_SECRET_SIZE));
874
780
  }
875
781
  };
876
782
  var StaticSecret = class {
877
783
  constructor(secret) {
878
784
  if (typeof secret === "string") {
879
- secret = hexToBytes(secret, STATIC_SECRET_SIZE);
785
+ secret = hexToBytes(secret);
880
786
  }
881
787
  if (secret.length !== STATIC_SECRET_SIZE) {
882
788
  throw new Error(`Invalid static secret length: expected ${STATIC_SECRET_SIZE} bytes, got ${secret.length}`);
@@ -884,16 +790,17 @@ var StaticSecret = class {
884
790
  this.secret = secret;
885
791
  }
886
792
  publicKey() {
887
- const publicKey = import_ed25519.x25519.getPublicKey(this.secret);
793
+ const publicKey = x25519.getPublicKey(this.secret);
888
794
  return new PublicKey(publicKey);
889
795
  }
890
796
  diffieHellman(otherPublicKey) {
891
- const sharedSecret = import_ed25519.x25519.getSharedSecret(this.secret, otherPublicKey.toBytes());
892
- return new SharedSecret(sharedSecret);
797
+ const sharedSecret = x25519.getSharedSecret(this.secret, otherPublicKey.toBytes());
798
+ return new SharedSecret(sharedSecret.slice(0, 16));
893
799
  }
894
800
  };
895
801
 
896
802
  // src/identity.ts
803
+ import { hexToBytes as hexToBytes2, Reader as Reader2, Writer } from "@hamradio/packet";
897
804
  var parseNodeHash = (hash) => {
898
805
  if (hash instanceof Uint8Array) {
899
806
  return hash[0];
@@ -904,7 +811,7 @@ var parseNodeHash = (hash) => {
904
811
  }
905
812
  return hash;
906
813
  } else if (typeof hash === "string") {
907
- const parsed = hexToBytes(hash);
814
+ const parsed = hexToBytes2(hash);
908
815
  if (parsed.length !== 1) {
909
816
  throw new Error("NodeHash string must represent a single byte");
910
817
  }
@@ -920,7 +827,7 @@ var toPublicKeyBytes = (key) => {
920
827
  } else if (key instanceof Uint8Array) {
921
828
  return key;
922
829
  } else if (typeof key === "string") {
923
- return hexToBytes(key);
830
+ return hexToBytes2(key);
924
831
  } else {
925
832
  throw new Error("Invalid type for toPublicKeyBytes");
926
833
  }
@@ -979,7 +886,7 @@ var LocalIdentity = class extends Identity {
979
886
  } else {
980
887
  throw new Error("Invalid type for calculateSharedSecret comparison");
981
888
  }
982
- return new SharedSecret(this.privateKey.calculateSharedSecret(otherPublicKey));
889
+ return new SharedSecret(this.privateKey.calculateSharedSecret(otherPublicKey).slice(0, 16));
983
890
  }
984
891
  };
985
892
  var Contact = class {
@@ -1023,12 +930,12 @@ var Group = class {
1023
930
  if (data.length < 5) {
1024
931
  throw new Error("Invalid ciphertext");
1025
932
  }
1026
- const reader = new BufferReader(data);
1027
- const timestamp = reader.readTimestamp();
1028
- const flags = reader.readByte();
933
+ const reader = new Reader2(data);
934
+ const timestamp = reader.date32();
935
+ const flags = reader.uint8();
1029
936
  const textType = flags >> 2 & 63;
1030
937
  const attempt = flags & 3;
1031
- const message = new TextDecoder("utf-8").decode(reader.readBytes());
938
+ const message = new TextDecoder("utf-8").decode(reader.bytes());
1032
939
  return {
1033
940
  timestamp,
1034
941
  textType,
@@ -1037,11 +944,11 @@ var Group = class {
1037
944
  };
1038
945
  }
1039
946
  encryptText(plain) {
1040
- const writer = new BufferWriter();
1041
- writer.writeTimestamp(plain.timestamp);
947
+ const writer = new Writer(4 + 1 + new TextEncoder().encode(plain.message).length);
948
+ writer.date32(plain.timestamp);
1042
949
  const flags = (plain.textType & 63) << 2 | plain.attempt & 3;
1043
- writer.writeByte(flags);
1044
- writer.writeBytes(new TextEncoder().encode(plain.message));
950
+ writer.uint8(flags);
951
+ writer.utf8String(plain.message);
1045
952
  const data = writer.toBytes();
1046
953
  return this.secret.encrypt(data);
1047
954
  }
@@ -1050,16 +957,16 @@ var Group = class {
1050
957
  if (data.length < 4) {
1051
958
  throw new Error("Invalid ciphertext");
1052
959
  }
1053
- const reader = new BufferReader(data);
960
+ const reader = new Reader2(data);
1054
961
  return {
1055
- timestamp: reader.readTimestamp(),
1056
- data: reader.readBytes(reader.remainingBytes())
962
+ timestamp: reader.date32(),
963
+ data: reader.bytes()
1057
964
  };
1058
965
  }
1059
966
  encryptData(plain) {
1060
- const writer = new BufferWriter();
1061
- writer.writeTimestamp(plain.timestamp);
1062
- writer.writeBytes(plain.data);
967
+ const writer = new Writer(4 + plain.data.length);
968
+ writer.date32(plain.timestamp);
969
+ writer.bytes(plain.data);
1063
970
  const data = writer.toBytes();
1064
971
  return this.secret.encrypt(data);
1065
972
  }
@@ -1069,6 +976,8 @@ var Contacts = class {
1069
976
  this.localIdentities = [];
1070
977
  this.contacts = {};
1071
978
  this.groups = {};
979
+ this.addGroup(new Group("Public"));
980
+ this.addGroup(new Group("#test"));
1072
981
  }
1073
982
  addLocalIdentity(identity) {
1074
983
  this.localIdentities.push({ identity, sharedSecrets: {} });
@@ -1080,6 +989,23 @@ var Contacts = class {
1080
989
  }
1081
990
  this.contacts[hash].push(contact);
1082
991
  }
992
+ hasContact(nameOrHash) {
993
+ if (typeof nameOrHash === "string") {
994
+ return Object.values(this.contacts).flat().some((contact) => contact.name.toLowerCase() === nameOrHash.toLowerCase());
995
+ } else {
996
+ const hash = parseNodeHash(nameOrHash);
997
+ return (this.contacts[hash] || []).length > 0;
998
+ }
999
+ }
1000
+ getContactByName(name) {
1001
+ const contact = Object.values(this.contacts).flat().find((contact2) => contact2.name.toLowerCase() === name.toLowerCase());
1002
+ return contact || null;
1003
+ }
1004
+ getContacts() {
1005
+ const contacts = Object.values(this.contacts).flat();
1006
+ contacts.sort((a, b) => a.name.localeCompare(b.name));
1007
+ return contacts;
1008
+ }
1083
1009
  decrypt(src, dst, hmac2, ciphertext) {
1084
1010
  let contacts = [];
1085
1011
  if (src instanceof PublicKey) {
@@ -1127,17 +1053,45 @@ var Contacts = class {
1127
1053
  return sharedSecret;
1128
1054
  }
1129
1055
  addGroup(group) {
1130
- const hash = parseNodeHash(group.hash());
1056
+ for (const key of Object.keys(this.groups)) {
1057
+ const hash2 = Number(key);
1058
+ this.groups[hash2] = this.groups[hash2].filter((g) => g.name.toLowerCase() !== group.name.toLowerCase());
1059
+ if (this.groups[hash2].length === 0) {
1060
+ delete this.groups[hash2];
1061
+ }
1062
+ }
1063
+ const hash = group.hash();
1131
1064
  if (!this.groups[hash]) {
1132
1065
  this.groups[hash] = [];
1133
1066
  }
1134
1067
  this.groups[hash].push(group);
1135
1068
  }
1069
+ hasGroup(nameOrHash) {
1070
+ if (typeof nameOrHash === "string") {
1071
+ return Object.values(this.groups).flat().some((group) => group.name.toLowerCase() === nameOrHash.toLowerCase());
1072
+ } else {
1073
+ const hash = parseNodeHash(nameOrHash);
1074
+ return (this.groups[hash] || []).length > 0;
1075
+ }
1076
+ }
1077
+ getGroupByName(name) {
1078
+ const group = Object.values(this.groups).flat().find((group2) => group2.name.toLowerCase() === name.toLowerCase());
1079
+ return group || null;
1080
+ }
1081
+ getGroups() {
1082
+ const groups = Object.values(this.groups).flat();
1083
+ groups.sort((a, b) => {
1084
+ if (a.name === "Public") return -1;
1085
+ if (b.name === "Public") return 1;
1086
+ return a.name.localeCompare(b.name);
1087
+ });
1088
+ return groups;
1089
+ }
1136
1090
  decryptGroupText(channelHash, hmac2, ciphertext) {
1137
1091
  const hash = parseNodeHash(channelHash);
1138
1092
  const groups = this.groups[hash] || [];
1139
1093
  if (groups.length === 0) {
1140
- throw new Error("Unknown group hash");
1094
+ throw new Error(`Unknown group hash ${hash.toString(16).padStart(2, "0")}`);
1141
1095
  }
1142
1096
  for (const group of groups) {
1143
1097
  try {
@@ -1146,13 +1100,13 @@ var Contacts = class {
1146
1100
  } catch {
1147
1101
  }
1148
1102
  }
1149
- throw new Error("Decryption failed with all known groups");
1103
+ throw new Error(`Decryption failed with all known groups with hash ${hash.toString(16).padStart(2, "0")}`);
1150
1104
  }
1151
1105
  decryptGroupData(channelHash, hmac2, ciphertext) {
1152
1106
  const hash = parseNodeHash(channelHash);
1153
1107
  const groups = this.groups[hash] || [];
1154
1108
  if (groups.length === 0) {
1155
- throw new Error("Unknown group hash");
1109
+ throw new Error(`Unknown group hash ${hash.toString(16).padStart(2, "0")}`);
1156
1110
  }
1157
1111
  for (const group of groups) {
1158
1112
  try {
@@ -1161,11 +1115,10 @@ var Contacts = class {
1161
1115
  } catch {
1162
1116
  }
1163
1117
  }
1164
- throw new Error("Decryption failed with all known groups");
1118
+ throw new Error(`Decryption failed with all known groups with hash ${hash.toString(16).padStart(2, "0")}`);
1165
1119
  }
1166
1120
  };
1167
- // Annotate the CommonJS export names for ESM import in node:
1168
- 0 && (module.exports = {
1121
+ export {
1169
1122
  Contact,
1170
1123
  Contacts,
1171
1124
  Group,
@@ -1182,4 +1135,4 @@ var Contacts = class {
1182
1135
  StaticSecret,
1183
1136
  TextType,
1184
1137
  parseNodeHash
1185
- });
1138
+ };