@waku/core 0.0.36-6d86b6f.0 → 0.0.36-76fb1ea.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/bundle/{base_protocol-DvQrudwy.js → base_protocol-DbwKyDLW.js} +1 -1
  2. package/bundle/{index-CTo1my9M.js → index-JnhMR9ZE.js} +20 -1
  3. package/bundle/index.js +510 -58
  4. package/bundle/lib/base_protocol.js +2 -2
  5. package/bundle/lib/message/version_0.js +2 -2
  6. package/bundle/{version_0-CiYGrPc2.js → version_0-sWyv9XWm.js} +920 -185
  7. package/dist/.tsbuildinfo +1 -1
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.js +2 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/connection_manager/connection_manager.d.ts +1 -1
  12. package/dist/lib/connection_manager/connection_manager.js +1 -1
  13. package/dist/lib/filter/filter.d.ts +4 -2
  14. package/dist/lib/filter/filter.js +21 -3
  15. package/dist/lib/filter/filter.js.map +1 -1
  16. package/dist/lib/light_push/index.d.ts +5 -1
  17. package/dist/lib/light_push/index.js +5 -1
  18. package/dist/lib/light_push/index.js.map +1 -1
  19. package/dist/lib/light_push/light_push.d.ts +3 -4
  20. package/dist/lib/light_push/light_push.js +12 -21
  21. package/dist/lib/light_push/light_push.js.map +1 -1
  22. package/dist/lib/light_push/light_push_v3.d.ts +9 -0
  23. package/dist/lib/light_push/light_push_v3.js +171 -0
  24. package/dist/lib/light_push/light_push_v3.js.map +1 -0
  25. package/dist/lib/light_push/push_rpc.d.ts +1 -1
  26. package/dist/lib/light_push/push_rpc.js.map +1 -1
  27. package/dist/lib/light_push/push_rpc_v2.d.ts +11 -0
  28. package/dist/lib/light_push/push_rpc_v2.js +32 -0
  29. package/dist/lib/light_push/push_rpc_v2.js.map +1 -0
  30. package/dist/lib/light_push/push_rpc_v3.d.ts +11 -0
  31. package/dist/lib/light_push/push_rpc_v3.js +33 -0
  32. package/dist/lib/light_push/push_rpc_v3.js.map +1 -0
  33. package/dist/lib/light_push/status_codes.d.ts +14 -0
  34. package/dist/lib/light_push/status_codes.js +49 -0
  35. package/dist/lib/light_push/status_codes.js.map +1 -0
  36. package/dist/lib/light_push/status_codes_v3.d.ts +4 -0
  37. package/dist/lib/light_push/status_codes_v3.js +53 -0
  38. package/dist/lib/light_push/status_codes_v3.js.map +1 -0
  39. package/dist/lib/light_push/utils.d.ts +6 -0
  40. package/dist/lib/light_push/utils.js +41 -0
  41. package/dist/lib/light_push/utils.js.map +1 -1
  42. package/dist/lib/message/version_0.d.ts +2 -3
  43. package/dist/lib/message/version_0.js +1 -4
  44. package/dist/lib/message/version_0.js.map +1 -1
  45. package/dist/lib/message_hash/index.d.ts +1 -0
  46. package/dist/lib/message_hash/index.js +2 -0
  47. package/dist/lib/message_hash/index.js.map +1 -0
  48. package/dist/lib/message_hash/message_hash.d.ts +52 -0
  49. package/dist/lib/message_hash/message_hash.js +84 -0
  50. package/dist/lib/message_hash/message_hash.js.map +1 -0
  51. package/dist/lib/store/rpc.js +16 -10
  52. package/dist/lib/store/rpc.js.map +1 -1
  53. package/dist/lib/store/store.js +12 -2
  54. package/dist/lib/store/store.js.map +1 -1
  55. package/package.json +1 -1
  56. package/src/index.ts +7 -0
  57. package/src/lib/connection_manager/connection_manager.ts +1 -1
  58. package/src/lib/filter/filter.ts +33 -6
  59. package/src/lib/light_push/index.ts +22 -1
  60. package/src/lib/light_push/light_push.ts +19 -25
  61. package/src/lib/light_push/light_push_v3.ts +232 -0
  62. package/src/lib/light_push/push_rpc.ts +1 -1
  63. package/src/lib/light_push/push_rpc_v2.ts +38 -0
  64. package/src/lib/light_push/push_rpc_v3.ts +46 -0
  65. package/src/lib/light_push/status_codes.ts +71 -0
  66. package/src/lib/light_push/status_codes_v3.ts +80 -0
  67. package/src/lib/light_push/utils.ts +57 -0
  68. package/src/lib/message/version_0.ts +3 -7
  69. package/src/lib/message_hash/index.ts +1 -0
  70. package/src/lib/message_hash/message_hash.ts +106 -0
  71. package/src/lib/store/rpc.ts +23 -19
  72. package/src/lib/store/store.ts +13 -1
