@beam-network/sdk 0.2.18 → 0.2.20

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/README.md CHANGED
@@ -95,6 +95,6 @@ For low-level raw transfer configs, use `createRawTransfer`; lifecycle transport
95
95
 
96
96
  ## Route Streaming And Payload Size
97
97
 
98
- Provider transfers stream signed routes over NATS in target batches of 512 routes. The SDK still splits a batch earlier when the encoded MessagePack request would exceed `maxPayloadBytes`, which defaults to 24 MiB.
98
+ Provider transfers stream signed routes over NATS in target batches of 128 routes. Signing continues while completed batches are sent in order. The SDK still splits a batch earlier when the encoded MessagePack request would exceed `maxPayloadBytes`, which defaults to 24 MiB.
99
99
 
100
100
  NATS requires this guard because the broker rejects messages above its configured `max_payload`. This limit applies only to lifecycle/control metadata; transfer file bytes do not flow through NATS.
package/dist/client.js CHANGED
@@ -113,7 +113,7 @@ export class BeamClient {
113
113
  });
114
114
  await stream.begin();
115
115
  for (const route of input.chunkRoutes) {
116
- await stream.addRoute(route);
116
+ stream.addRoute(route);
117
117
  }
118
118
  return stream.complete();
119
119
  }
@@ -223,7 +223,7 @@ export class BeamClient {
223
223
  }
224
224
  multipartUploads.set(multipartKey, upload);
225
225
  }