package/bundle/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { v as version_0, a as allocUnsafe, b as alloc, e as encodingLength$1, c as encode$2, d as decode$4, F as FilterSubscribeRequest, f as FilterSubscribeResponse$1, M as MessagePush, P as PushRpc$1, g as PushResponse, S as StoreQueryRequest$1, h as StoreQueryResponse$1, t as toString$1, i as bases, j as fromString, u as utf8ToBytes, k as createEncoder, p as pubsubTopicToSingleShardInfo, l as bytesToUtf8, s as shardInfoToPubsubTopics, W as WakuMetadataRequest, m as pubsubTopicsToShardInfo, n as WakuMetadataResponse } from './version_0-CiYGrPc2.js';
2
- export { o as createDecoder } from './version_0-CiYGrPc2.js';
3
- import { e as equals$2, c as coerce, b as base32, a as base58btc, d as base36, L as Logger, P as ProtocolError, T as Tags, E as EPeersByDiscoveryEvents, f as EConnectionStateEvents } from './index-CTo1my9M.js';
4
- import { B as BaseProtocol } from './base_protocol-DvQrudwy.js';
5
- export { S as StreamManager } from './base_protocol-DvQrudwy.js';
1
+ import { v as version_0, a as allocUnsafe, b as alloc, e as encodingLength$1, c as encode$2, d as decode$4, F as FilterSubscribeRequest, f as FilterSubscribeResponse$1, M as MessagePush, P as PushRpc, L as LightpushResponse, g as LightpushRequest, h as PushResponse, S as StoreQueryRequest$1, i as StoreQueryResponse$1, t as toString$1, j as bases, k as fromString, u as utf8ToBytes, l as createEncoder, p as pubsubTopicToSingleShardInfo, m as bytesToUtf8, s as shardInfoToPubsubTopics, W as WakuMetadataRequest, n as pubsubTopicsToShardInfo, o as WakuMetadataResponse, q as concat$1, r as sha256, w as bytesToHex, x as numberToBytes } from './version_0-sWyv9XWm.js';
2
+ export { y as createDecoder } from './version_0-sWyv9XWm.js';
3
+ import { e as equals$2, c as coerce, b as base32, a as base58btc, d as base36, L as Logger, P as ProtocolError, f as LightPushStatusCodeV3, g as LightPushCodecV3, i as isSuccessStatusCodeV3, T as Tags, E as EPeersByDiscoveryEvents, h as EConnectionStateEvents } from './index-JnhMR9ZE.js';
4
+ import { B as BaseProtocol } from './base_protocol-DbwKyDLW.js';
5
+ export { S as StreamManager } from './base_protocol-DbwKyDLW.js';
6
6
 
7
7
  /* eslint-disable */
8
8
  var encode_1 = encode$1;
@@ -514,6 +514,10 @@ function encodeCID(version, code, multihash) {
514
514
  }
515
515
  const cidSymbol = Symbol.for('@ipld/js-cid/CID');
516
516
 
517
+ function isDefined(value) {
518
+ return Boolean(value);
519
+ }
520
+
517
521
  const MB = 1024 ** 2;
518
522
  const SIZE_CAP_IN_MB = 1;