226
- await routeStream.addRoute(await this.signProviderRoute({
226
+ routeStream.addRoute(await this.signProviderRoute({
227
227
  chunk,
228
228
  target,
229
229
  source,
@@ -245,6 +245,7 @@ export class BeamClient {
245
245
  }
246
246
  }
247
247
  catch (error) {
248
+ routeStream.abort();
248
249
  this.stopRecoverySigner(prepared.transfer_id);
249
250
  await abortCreatedUploads(multipartUploads);
250
251
  if (routeStreamStarted) {
@@ -440,9 +441,9 @@ export class BeamClient {
440
441
  }
441
442
  }
442
443
  }
443
- // Target route-stream batches at 512 signed routes. The transport still splits
444
+ // Target route-stream batches at 128 signed routes. The transport still splits
444
445
  // earlier when the encoded NATS request would exceed maxPayloadBytes.
445
- const ROUTE_STREAM_TARGET_BATCH_ROUTES = 512;
446
+ const ROUTE_STREAM_TARGET_BATCH_ROUTES = 128;
446
447
  class RouteStreamSender {
447
448
  control;
448
449
  options;
@@ -450,6 +451,8 @@ class RouteStreamSender {
450
451
  checksum = new RouteKeysChecksum();
451
452
  batch = [];
452
453
  batchIndex = 0;
454
+ sendTail = Promise.resolve();
455
+ sendError = null;
453
456
  constructor(control, options) {
454
457
  this.control = control;
455
458
  this.options = options;
@@ -465,15 +468,17 @@ class RouteStreamSender {
465
468
  auto_distribute: this.options.autoDistribute
466
469
  }), this.options.transferId);
467
470
  }
468
- async addRoute(route) {
469
- await this.checksum.add(routeKeyForSignedRoute(route));
471
+ addRoute(route) {
470
472
  this.batch.push(route);
471
473
  if (this.batch.length >= ROUTE_STREAM_TARGET_BATCH_ROUTES) {
472
- await this.flush();
474
+ this.enqueueFlush();
473
475
  }
474
476
  }
475
477
  async complete() {
476
- await this.flush();
478
+ this.enqueueFlush();
479
+ await this.sendTail;
480
+ if (this.sendError)
481
+ throw this.sendError;
477
482
  return this.control.request("transfer.route_stream.complete", {
478
483
  transfer_id: this.options.transferId,
479
484
  stream_id: this.streamId,
@@ -482,7 +487,7 @@ class RouteStreamSender {
482
487
  route_keys_checksum: this.checksum.value()
483
488
  }, this.options.transferId);
484
489
  }
485
- async flush() {
490
+ enqueueFlush() {
486
491
  if (!this.batch.length)
487
492
  return;
488
493
  const routes = this.batch.splice(0, this.batch.length);
@@ -495,39 +500,55 @@ class RouteStreamSender {
495
500
  for (const chunk of chunks) {
496
501
  const batchIndex = this.batchIndex;
497
502
  this.batchIndex += 1;
498
- await this.control.request("transfer.route_stream.batch", {
499
- transfer_id: this.options.transferId,
500
- stream_id: this.streamId,
501
- batch_id: `${this.streamId}:${batchIndex}`,
502
- batch_index: batchIndex,
503
- chunk_routes: chunk,
504
- route_count: chunk.length,
505
- route_keys_checksum: await routeKeysChecksum(chunk.map(routeKeyForSignedRoute))
506
- }, this.options.transferId);
503
+ this.sendTail = this.sendTail.then(async () => {
504
+ if (this.sendError)
505
+ return;
506
+ try {
507
+ const chunkChecksum = new RouteKeysChecksum();
508
+ await chunkChecksum.addMany(chunk.map(routeKeyForSignedRoute));
509
+ this.checksum.merge(chunkChecksum);
510
+ await this.control.request("transfer.route_stream.batch", {
511
+ transfer_id: this.options.transferId,
512
+ stream_id: this.streamId,
513
+ batch_id: `${this.streamId}:${batchIndex}`,
514
+ batch_index: batchIndex,
515
+ chunk_routes: chunk,
516
+ route_count: chunk.length,
517
+ route_keys_checksum: chunkChecksum.value()
518
+ }, this.options.transferId);
519
+ }
520
+ catch (error) {
521
+ this.sendError = error;
522
+ }
523
+ });
507
524
  }
508
525
  }
526
+ abort() {
527
+ this.sendError ??= new Error("route_stream_aborted");
528
+ }
509
529
  }
510
530
  class RouteKeysChecksum {
511
531
  bytes = new Uint8Array(32);
512
532
  count = 0;
513
- async add(routeKeyValue) {
514
- const digest = await sha256Bytes(routeKeyValue);
533
+ async addMany(routeKeys) {
534
+ const digests = await Promise.all(routeKeys.map(sha256Bytes));
535
+ for (const digest of digests) {
536
+ for (let index = 0; index < this.bytes.length; index += 1) {
537
+ this.bytes[index] ^= digest[index] ?? 0;
538
+ }
539
+ }
540
+ this.count += routeKeys.length;
541
+ }
542
+ merge(other) {
515
543
  for (let index = 0; index < this.bytes.length; index += 1) {
516
- this.bytes[index] ^= digest[index] ?? 0;
544
+ this.bytes[index] ^= other.bytes[index] ?? 0;
517
545
  }
518
- this.count += 1;
546
+ this.count += other.count;
519
547
  }
520
548
  value() {
521
549
  return `sha256-xor-v1:${this.count}:${hex(this.bytes)}`;
522
550
  }
523
551
  }
524
- async function routeKeysChecksum(routeKeys) {
525
- const checksum = new RouteKeysChecksum();
526
- for (const routeKeyValue of routeKeys) {
527
- await checksum.add(routeKeyValue);
528
- }
529
- return checksum.value();
530
- }
531
552
  function routeKeyForSignedRoute(route) {
532
553
  return `${route.source_id}:${route.destination_id}:${route.chunk_index}`;
533
554
  }
@@ -58,6 +58,7 @@ export class BeamTransferControl {
58
58
  const nc = await this.connection();
59
59
  const subject = this.routeRecoverySignSubject(transferId);
60
60
  const sub = nc.subscribe(subject);
61
+ await nc.flush();
61
62
  let active = true;
62
63
  void (async () => {
63
64
  for await (const msg of sub) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beam-network/sdk",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
4
4
  "description": "TypeScript SDK for BEAM transfer creation and management.",
5
5
  "type": "module",
6
6
  "license": "MIT",