519
523
  /**
@@ -2294,24 +2298,42 @@ class FilterSubscribeResponse {
2294
2298
  }
2295
2299
  }
2296
2300
 
2297
- const log$5 = new Logger("filter:v2");
2301
+ const log$6 = new Logger("filter:v2");
2298
2302
  const FilterCodecs = {
2299
2303
  SUBSCRIBE: "/vac/waku/filter-subscribe/2.0.0-beta1",
2300
2304
  PUSH: "/vac/waku/filter-push/2.0.0-beta1"
2301
2305
  };
2302
2306
  class FilterCore extends BaseProtocol {
2303
- handleIncomingMessage;
2304
2307
  pubsubTopics;
2308
+ static handleIncomingMessage;
2305
2309
  constructor(handleIncomingMessage, pubsubTopics, libp2p) {
2306
2310
  super(FilterCodecs.SUBSCRIBE, libp2p.components, pubsubTopics);
2307
- this.handleIncomingMessage = handleIncomingMessage;
2308
2311
  this.pubsubTopics = pubsubTopics;
2312
+ // TODO(weboko): remove when @waku/sdk 0.0.33 is released
2313
+ const prevHandler = FilterCore.handleIncomingMessage;
2314
+ FilterCore.handleIncomingMessage = !prevHandler
2315
+ ? handleIncomingMessage
2316
+ : async (pubsubTopic, message, peerIdStr) => {
2317
+ try {
2318
+ await prevHandler(pubsubTopic, message, peerIdStr);
2319
+ }
2320
+ catch (e) {
2321
+ log$6.error("Previous FilterCore incoming message handler failed ", e);
2322
+ }
2323
+ try {
2324
+ await handleIncomingMessage(pubsubTopic, message, peerIdStr);
2325
+ }
2326
+ catch (e) {
2327
+ log$6.error("Present FilterCore incoming message handler failed ", e);
2328
+ }
2329
+ return;
2330
+ };
2309
2331
  libp2p
2310
2332
  .handle(FilterCodecs.PUSH, this.onRequest.bind(this), {
2311
2333
  maxInboundStreams: 100
2312
2334
  })
2313
2335
  .catch((e) => {
2314
- log$5.error("Failed to register ", FilterCodecs.PUSH, e);
2336
+ log$6.error("Failed to register ", FilterCodecs.PUSH, e);
2315
2337
  });
2316
2338
  }
2317
2339
  async subscribe(pubsubTopic, peerId, contentTopics) {
@@ -2322,7 +2344,7 @@ class FilterCore extends BaseProtocol {
2322
2344
  res = await pipe([request.encode()], encode, stream, decode, async (source) => await all(source));
2323
2345
  }
2324
2346
  catch (error) {
2325
- log$5.error("Failed to send subscribe request", error);
2347
+ log$6.error("Failed to send subscribe request", error);
2326
2348
  return {
2327
2349
  success: null,
2328
2350
  failure: {
@@ -2333,7 +2355,7 @@ class FilterCore extends BaseProtocol {
2333
2355
  }
2334
2356
  const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
2335
2357
  if (statusCode < 200 || statusCode >= 300) {
2336
- log$5.error(`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2358
+ log$6.error(`Filter subscribe request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2337
2359
  return {
2338
2360
  failure: {
2339
2361
  error: ProtocolError.REMOTE_PEER_REJECTED,
@@ -2353,7 +2375,7 @@ class FilterCore extends BaseProtocol {
2353
2375
  stream = await this.getStream(peerId);
2354
2376
  }
2355
2377
  catch (error) {
2356
- log$5.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
2378
+ log$6.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
2357
2379
  return {
2358
2380
  success: null,
2359
2381
  failure: {
@@ -2367,7 +2389,7 @@ class FilterCore extends BaseProtocol {
2367
2389
  await pipe([unsubscribeRequest.encode()], encode, stream.sink);
2368
2390
  }
2369
2391
  catch (error) {
2370
- log$5.error("Failed to send unsubscribe request", error);
2392
+ log$6.error("Failed to send unsubscribe request", error);
2371
2393
  return {
2372
2394
  success: null,
2373
2395
  failure: {
@@ -2396,7 +2418,7 @@ class FilterCore extends BaseProtocol {
2396
2418
  }
2397
2419
  const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
2398
2420
  if (statusCode < 200 || statusCode >= 300) {
2399
- log$5.error(`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2421
+ log$6.error(`Filter unsubscribe all request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2400
2422
  return {
2401
2423
  failure: {
2402
2424
  error: ProtocolError.REMOTE_PEER_REJECTED,
@@ -2416,7 +2438,7 @@ class FilterCore extends BaseProtocol {
2416
2438
  stream = await this.getStream(peerId);
2417
2439
  }
2418
2440
  catch (error) {
2419
- log$5.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
2441
+ log$6.error(`Failed to get a stream for remote peer${peerId.toString()}`, error);
2420
2442
  return {
2421
2443
  success: null,
2422
2444
  failure: {
@@ -2431,7 +2453,7 @@ class FilterCore extends BaseProtocol {
2431
2453
  res = await pipe([request.encode()], encode, stream, decode, async (source) => await all(source));
2432
2454
  }
2433
2455
  catch (error) {
2434
- log$5.error("Failed to send ping request", error);
2456
+ log$6.error("Failed to send ping request", error);
2435
2457
  return {
2436
2458
  success: null,
2437
2459
  failure: {
@@ -2451,7 +2473,7 @@ class FilterCore extends BaseProtocol {
2451
2473
  }
2452
2474
  const { statusCode, requestId, statusDesc } = FilterSubscribeResponse.decode(res[0].slice());
2453
2475
  if (statusCode < 200 || statusCode >= 300) {
2454
- log$5.error(`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2476
+ log$6.error(`Filter ping request ${requestId} failed with status code ${statusCode}: ${statusDesc}`);
2455
2477
  return {
2456
2478
  success: null,
2457
2479
  failure: {
@@ -2468,30 +2490,30 @@ class FilterCore extends BaseProtocol {
2468
2490
  onRequest(streamData) {
2469
2491
  const { connection, stream } = streamData;
2470
2492
  const { remotePeer } = connection;
2471
- log$5.info(`Received message from ${remotePeer.toString()}`);
2493
+ log$6.info(`Received message from ${remotePeer.toString()}`);
2472
2494
  try {
2473
2495
  pipe(stream, decode, async (source) => {
2474
2496
  for await (const bytes of source) {
2475
2497
  const response = FilterPushRpc.decode(bytes.slice());
2476
2498
  const { pubsubTopic, wakuMessage } = response;
2477
2499
  if (!wakuMessage) {
2478
- log$5.error("Received empty message");
2500
+ log$6.error("Received empty message");
2479
2501
  return;
2480
2502
  }
2481
2503
  if (!pubsubTopic) {
2482
- log$5.error("Pubsub topic missing from push message");
2504
+ log$6.error("Pubsub topic missing from push message");
2483
2505
  return;
2484
2506
  }
2485
- await this.handleIncomingMessage(pubsubTopic, wakuMessage, connection.remotePeer.toString());
2507
+ await FilterCore.handleIncomingMessage?.(pubsubTopic, wakuMessage, connection.remotePeer.toString());
2486
2508
  }
2487
2509
  }).then(() => {
2488
- log$5.info("Receiving pipe closed.");
2510
+ log$6.info("Receiving pipe closed.");
2489
2511
  }, async (e) => {
2490
- log$5.error(`Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `, e);
2512
+ log$6.error(`Error with receiving pipe on peer:${connection.remotePeer.toString()} -- stream:${stream.id} -- protocol:${stream.protocol}: `, e);
2491
2513
  });
2492
2514
  }
2493
2515
  catch (e) {
2494
- log$5.error("Error decoding message", e);
2516
+ log$6.error("Error decoding message", e);
2495
2517
  }
2496
2518
  }
2497
2519
  }
@@ -2502,13 +2524,13 @@ var index$2 = /*#__PURE__*/Object.freeze({
2502
2524
  FilterCore: FilterCore
2503
2525
  });
2504
2526
 
2505
- class PushRpc {
2527
+ class PushRpcV2 {
2506
2528
  proto;
2507
2529
  constructor(proto) {
2508
2530
  this.proto = proto;
2509
2531
  }
2510
2532
  static createRequest(message, pubsubTopic) {
2511
- return new PushRpc({
2533
+ return new PushRpcV2({
2512
2534
  requestId: v4(),
2513
2535
  request: {
2514
2536
  message: message,
@@ -2518,11 +2540,11 @@ class PushRpc {
2518
2540
  });
2519
2541
  }
2520
2542
  static decode(bytes) {
2521
- const res = PushRpc$1.decode(bytes);
2522
- return new PushRpc(res);
2543
+ const res = PushRpc.decode(bytes);
2544
+ return new PushRpcV2(res);
2523
2545
  }
2524
2546
  encode() {
2525
- return PushRpc$1.encode(this.proto);
2547
+ return PushRpc.encode(this.proto);
2526
2548
  }
2527
2549
  get query() {
2528
2550
  return this.proto.request;
@@ -2549,18 +2571,260 @@ const isRLNResponseError = (info) => {
2549
2571
  info.includes(RLN_MESSAGE_ID_PREFIX_ERROR) ||
2550
2572
  info.includes(RLN_REMOTE_VALIDATION));
2551
2573
  };
2552
-
2553
- const log$4 = new Logger("light-push");
2554
- const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
2555
2574
  /**
2556
- * Implements the [Waku v2 Light Push protocol](https://rfc.vac.dev/spec/19/).
2575
+ * Maps error information from push response to appropriate ProtocolError
2576
+ * Uses pattern matching to handle various error cases
2557
2577
  */
2578
+ function mapInfoToProtocolError(info) {
2579
+ if (!info) {
2580
+ return ProtocolError.REMOTE_PEER_REJECTED;
2581
+ }
2582
+ const lowerInfo = info.toLowerCase();
2583
+ // RLN errors
2584
+ if (isRLNResponseError(info)) {
2585
+ return ProtocolError.RLN_PROOF_GENERATION;
2586
+ }
2587
+ // Rate limiting patterns
2588
+ if (lowerInfo.includes("rate limit") ||
2589
+ lowerInfo.includes("too many requests")) {
2590
+ return ProtocolError.REMOTE_PEER_REJECTED;
2591
+ }
2592
+ // Topic errors
2593
+ if (lowerInfo.includes("topic") &&
2594
+ (lowerInfo.includes("not found") || lowerInfo.includes("not configured"))) {
2595
+ return ProtocolError.TOPIC_NOT_CONFIGURED;
2596
+ }
2597
+ // Size errors
2598
+ if (lowerInfo.includes("too large") || lowerInfo.includes("size")) {
2599
+ return ProtocolError.SIZE_TOO_BIG;
2600
+ }
2601
+ // Decoding errors
2602
+ if (lowerInfo.includes("decode") ||
2603
+ lowerInfo.includes("invalid") ||
2604
+ lowerInfo.includes("malformed")) {
2605
+ return ProtocolError.DECODE_FAILED;
2606
+ }
2607
+ // Empty payload
2608
+ if (lowerInfo.includes("empty") && lowerInfo.includes("payload")) {
2609
+ return ProtocolError.EMPTY_PAYLOAD;
2610
+ }
2611
+ // Default case
2612
+ return ProtocolError.REMOTE_PEER_REJECTED;
2613
+ }
2614
+
2615
+ const log$5 = new Logger("light-push");
2616
+ const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
2617
+ const LightPushCodecV2 = LightPushCodec;
2558
2618
  class LightPushCore extends BaseProtocol {
2559
2619
  pubsubTopics;
2560
2620
  constructor(pubsubTopics, libp2p) {
2561
2621
  super(LightPushCodec, libp2p.components, pubsubTopics);
2562
2622
  this.pubsubTopics = pubsubTopics;
2563
2623
  }
2624
+ async preparePushMessage(encoder, message) {
2625
+ try {
2626
+ if (!message.payload || message.payload.length === 0) {
2627
+ log$5.error("Failed to send waku light push: payload is empty");
2628
+ return { query: null, error: ProtocolError.EMPTY_PAYLOAD };
2629
+ }
2630
+ if (!(await isMessageSizeUnderCap(encoder, message))) {
2631
+ log$5.error("Failed to send waku light push: message is bigger than 1MB");
2632
+ return { query: null, error: ProtocolError.SIZE_TOO_BIG };
2633
+ }
2634
+ const protoMessage = await encoder.toProtoObj(message);
2635
+ if (!protoMessage) {
2636
+ log$5.error("Failed to encode to protoMessage, aborting push");
2637
+ return {
2638
+ query: null,
2639
+ error: ProtocolError.ENCODE_FAILED
2640
+ };
2641
+ }
2642
+ const query = PushRpcV2.createRequest(protoMessage, encoder.pubsubTopic);
2643
+ return { query, error: null };
2644
+ }
2645
+ catch (error) {
2646
+ log$5.error("Failed to prepare push message", error);
2647
+ return {
2648
+ query: null,
2649
+ error: ProtocolError.GENERIC_FAIL
2650
+ };
2651
+ }
2652
+ }
2653
+ async send(encoder, message, peerId) {
2654
+ const { query, error: preparationError } = await this.preparePushMessage(encoder, message);
2655
+ if (preparationError || !query) {
2656
+ return {
2657
+ success: null,
2658
+ failure: {
2659
+ error: preparationError,
2660
+ peerId
2661
+ }
2662
+ };
2663
+ }
2664
+ let stream;
2665
+ try {
2666
+ stream = await this.getStream(peerId);
2667
+ }
2668
+ catch (error) {
2669
+ log$5.error("Failed to get stream", error);
2670
+ return {
2671
+ success: null,
2672
+ failure: {
2673
+ error: ProtocolError.NO_STREAM_AVAILABLE,
2674
+ peerId: peerId
2675
+ }
2676
+ };
2677
+ }
2678
+ let res;
2679
+ try {
2680
+ res = await pipe([query.encode()], encode, stream, decode, async (source) => await all(source));
2681
+ }
2682
+ catch (err) {
2683
+ log$5.error("Failed to send waku light push request", err);
2684
+ return {
2685
+ success: null,
2686
+ failure: {
2687
+ error: ProtocolError.STREAM_ABORTED,
2688
+ peerId: peerId
2689
+ }
2690
+ };
2691
+ }
2692
+ const bytes = new Uint8ArrayList();
2693
+ res.forEach((chunk) => {
2694
+ bytes.append(chunk);
2695
+ });
2696
+ let response;
2697
+ try {
2698
+ response = PushRpcV2.decode(bytes).response;
2699
+ }
2700
+ catch (err) {
2701
+ log$5.error("Failed to decode push reply", err);
2702
+ return {
2703
+ success: null,
2704
+ failure: {
2705
+ error: ProtocolError.DECODE_FAILED,
2706
+ peerId: peerId
2707
+ }
2708
+ };
2709
+ }
2710
+ if (!response) {
2711
+ log$5.error("Remote peer fault: No response in PushRPC");
2712
+ return {
2713
+ success: null,
2714
+ failure: {
2715
+ error: ProtocolError.NO_RESPONSE,
2716
+ peerId: peerId
2717
+ }
2718
+ };
2719
+ }
2720
+ if (!response.isSuccess) {
2721
+ const errorMessage = response.info || "Message rejected";
2722
+ log$5.error("Remote peer rejected the message: ", errorMessage);
2723
+ // Use pattern matching to determine the appropriate error type
2724
+ const error = mapInfoToProtocolError(response.info);
2725
+ return {
2726
+ success: null,
2727
+ failure: {
2728
+ error: error,
2729
+ peerId: peerId
2730
+ }
2731
+ };
2732
+ }
2733
+ return { success: peerId, failure: null };
2734
+ }
2735
+ }
2736
+ const LightPushCoreV2 = LightPushCore;
2737
+
2738
+ class PushRpcV3 {
2739
+ request;
2740
+ response;
2741
+ constructor(request, response) {
2742
+ this.request = request;
2743
+ this.response = response;
2744
+ }
2745
+ static createRequest(message, pubsubTopic) {
2746
+ const request = {
2747
+ requestId: v4(),
2748
+ message: message,
2749
+ // Only include pubsubTopic if explicitly provided (for nwaku autosharding compatibility)
2750
+ ...(pubsubTopic && { pubsubTopic })
2751
+ };
2752
+ return new PushRpcV3(request, undefined);
2753
+ }
2754
+ static decode(bytes) {
2755
+ const response = LightpushResponse.decode(bytes);
2756
+ return new PushRpcV3(undefined, response);
2757
+ }
2758
+ encode() {
2759
+ if (!this.request) {
2760
+ throw new Error("Cannot encode without a request");
2761
+ }
2762
+ return LightpushRequest.encode(this.request);
2763
+ }
2764
+ get query() {
2765
+ return this.request;
2766
+ }
2767
+ }
2768
+
2769
+ const lightPushStatusDescriptionsV3 = {
2770
+ [LightPushStatusCodeV3.SUCCESS]: "Message sent successfully",
2771
+ [LightPushStatusCodeV3.BAD_REQUEST]: "Bad request format",
2772
+ [LightPushStatusCodeV3.PAYLOAD_TOO_LARGE]: "Message payload exceeds maximum size",
2773
+ [LightPushStatusCodeV3.INVALID_MESSAGE_ERROR]: "Message validation failed",
2774
+ [LightPushStatusCodeV3.UNSUPPORTED_PUBSUB_TOPIC]: "Unsupported pubsub topic",
2775
+ [LightPushStatusCodeV3.TOO_MANY_REQUESTS]: "Rate limit exceeded",
2776
+ [LightPushStatusCodeV3.INTERNAL_SERVER_ERROR]: "Internal server error",
2777
+ [LightPushStatusCodeV3.SERVICE_NOT_AVAILABLE]: "Service temporarily unavailable",
2778
+ [LightPushStatusCodeV3.OUT_OF_RLN_PROOF]: "RLN proof generation failed",
2779
+ [LightPushStatusCodeV3.NO_PEERS_TO_RELAY]: "No relay peers available"
2780
+ };
2781
+ function lightPushStatusCodeToProtocolErrorV3(statusCode) {
2782
+ if (!statusCode) {
2783
+ return ProtocolError.GENERIC_FAIL;
2784
+ }
2785
+ switch (statusCode) {
2786
+ case LightPushStatusCodeV3.SUCCESS:
2787
+ return ProtocolError.GENERIC_FAIL;
2788
+ case LightPushStatusCodeV3.BAD_REQUEST:
2789
+ return ProtocolError.DECODE_FAILED;
2790
+ case LightPushStatusCodeV3.PAYLOAD_TOO_LARGE:
2791
+ return ProtocolError.SIZE_TOO_BIG;
2792
+ case LightPushStatusCodeV3.INVALID_MESSAGE_ERROR:
2793
+ return ProtocolError.EMPTY_PAYLOAD;
2794
+ case LightPushStatusCodeV3.UNSUPPORTED_PUBSUB_TOPIC:
2795
+ return ProtocolError.TOPIC_NOT_CONFIGURED;
2796
+ case LightPushStatusCodeV3.TOO_MANY_REQUESTS:
2797
+ return ProtocolError.REMOTE_PEER_REJECTED;
2798
+ case LightPushStatusCodeV3.INTERNAL_SERVER_ERROR:
2799
+ return ProtocolError.GENERIC_FAIL;
2800
+ case LightPushStatusCodeV3.SERVICE_NOT_AVAILABLE:
2801
+ return ProtocolError.NO_PEER_AVAILABLE;
2802
+ case LightPushStatusCodeV3.OUT_OF_RLN_PROOF:
2803
+ return ProtocolError.RLN_PROOF_GENERATION;
2804
+ case LightPushStatusCodeV3.NO_PEERS_TO_RELAY:
2805
+ return ProtocolError.NO_PEER_AVAILABLE;
2806
+ default:
2807
+ return ProtocolError.REMOTE_PEER_REJECTED;
2808
+ }
2809
+ }
2810
+ function getLightPushStatusDescriptionV3(statusCode, customDesc) {
2811
+ if (customDesc) {
2812
+ return customDesc;
2813
+ }
2814
+ if (!statusCode) {
2815
+ return "Unknown error";
2816
+ }
2817
+ return (lightPushStatusDescriptionsV3[statusCode] ||
2818
+ `Unknown status code: ${statusCode}`);
2819
+ }
2820
+
2821
+ const log$4 = new Logger("light-push-v3");
2822
+ class LightPushCoreV3 extends BaseProtocol {
2823
+ pubsubTopics;
2824
+ constructor(pubsubTopics, libp2p) {
2825
+ super(LightPushCodecV3, libp2p.components, pubsubTopics);
2826
+ this.pubsubTopics = pubsubTopics;
2827
+ }
2564
2828
  async preparePushMessage(encoder, message) {
2565
2829
  try {
2566
2830
  if (!message.payload || message.payload.length === 0) {
@@ -2579,7 +2843,7 @@ class LightPushCore extends BaseProtocol {
2579
2843
  error: ProtocolError.ENCODE_FAILED
2580
2844
  };
2581
2845
  }
2582
- const query = PushRpc.createRequest(protoMessage, encoder.pubsubTopic);
2846
+ const query = PushRpcV3.createRequest(protoMessage, encoder.pubsubTopic);
2583
2847
  return { query, error: null };
2584
2848
  }
2585
2849
  catch (error) {
@@ -2620,7 +2884,6 @@ class LightPushCore extends BaseProtocol {
2620
2884
  res = await pipe([query.encode()], encode, stream, decode, async (source) => await all(source));
2621
2885
  }
2622
2886
  catch (err) {
2623
- // can fail only because of `stream` abortion
2624
2887
  log$4.error("Failed to send waku light push request", err);
2625
2888
  return {
2626
2889
  success: null,
@@ -2636,10 +2899,10 @@ class LightPushCore extends BaseProtocol {
2636
2899
  });
2637
2900
  let response;
2638
2901
  try {
2639
- response = PushRpc.decode(bytes).response;
2902
+ response = LightpushResponse.decode(bytes);
2640
2903
  }
2641
2904
  catch (err) {
2642
- log$4.error("Failed to decode push reply", err);
2905
+ log$4.error("Failed to decode push response", err);
2643
2906
  return {
2644
2907
  success: null,
2645
2908
  failure: {
@@ -2649,7 +2912,7 @@ class LightPushCore extends BaseProtocol {
2649
2912
  };
2650
2913
  }
2651
2914
  if (!response) {
2652
- log$4.error("Remote peer fault: No response in PushRPC");
2915
+ log$4.error("Remote peer fault: No response received");
2653
2916
  return {
2654
2917
  success: null,
2655
2918
  failure: {
@@ -2658,7 +2921,37 @@ class LightPushCore extends BaseProtocol {
2658
2921
  }
2659
2922
  };
2660
2923
  }
2661
- if (isRLNResponseError(response.info)) {
2924
+ // Validate request ID matches (except for rate limiting responses)
2925
+ if (response.requestId !== query.query?.requestId) {
2926
+ // nwaku sends "N/A" for rate limiting responses
2927
+ if (response.statusCode !== LightPushStatusCodeV3.TOO_MANY_REQUESTS) {
2928
+ log$4.error("Request ID mismatch", {
2929
+ sent: query.query?.requestId,
2930
+ received: response.requestId
2931
+ });
2932
+ return {
2933
+ success: null,
2934
+ failure: {
2935
+ error: ProtocolError.GENERIC_FAIL,
2936
+ peerId: peerId
2937
+ }
2938
+ };
2939
+ }
2940
+ }
2941
+ const statusCode = response.statusCode;
2942
+ const isSuccess = isSuccessStatusCodeV3(statusCode);
2943
+ // Special handling for nwaku rate limiting
2944
+ if (statusCode === LightPushStatusCodeV3.TOO_MANY_REQUESTS) {
2945
+ if (response.requestId === "N/A") {
2946
+ log$4.warn("Rate limited by nwaku node", {
2947
+ statusDesc: response.statusDesc || "Request rejected due to too many requests"
2948
+ });
2949
+ }
2950
+ }
2951
+ if (response.relayPeerCount !== undefined) {
2952
+ log$4.info(`Message relayed to ${response.relayPeerCount} peers`);
2953
+ }
2954
+ if (response.statusDesc && isRLNResponseError(response.statusDesc)) {
2662
2955
  log$4.error("Remote peer fault: RLN generation");
2663
2956
  return {
2664
2957
  success: null,
@@ -2668,12 +2961,14 @@ class LightPushCore extends BaseProtocol {
2668
2961
  }
2669
2962
  };
2670
2963
  }
2671
- if (!response.isSuccess) {
2672
- log$4.error("Remote peer rejected the message: ", response.info);
2964
+ if (!isSuccess) {
2965
+ const errorMessage = getLightPushStatusDescriptionV3(statusCode, response.statusDesc);
2966
+ log$4.error("Remote peer rejected the message: ", errorMessage);
2967
+ const protocolError = lightPushStatusCodeToProtocolErrorV3(statusCode);
2673
2968
  return {
2674
2969
  success: null,
2675
2970
  failure: {
2676
- error: ProtocolError.REMOTE_PEER_REJECTED,
2971
+ error: protocolError,
2677
2972
  peerId: peerId
2678
2973
  }
2679
2974
  };
@@ -2682,11 +2977,71 @@ class LightPushCore extends BaseProtocol {
2682
2977
  }
2683
2978
  }
2684
2979
 
2980
+ var LightPushStatusCode;
2981
+ (function (LightPushStatusCode) {
2982
+ LightPushStatusCode[LightPushStatusCode["SUCCESS"] = 200] = "SUCCESS";
2983
+ LightPushStatusCode[LightPushStatusCode["BAD_REQUEST"] = 400] = "BAD_REQUEST";
2984
+ LightPushStatusCode[LightPushStatusCode["UNSUPPORTED_PUBSUB_TOPIC"] = 404] = "UNSUPPORTED_PUBSUB_TOPIC";
2985
+ LightPushStatusCode[LightPushStatusCode["REQUEST_TOO_LARGE"] = 413] = "REQUEST_TOO_LARGE";
2986
+ LightPushStatusCode[LightPushStatusCode["TOO_MANY_REQUESTS"] = 429] = "TOO_MANY_REQUESTS";
2987
+ LightPushStatusCode[LightPushStatusCode["INTERNAL_SERVER_ERROR"] = 500] = "INTERNAL_SERVER_ERROR";
2988
+ LightPushStatusCode[LightPushStatusCode["NO_PEERS_TO_RELAY"] = 503] = "NO_PEERS_TO_RELAY";
2989
+ })(LightPushStatusCode || (LightPushStatusCode = {}));
2990
+ function lightPushStatusCodeToProtocolError(statusCode) {
2991
+ switch (statusCode) {
2992
+ case LightPushStatusCode.SUCCESS:
2993
+ return null;
2994
+ case LightPushStatusCode.BAD_REQUEST:
2995
+ return ProtocolError.GENERIC_FAIL;
2996
+ case LightPushStatusCode.UNSUPPORTED_PUBSUB_TOPIC:
2997
+ return ProtocolError.TOPIC_NOT_CONFIGURED;
2998
+ case LightPushStatusCode.REQUEST_TOO_LARGE:
2999
+ return ProtocolError.SIZE_TOO_BIG;
3000
+ case LightPushStatusCode.TOO_MANY_REQUESTS:
3001
+ return ProtocolError.GENERIC_FAIL;
3002
+ case LightPushStatusCode.INTERNAL_SERVER_ERROR:
3003
+ return ProtocolError.REMOTE_PEER_REJECTED;
3004
+ case LightPushStatusCode.NO_PEERS_TO_RELAY:
3005
+ return ProtocolError.NO_PEER_AVAILABLE;
3006
+ default:
3007
+ return ProtocolError.REMOTE_PEER_REJECTED;
3008
+ }
3009
+ }
3010
+ const lightPushStatusDescriptions = {
3011
+ [LightPushStatusCode.SUCCESS]: "Message pushed successfully",
3012
+ [LightPushStatusCode.BAD_REQUEST]: "Invalid request format or missing required fields",
3013
+ [LightPushStatusCode.UNSUPPORTED_PUBSUB_TOPIC]: "The specified pubsub topic is not supported",
3014
+ [LightPushStatusCode.REQUEST_TOO_LARGE]: "Message size exceeds maximum allowed size",
3015
+ [LightPushStatusCode.TOO_MANY_REQUESTS]: "Rate limit exceeded, too many requests",
3016
+ [LightPushStatusCode.INTERNAL_SERVER_ERROR]: "Internal server error occurred",
3017
+ [LightPushStatusCode.NO_PEERS_TO_RELAY]: "No relay peers available to forward the message"
3018
+ };
3019
+ function isSuccessStatusCode(statusCode) {
3020
+ return statusCode === LightPushStatusCode.SUCCESS;
3021
+ }
3022
+ function getLightPushStatusDescription(statusCode, statusDesc) {
3023
+ return (statusDesc ||
3024
+ lightPushStatusDescriptions[statusCode] ||
3025
+ `Unknown status code: ${statusCode}`);
3026
+ }
3027
+
2685
3028
  var index$1 = /*#__PURE__*/Object.freeze({
2686
3029
  __proto__: null,
2687
3030
  LightPushCodec: LightPushCodec,
3031
+ LightPushCodecV2: LightPushCodecV2,
2688
3032
  LightPushCore: LightPushCore,
2689
- get PushResponse () { return PushResponse; }
3033
+ LightPushCoreV2: LightPushCoreV2,
3034
+ LightPushCoreV3: LightPushCoreV3,
3035
+ get LightPushStatusCode () { return LightPushStatusCode; },
3036
+ get PushResponse () { return PushResponse; },
3037
+ PushRpcV3: PushRpcV3,
3038
+ getLightPushStatusDescription: getLightPushStatusDescription,
3039
+ getLightPushStatusDescriptionV3: getLightPushStatusDescriptionV3,
3040
+ isSuccessStatusCode: isSuccessStatusCode,
3041
+ lightPushStatusCodeToProtocolError: lightPushStatusCodeToProtocolError,
3042
+ lightPushStatusCodeToProtocolErrorV3: lightPushStatusCodeToProtocolErrorV3,
3043
+ lightPushStatusDescriptions: lightPushStatusDescriptions,
3044
+ lightPushStatusDescriptionsV3: lightPushStatusDescriptionsV3
2690
3045
  });
2691
3046
 
2692
3047
  const EmptyMessage = {
@@ -2714,6 +3069,7 @@ class StoreQueryRequest {
2714
3069
  static create(params) {
2715
3070
  const request = new StoreQueryRequest({
2716
3071
  ...params,
3072
+ contentTopics: params.contentTopics || [],
2717
3073
  requestId: v4(),
2718
3074
  timeStart: params.timeStart
2719
3075
  ? BigInt(params.timeStart.getTime() * ONE_MILLION)
@@ -2726,17 +3082,22 @@ class StoreQueryRequest {
2726
3082
  ? BigInt(params.paginationLimit)
2727
3083
  : undefined
2728
3084
  });
2729
- // Validate request parameters based on RFC
2730
- if ((params.pubsubTopic && !params.contentTopics) ||
2731
- (!params.pubsubTopic && params.contentTopics)) {
2732
- throw new Error("Both pubsubTopic and contentTopics must be set or unset");
2733
- }
2734
- if (params.messageHashes &&
2735
- (params.pubsubTopic ||
2736
- params.contentTopics ||
2737
- params.timeStart ||
2738
- params.timeEnd)) {
2739
- throw new Error("Message hash lookup queries cannot include content filter criteria");
3085
+ const isHashQuery = params.messageHashes && params.messageHashes.length > 0;
3086
+ const hasContentTopics = params.contentTopics && params.contentTopics.length > 0;
3087
+ const hasTimeFilter = params.timeStart || params.timeEnd;
3088
+ if (isHashQuery) {
3089
+ if (hasContentTopics || hasTimeFilter) {
3090
+ throw new Error("Message hash lookup queries cannot include content filter criteria (contentTopics, timeStart, or timeEnd)");
3091
+ }
3092
+ }
3093
+ else {
3094
+ if ((params.pubsubTopic &&
3095
+ (!params.contentTopics || params.contentTopics.length === 0)) ||
3096
+ (!params.pubsubTopic &&
3097
+ params.contentTopics &&
3098
+ params.contentTopics.length > 0)) {
3099
+ throw new Error("Both pubsubTopic and contentTopics must be set together for content-filtered queries");
3100
+ }
2740
3101
  }
2741
3102
  return request;
2742
3103
  }
@@ -2783,8 +3144,12 @@ class StoreCore extends BaseProtocol {
2783
3144
  this.pubsubTopics = pubsubTopics;
2784
3145
  }
2785
3146
  async *queryPerPage(queryOpts, decoders, peerId) {
2786
- if (queryOpts.contentTopics.toString() !==
2787
- Array.from(decoders.keys()).toString()) {
3147
+ // Only validate decoder content topics for content-filtered queries
3148
+ const isHashQuery = queryOpts.messageHashes && queryOpts.messageHashes.length > 0;
3149
+ if (!isHashQuery &&
3150
+ queryOpts.contentTopics &&
3151
+ queryOpts.contentTopics.toString() !==
3152
+ Array.from(decoders.keys()).toString()) {
2788
3153
  throw new Error("Internal error, the decoders should match the query's content topics");
2789
3154
  }
2790
3155
  let currentCursor = queryOpts.paginationCursor;
@@ -2793,6 +3158,12 @@ class StoreCore extends BaseProtocol {
2793
3158
  ...queryOpts,
2794
3159
  paginationCursor: currentCursor
2795
3160
  });
3161
+ log$3.info("Sending store query request:", {
3162
+ hasMessageHashes: !!queryOpts.messageHashes?.length,
3163
+ messageHashCount: queryOpts.messageHashes?.length,
3164
+ pubsubTopic: queryOpts.pubsubTopic,
3165
+ contentTopics: queryOpts.contentTopics
3166
+ });
2796
3167
  let stream;
2797
3168
  try {
2798
3169
  stream = await this.getStream(peerId);
@@ -4386,7 +4757,7 @@ class ConnectionManager extends TypedEventEmitter {
4386
4757
  * // Dial using multiaddr with specific protocols
4387
4758
  * await connectionManager.dialPeer(multiaddr, [
4388
4759
  * "/vac/waku/relay/2.0.0",
4389
- * "/vac/waku/lightpush/2.0.0-beta1"
4760
+ * "/vac/waku/lightpush/3.0.0"
4390
4761
  * ]);
4391
4762
  * ```
4392
4763
  *
@@ -4854,4 +5225,85 @@ function wakuMetadata(pubsubTopics) {
4854
5225
  return (components) => new Metadata(pubsubTopics, components);
4855
5226
  }
4856
5227
 
4857
- export { ConnectionManager, FilterCodecs, FilterCore, LightPushCodec, LightPushCore, MetadataCodec, StoreCodec, StoreCore, createEncoder, index$3 as message, wakuMetadata, index$2 as waku_filter, index$1 as waku_light_push, index as waku_store };
5228
+ /**
5229
+ * Deterministic Message Hashing as defined in
5230
+ * [14/WAKU2-MESSAGE](https://rfc.vac.dev/spec/14/#deterministic-message-hashing)
5231
+ *
5232
+ * Computes a SHA-256 hash of the concatenation of pubsub topic, payload, content topic, meta, and timestamp.
5233
+ *
5234
+ * @param pubsubTopic - The pubsub topic string
5235
+ * @param message - The message to be hashed
5236
+ * @returns A Uint8Array containing the SHA-256 hash
5237
+ *
5238
+ * @example
5239
+ * ```typescript
5240
+ * import { messageHash } from "@waku/core";
5241
+ *
5242
+ * const pubsubTopic = "/waku/2/default-waku/proto";
5243
+ * const message = {
5244
+ * payload: new Uint8Array([1, 2, 3, 4]),
5245
+ * contentTopic: "/waku/2/default-content/proto",
5246
+ * meta: new Uint8Array([5, 6, 7, 8]),
5247
+ * timestamp: new Date()
5248
+ * };
5249
+ *
5250
+ * const hash = messageHash(pubsubTopic, message);
5251
+ * ```
5252
+ */
5253
+ function messageHash(pubsubTopic, message) {
5254
+ const pubsubTopicBytes = utf8ToBytes(pubsubTopic);
5255
+ const contentTopicBytes = utf8ToBytes(message.contentTopic);
5256
+ const timestampBytes = tryConvertTimestampToBytes(message.timestamp);
5257
+ const bytes = concat$1([
5258
+ pubsubTopicBytes,
5259
+ message.payload,
5260
+ contentTopicBytes,
5261
+ message.meta,
5262
+ timestampBytes
5263
+ ].filter(isDefined));
5264
+ return sha256(bytes);
5265
+ }
5266
+ function tryConvertTimestampToBytes(timestamp) {
5267
+ if (!timestamp) {
5268
+ return;
5269
+ }
5270
+ let bigIntTimestamp;
5271
+ if (typeof timestamp === "bigint") {
5272
+ bigIntTimestamp = timestamp;
5273
+ }
5274
+ else {
5275
+ bigIntTimestamp = BigInt(timestamp.valueOf()) * 1000000n;
5276
+ }
5277
+ return numberToBytes(bigIntTimestamp);
5278
+ }
5279
+ /**
5280
+ * Computes a deterministic message hash and returns it as a hexadecimal string.
5281
+ * This is a convenience wrapper around messageHash that converts the result to a hex string.
5282
+ *
5283
+ * @param pubsubTopic - The pubsub topic string
5284
+ * @param message - The message to be hashed
5285
+ * @returns A string containing the hex representation of the SHA-256 hash
5286
+ *
5287
+ * @example
5288
+ * ```typescript
5289
+ * import { messageHashStr } from "@waku/core";
5290
+ *
5291
+ * const pubsubTopic = "/waku/2/default-waku/proto";
5292
+ * const message = {
5293
+ * payload: new Uint8Array([1, 2, 3, 4]),
5294
+ * contentTopic: "/waku/2/default-content/proto",
5295
+ * meta: new Uint8Array([5, 6, 7, 8]),
5296
+ * timestamp: new Date()
5297
+ * };
5298
+ *
5299
+ * const hashString = messageHashStr(pubsubTopic, message);
5300
+ * console.log(hashString); // e.g. "a1b2c3d4..."
5301
+ * ```
5302
+ */
5303
+ function messageHashStr(pubsubTopic, message) {
5304
+ const hash = messageHash(pubsubTopic, message);
5305
+ const hashStr = bytesToHex(hash);
5306
+ return hashStr;
5307
+ }
5308
+
5309
+ export { ConnectionManager, FilterCodecs, FilterCore, LightPushCodec, LightPushCodecV2, LightPushCore, LightPushCoreV2, LightPushCoreV3, MetadataCodec, StoreCodec, StoreCore, createEncoder, index$3 as message, messageHash, messageHashStr, wakuMetadata, index$2 as waku_filter, index$1 as waku_light_push, index as waku_store };