moqtail 0.7.0 → 0.8.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.
@@ -575,27 +575,37 @@ var ObjectDatagramStatusType, ObjectDatagramType, FetchHeaderType, SubgroupHeade
575
575
  var init_constant = __esm({
576
576
  "src/model/data/constant.ts"() {
577
577
  ObjectDatagramStatusType = /* @__PURE__ */ ((ObjectDatagramStatusType2) => {
578
- ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithoutExtensions"] = 2] = "WithoutExtensions";
579
- ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithExtensions"] = 3] = "WithExtensions";
578
+ ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithoutExtensions"] = 32] = "WithoutExtensions";
579
+ ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithExtensions"] = 33] = "WithExtensions";
580
580
  return ObjectDatagramStatusType2;
581
581
  })(ObjectDatagramStatusType || {});
582
582
  ((ObjectDatagramStatusType2) => {
583
583
  function tryFrom(value) {
584
584
  const v = typeof value === "bigint" ? Number(value) : value;
585
585
  switch (v) {
586
- case 2:
587
- return 2 /* WithoutExtensions */;
588
- case 3:
589
- return 3 /* WithExtensions */;
586
+ case 32:
587
+ return 32 /* WithoutExtensions */;
588
+ case 33:
589
+ return 33 /* WithExtensions */;
590
590
  default:
591
591
  throw new Error(`Invalid ObjectDatagramStatusType: ${value}`);
592
592
  }
593
593
  }
594
594
  ObjectDatagramStatusType2.tryFrom = tryFrom;
595
+ function hasExtensions(t) {
596
+ return t === 33 /* WithExtensions */;
597
+ }
598
+ ObjectDatagramStatusType2.hasExtensions = hasExtensions;
595
599
  })(ObjectDatagramStatusType || (ObjectDatagramStatusType = {}));
596
600
  ObjectDatagramType = /* @__PURE__ */ ((ObjectDatagramType2) => {
597
- ObjectDatagramType2[ObjectDatagramType2["WithoutExtensions"] = 0] = "WithoutExtensions";
598
- ObjectDatagramType2[ObjectDatagramType2["WithExtensions"] = 1] = "WithExtensions";
601
+ ObjectDatagramType2[ObjectDatagramType2["Type0x00"] = 0] = "Type0x00";
602
+ ObjectDatagramType2[ObjectDatagramType2["Type0x01"] = 1] = "Type0x01";
603
+ ObjectDatagramType2[ObjectDatagramType2["Type0x02"] = 2] = "Type0x02";
604
+ ObjectDatagramType2[ObjectDatagramType2["Type0x03"] = 3] = "Type0x03";
605
+ ObjectDatagramType2[ObjectDatagramType2["Type0x04"] = 4] = "Type0x04";
606
+ ObjectDatagramType2[ObjectDatagramType2["Type0x05"] = 5] = "Type0x05";
607
+ ObjectDatagramType2[ObjectDatagramType2["Type0x06"] = 6] = "Type0x06";
608
+ ObjectDatagramType2[ObjectDatagramType2["Type0x07"] = 7] = "Type0x07";
599
609
  return ObjectDatagramType2;
600
610
  })(ObjectDatagramType || {});
601
611
  ((ObjectDatagramType2) => {
@@ -603,14 +613,46 @@ var init_constant = __esm({
603
613
  const v = typeof value === "bigint" ? Number(value) : value;
604
614
  switch (v) {
605
615
  case 0:
606
- return 0 /* WithoutExtensions */;
616
+ return 0 /* Type0x00 */;
607
617
  case 1:
608
- return 1 /* WithExtensions */;
618
+ return 1 /* Type0x01 */;
619
+ case 2:
620
+ return 2 /* Type0x02 */;
621
+ case 3:
622
+ return 3 /* Type0x03 */;
623
+ case 4:
624
+ return 4 /* Type0x04 */;
625
+ case 5:
626
+ return 5 /* Type0x05 */;
627
+ case 6:
628
+ return 6 /* Type0x06 */;
629
+ case 7:
630
+ return 7 /* Type0x07 */;
609
631
  default:
610
632
  throw new Error(`Invalid ObjectDatagramType: ${value}`);
611
633
  }
612
634
  }
613
635
  ObjectDatagramType2.tryFrom = tryFrom;
636
+ function hasExtensions(t) {
637
+ return (t & 1) !== 0;
638
+ }
639
+ ObjectDatagramType2.hasExtensions = hasExtensions;
640
+ function isEndOfGroup(t) {
641
+ return (t & 2) !== 0;
642
+ }
643
+ ObjectDatagramType2.isEndOfGroup = isEndOfGroup;
644
+ function hasObjectId(t) {
645
+ return (t & 4) === 0;
646
+ }
647
+ ObjectDatagramType2.hasObjectId = hasObjectId;
648
+ function fromProperties(hasExtensions2, endOfGroup, objectIdIsZero) {
649
+ let type = 0;
650
+ if (hasExtensions2) type |= 1;
651
+ if (endOfGroup) type |= 2;
652
+ if (objectIdIsZero) type |= 4;
653
+ return type;
654
+ }
655
+ ObjectDatagramType2.fromProperties = fromProperties;
614
656
  })(ObjectDatagramType || (ObjectDatagramType = {}));
615
657
  FetchHeaderType = /* @__PURE__ */ ((FetchHeaderType3) => {
616
658
  FetchHeaderType3[FetchHeaderType3["Type0x05"] = 5] = "Type0x05";
@@ -765,11 +807,12 @@ var init_datagram_object = __esm({
765
807
  init_constant();
766
808
  init_location();
767
809
  DatagramObject = class _DatagramObject {
768
- constructor(type, trackAlias, location, publisherPriority, extensionHeaders, payload) {
810
+ constructor(type, trackAlias, location, publisherPriority, extensionHeaders, payload, endOfGroup) {
769
811
  this.type = type;
770
812
  this.publisherPriority = publisherPriority;
771
813
  this.extensionHeaders = extensionHeaders;
772
814
  this.payload = payload;
815
+ this.endOfGroup = endOfGroup;
773
816
  this.trackAlias = BigInt(trackAlias);
774
817
  this.location = location;
775
818
  }
@@ -781,34 +824,48 @@ var init_datagram_object = __esm({
781
824
  get objectId() {
782
825
  return this.location.object;
783
826
  }
784
- static newWithExtensions(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload) {
827
+ /**
828
+ * Create a new DatagramObject with all properties specified.
829
+ * The type is automatically determined based on extensions, endOfGroup, and objectId.
830
+ */
831
+ static new(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload, endOfGroup = false) {
832
+ const hasExtensions = extensionHeaders !== null && extensionHeaders.length > 0;
833
+ const objectIdIsZero = objectId === 0n;
834
+ const type = ObjectDatagramType.fromProperties(hasExtensions, endOfGroup, objectIdIsZero);
785
835
  return new _DatagramObject(
786
- 1 /* WithExtensions */,
836
+ type,
787
837
  trackAlias,
788
838
  new Location(groupId, objectId),
789
839
  publisherPriority,
790
- extensionHeaders,
791
- payload
840
+ hasExtensions ? extensionHeaders : null,
841
+ payload,
842
+ endOfGroup
792
843
  );
793
844
  }
794
- static newWithoutExtensions(trackAlias, groupId, objectId, publisherPriority, payload) {
795
- return new _DatagramObject(
796
- 0 /* WithoutExtensions */,
797
- trackAlias,
798
- new Location(groupId, objectId),
799
- publisherPriority,
800
- null,
801
- payload
802
- );
845
+ /**
846
+ * Create a DatagramObject with extensions.
847
+ * @deprecated Use DatagramObject.new() instead for Draft-14 compliance.
848
+ */
849
+ static newWithExtensions(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload, endOfGroup = false) {
850
+ return _DatagramObject.new(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload, endOfGroup);
851
+ }
852
+ /**
853
+ * Create a DatagramObject without extensions.
854
+ * @deprecated Use DatagramObject.new() instead for Draft-14 compliance.
855
+ */
856
+ static newWithoutExtensions(trackAlias, groupId, objectId, publisherPriority, payload, endOfGroup = false) {
857
+ return _DatagramObject.new(trackAlias, groupId, objectId, publisherPriority, null, payload, endOfGroup);
803
858
  }
804
859
  serialize() {
805
860
  const buf = new ByteBuffer();
806
861
  buf.putVI(this.type);
807
862
  buf.putVI(this.trackAlias);
808
863
  buf.putVI(this.location.group);
809
- buf.putVI(this.location.object);
864
+ if (ObjectDatagramType.hasObjectId(this.type)) {
865
+ buf.putVI(this.location.object);
866
+ }
810
867
  buf.putU8(this.publisherPriority);
811
- if (this.type === 1 /* WithExtensions */) {
868
+ if (ObjectDatagramType.hasExtensions(this.type)) {
812
869
  const extBuf = new ByteBuffer();
813
870
  if (this.extensionHeaders) {
814
871
  for (const header of this.extensionHeaders) {
@@ -826,28 +883,32 @@ var init_datagram_object = __esm({
826
883
  const msgType = ObjectDatagramType.tryFrom(msgTypeRaw);
827
884
  const trackAlias = buf.getVI();
828
885
  const groupId = buf.getVI();
829
- const objectId = buf.getVI();
886
+ let objectId;
887
+ if (ObjectDatagramType.hasObjectId(msgType)) {
888
+ objectId = buf.getVI();
889
+ } else {
890
+ objectId = 0n;
891
+ }
830
892
  const publisherPriority = buf.getU8();
831
893
  let extensionHeaders = null;
832
- switch (msgType) {
833
- case 1 /* WithExtensions */: {
834
- const extBytes = buf.getLengthPrefixedBytes();
835
- const headerBytes = new FrozenByteBuffer5(extBytes);
836
- extensionHeaders = [];
837
- while (headerBytes.remaining > 0) {
838
- extensionHeaders.push(headerBytes.getKeyValuePair());
839
- }
840
- break;
894
+ if (ObjectDatagramType.hasExtensions(msgType)) {
895
+ const extBytes = buf.getLengthPrefixedBytes();
896
+ const headerBytes = new FrozenByteBuffer5(extBytes);
897
+ extensionHeaders = [];
898
+ while (headerBytes.remaining > 0) {
899
+ extensionHeaders.push(headerBytes.getKeyValuePair());
841
900
  }
842
901
  }
843
902
  const payload = buf.getBytes(buf.remaining);
903
+ const endOfGroup = ObjectDatagramType.isEndOfGroup(msgType);
844
904
  return new _DatagramObject(
845
905
  msgType,
846
906
  trackAlias,
847
907
  new Location(groupId, objectId),
848
908
  publisherPriority,
849
909
  extensionHeaders,
850
- payload
910
+ payload,
911
+ endOfGroup
851
912
  );
852
913
  }
853
914
  };
@@ -879,25 +940,35 @@ var init_datagram_status = __esm({
879
940
  get objectId() {
880
941
  return this.location.object;
881
942
  }
882
- static withExtensions(trackAlias, location, publisherPriority, extensionHeaders, objectStatus) {
943
+ /**
944
+ * Create a new DatagramStatus with all properties specified.
945
+ * The type is automatically determined based on whether extensions are present.
946
+ */
947
+ static new(trackAlias, location, publisherPriority, extensionHeaders, objectStatus) {
948
+ const hasExtensions = extensionHeaders !== null && extensionHeaders.length > 0;
949
+ const type = hasExtensions ? 33 /* WithExtensions */ : 32 /* WithoutExtensions */;
883
950
  return new _DatagramStatus(
884
- 3 /* WithExtensions */,
951
+ type,
885
952
  trackAlias,
886
953
  location,
887
954
  publisherPriority,
888
- extensionHeaders,
955
+ hasExtensions ? extensionHeaders : null,
889
956
  objectStatus
890
957
  );
891
958
  }
959
+ /**
960
+ * Create a DatagramStatus with extensions.
961
+ * @deprecated Use DatagramStatus.new() instead for Draft-14 compliance.
962
+ */
963
+ static withExtensions(trackAlias, location, publisherPriority, extensionHeaders, objectStatus) {
964
+ return _DatagramStatus.new(trackAlias, location, publisherPriority, extensionHeaders, objectStatus);
965
+ }
966
+ /**
967
+ * Create a DatagramStatus without extensions.
968
+ * @deprecated Use DatagramStatus.new() instead for Draft-14 compliance.
969
+ */
892
970
  static newWithoutExtensions(trackAlias, location, publisherPriority, objectStatus) {
893
- return new _DatagramStatus(
894
- 2 /* WithoutExtensions */,
895
- trackAlias,
896
- location,
897
- publisherPriority,
898
- null,
899
- objectStatus
900
- );
971
+ return _DatagramStatus.new(trackAlias, location, publisherPriority, null, objectStatus);
901
972
  }
902
973
  serialize() {
903
974
  const buf = new ByteBuffer();
@@ -906,7 +977,7 @@ var init_datagram_status = __esm({
906
977
  buf.putVI(this.location.group);
907
978
  buf.putVI(this.location.object);
908
979
  buf.putU8(this.publisherPriority);
909
- if (this.type === 3 /* WithExtensions */) {
980
+ if (ObjectDatagramStatusType.hasExtensions(this.type)) {
910
981
  const extBuf = new ByteBuffer();
911
982
  if (this.extensionHeaders) {
912
983
  for (const header of this.extensionHeaders) {
@@ -927,18 +998,14 @@ var init_datagram_status = __esm({
927
998
  const objectId = buf.getVI();
928
999
  const publisherPriority = buf.getU8();
929
1000
  let extensionHeaders = null;
930
- switch (msgType) {
931
- case 3 /* WithExtensions */: {
932
- const extBytes = buf.getLengthPrefixedBytes();
933
- const headerBytes = new FrozenByteBuffer5(extBytes);
934
- extensionHeaders = [];
935
- while (headerBytes.remaining > 0) {
936
- extensionHeaders.push(headerBytes.getKeyValuePair());
937
- }
938
- break;
1001
+ if (ObjectDatagramStatusType.hasExtensions(msgType)) {
1002
+ const extBytes = buf.getLengthPrefixedBytes();
1003
+ const headerBytes = new FrozenByteBuffer5(extBytes);
1004
+ extensionHeaders = [];
1005
+ while (headerBytes.remaining > 0) {
1006
+ extensionHeaders.push(headerBytes.getKeyValuePair());
939
1007
  }
940
1008
  }
941
- console.log("Came here for trying tryFrom with object status");
942
1009
  const objectStatus = ObjectStatus.tryFrom(buf.getVI());
943
1010
  return new _DatagramStatus(
944
1011
  msgType,
@@ -1598,6 +1665,14 @@ var init_object = __esm({
1598
1665
  datagramObject.payload
1599
1666
  );
1600
1667
  }
1668
+ /**
1669
+ * Returns the endOfGroup flag from the source DatagramObject.
1670
+ * This is separate from ObjectStatus.EndOfGroup - the flag indicates
1671
+ * this is the last object in the group even with Normal status.
1672
+ */
1673
+ static isDatagramEndOfGroup(datagramObject) {
1674
+ return datagramObject.endOfGroup;
1675
+ }
1601
1676
  static fromDatagramStatus(datagramStatus, fullTrackName) {
1602
1677
  return new _MoqtObject(
1603
1678
  fullTrackName,
@@ -1634,7 +1709,12 @@ var init_object = __esm({
1634
1709
  subgroupObject.payload
1635
1710
  );
1636
1711
  }
1637
- tryIntoDatagramObject(trackAlias) {
1712
+ /**
1713
+ * Convert to DatagramObject for wire transmission.
1714
+ * @param trackAlias - The track alias to use
1715
+ * @param endOfGroup - Draft-14: Whether this is the last object in the group
1716
+ */
1717
+ tryIntoDatagramObject(trackAlias, endOfGroup = false) {
1638
1718
  if (this.objectForwardingPreference !== "Datagram" /* Datagram */) {
1639
1719
  throw new CastingError(
1640
1720
  "MoqtObject.tryIntoDatagramObject",
@@ -1650,24 +1730,15 @@ var init_object = __esm({
1650
1730
  );
1651
1731
  }
1652
1732
  const alias = BigInt(trackAlias);
1653
- if (this.extensionHeaders && this.extensionHeaders.length > 0) {
1654
- return DatagramObject.newWithExtensions(
1655
- alias,
1656
- this.groupId,
1657
- this.objectId,
1658
- this.publisherPriority,
1659
- this.extensionHeaders,
1660
- this.payload
1661
- );
1662
- } else {
1663
- return DatagramObject.newWithoutExtensions(
1664
- alias,
1665
- this.groupId,
1666
- this.objectId,
1667
- this.publisherPriority,
1668
- this.payload
1669
- );
1670
- }
1733
+ return DatagramObject.new(
1734
+ alias,
1735
+ this.groupId,
1736
+ this.objectId,
1737
+ this.publisherPriority,
1738
+ this.extensionHeaders,
1739
+ this.payload,
1740
+ endOfGroup
1741
+ );
1671
1742
  }
1672
1743
  tryIntoDatagramStatus(trackAlias) {
1673
1744
  if (this.objectForwardingPreference !== "Datagram" /* Datagram */) {
@@ -3329,15 +3400,14 @@ var PublishDone = class _PublishDone {
3329
3400
 
3330
3401
  // src/model/control/publish.ts
3331
3402
  init_byte_buffer();
3332
- init_tuple();
3333
3403
  init_location();
3334
3404
  init_pair();
3335
3405
  init_error();
3406
+ init_data();
3336
3407
  var Publish = class _Publish {
3337
- constructor(requestId, trackNamespace, trackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3408
+ constructor(requestId, fullTrackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3338
3409
  this.requestId = requestId;
3339
- this.trackNamespace = trackNamespace;
3340
- this.trackName = trackName;
3410
+ this.fullTrackName = fullTrackName;
3341
3411
  this.trackAlias = trackAlias;
3342
3412
  this.groupOrder = groupOrder;
3343
3413
  this.contentExists = contentExists;
@@ -3345,11 +3415,10 @@ var Publish = class _Publish {
3345
3415
  this.forward = forward;
3346
3416
  this.parameters = parameters;
3347
3417
  }
3348
- static new(requestId, trackNamespace, trackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3418
+ static new(requestId, fullTrackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3349
3419
  return new _Publish(
3350
3420
  BigInt(requestId),
3351
- trackNamespace,
3352
- trackName,
3421
+ fullTrackName,
3353
3422
  BigInt(trackAlias),
3354
3423
  groupOrder,
3355
3424
  contentExists,
@@ -3366,9 +3435,7 @@ var Publish = class _Publish {
3366
3435
  buf.putVI(29 /* Publish */);
3367
3436
  const payload = new ByteBuffer();
3368
3437
  payload.putVI(this.requestId);
3369
- payload.putTuple(this.trackNamespace);
3370
- payload.putVI(this.trackName.length);
3371
- payload.putBytes(new TextEncoder().encode(this.trackName));
3438
+ payload.putBytes(this.fullTrackName.serialize().toUint8Array());
3372
3439
  payload.putVI(this.trackAlias);
3373
3440
  payload.putU8(this.groupOrder);
3374
3441
  payload.putU8(this.contentExists);
@@ -3390,10 +3457,7 @@ var Publish = class _Publish {
3390
3457
  }
3391
3458
  static parsePayload(buf) {
3392
3459
  const requestId = buf.getVI();
3393
- const trackNamespace = buf.getTuple();
3394
- const trackNameLength = buf.getVI();
3395
- const trackNameBytes = buf.getBytes(Number(trackNameLength));
3396
- const trackName = new TextDecoder().decode(trackNameBytes);
3460
+ const fullTrackName = buf.getFullTrackName();
3397
3461
  const trackAlias = buf.getVI();
3398
3462
  const groupOrder = buf.getU8();
3399
3463
  const contentExists = buf.getU8();
@@ -3409,8 +3473,7 @@ var Publish = class _Publish {
3409
3473
  }
3410
3474
  return new _Publish(
3411
3475
  requestId,
3412
- trackNamespace,
3413
- trackName,
3476
+ fullTrackName,
3414
3477
  trackAlias,
3415
3478
  groupOrder,
3416
3479
  contentExists,
@@ -5227,6 +5290,70 @@ var SubscribeRequest = class {
5227
5290
  }
5228
5291
  };
5229
5292
 
5293
+ // src/client/request/subscribe_namespace.ts
5294
+ var SubscribeNamespaceRequest = class {
5295
+ requestId;
5296
+ message;
5297
+ _resolve;
5298
+ _reject;
5299
+ promise;
5300
+ constructor(msg) {
5301
+ this.requestId = msg.requestId;
5302
+ this.message = msg;
5303
+ this.promise = new Promise((resolve, reject) => {
5304
+ this._resolve = resolve;
5305
+ this._reject = reject;
5306
+ });
5307
+ }
5308
+ resolve(value) {
5309
+ this._resolve(value);
5310
+ }
5311
+ reject(reason) {
5312
+ this._reject(reason);
5313
+ }
5314
+ then(onfulfilled, onrejected) {
5315
+ return this.promise.then(onfulfilled, onrejected);
5316
+ }
5317
+ catch(onrejected) {
5318
+ return this.promise.catch(onrejected);
5319
+ }
5320
+ finally(onfinally) {
5321
+ return this.promise.finally(onfinally);
5322
+ }
5323
+ };
5324
+
5325
+ // src/client/request/publish.ts
5326
+ var PublishRequest = class {
5327
+ requestId;
5328
+ message;
5329
+ _resolve;
5330
+ _reject;
5331
+ promise;
5332
+ constructor(msg) {
5333
+ this.requestId = msg.requestId;
5334
+ this.message = msg;
5335
+ this.promise = new Promise((resolve, reject) => {
5336
+ this._resolve = resolve;
5337
+ this._reject = reject;
5338
+ });
5339
+ }
5340
+ resolve(value) {
5341
+ this._resolve(value);
5342
+ }
5343
+ reject(reason) {
5344
+ this._reject(reason);
5345
+ }
5346
+ then(onfulfilled, onrejected) {
5347
+ return this.promise.then(onfulfilled, onrejected);
5348
+ }
5349
+ catch(onrejected) {
5350
+ return this.promise.catch(onrejected);
5351
+ }
5352
+ finally(onfinally) {
5353
+ return this.promise.finally(onfinally);
5354
+ }
5355
+ };
5356
+
5230
5357
  // src/client/handler/publish_namespace.ts
5231
5358
  var handlerPublishNamespace = async (client, msg) => {
5232
5359
  if (client.onNamespacePublished) {
@@ -5763,7 +5890,12 @@ var handlerSubscribe = async (client, msg) => {
5763
5890
  };
5764
5891
 
5765
5892
  // src/client/handler/subscribe_namespace.ts
5766
- var handlerSubscribeNamespace = async (_client, _msg) => {
5893
+ var handlerSubscribeNamespace = async (client, msg) => {
5894
+ if (client.onPeerSubscribeNamespace) {
5895
+ client.onPeerSubscribeNamespace(msg);
5896
+ }
5897
+ const okMsg = new SubscribeNamespaceOk(msg.requestId);
5898
+ await client.controlStream.send(okMsg);
5767
5899
  };
5768
5900
 
5769
5901
  // src/client/handler/subscribe_namespace_error.ts
@@ -5849,8 +5981,229 @@ var handlerUnsubscribe = async (client, msg) => {
5849
5981
  var handlerUnsubscribeNamespace = async (_client, _msg) => {
5850
5982
  };
5851
5983
 
5984
+ // src/client/handler/publish.ts
5985
+ var handlerPublish = async (client, msg) => {
5986
+ let streamController;
5987
+ const stream = new ReadableStream({
5988
+ start(c) {
5989
+ streamController = c;
5990
+ }
5991
+ });
5992
+ const localPseudoRequestId = client.allocatePseudoRequestId();
5993
+ client.requestIdMap.addMapping(localPseudoRequestId, msg.fullTrackName);
5994
+ client.subscriptionAliasMap.set(localPseudoRequestId, msg.trackAlias);
5995
+ client.aliasFullTrackNameMap.set(msg.trackAlias, msg.fullTrackName);
5996
+ const receiver = {
5997
+ requestId: localPseudoRequestId,
5998
+ streamsAccepted: 0,
5999
+ largestLocation: void 0,
6000
+ controller: streamController
6001
+ };
6002
+ client.subscriptions.set(msg.trackAlias, receiver);
6003
+ if (client.onPeerPublish) {
6004
+ client.onPeerPublish(msg, stream);
6005
+ }
6006
+ const publishOk = new PublishOk(
6007
+ msg.requestId,
6008
+ 1,
6009
+ 255,
6010
+ 1 /* Ascending */,
6011
+ 2 /* LatestObject */,
6012
+ void 0,
6013
+ void 0,
6014
+ []
6015
+ );
6016
+ await client.controlStream.send(publishOk);
6017
+ };
6018
+
6019
+ // src/client/publication/publish.ts
6020
+ init_subgroup_header();
6021
+ var PublishPublication = class {
6022
+ /**
6023
+ * Creates a new PublishPublication instance.
6024
+ * @param client - The MOQT client managing the connection.
6025
+ * @param track - The track being proactively published.
6026
+ * @param publishMsg - The publish message that initiated this session.
6027
+ */
6028
+ constructor(client, track, publishMsg) {
6029
+ this.client = client;
6030
+ this.track = track;
6031
+ this.publishMsg = publishMsg;
6032
+ this.#trackAlias = track.trackAlias;
6033
+ this.#publisherPriority = track.publisherPriority;
6034
+ this.publishToRelay();
6035
+ }
6036
+ /**
6037
+ * The latest location that was published to the relay.
6038
+ */
6039
+ latestLocation;
6040
+ /**
6041
+ * The alias for the track being published.
6042
+ */
6043
+ #trackAlias;
6044
+ /**
6045
+ * The priority of the publisher.
6046
+ */
6047
+ #publisherPriority;
6048
+ /**
6049
+ * The number of streams opened for this publication.
6050
+ */
6051
+ #streamsOpened = 0n;
6052
+ /**
6053
+ * Function to cancel publishing, if set.
6054
+ */
6055
+ #cancelPublishing;
6056
+ /**
6057
+ * Whether publishing is completed/cancelled.
6058
+ */
6059
+ #isCompleted = false;
6060
+ /**
6061
+ * Lock for synchronizing stream operations.
6062
+ */
6063
+ #lock = new SimpleLock();
6064
+ /**
6065
+ * Map of group IDs to their corresponding send streams.
6066
+ */
6067
+ #streams = /* @__PURE__ */ new Map();
6068
+ /**
6069
+ * Unique identifier for this publication instance.
6070
+ */
6071
+ #id = Math.floor(Math.random() * 1e6);
6072
+ /**
6073
+ * Calculates the stream priority based on publisher priority.
6074
+ * (Since this is a proactive push, there is no subscriber priority to average with).
6075
+ */
6076
+ get #streamPriority() {
6077
+ return getTransportPriority(this.#publisherPriority);
6078
+ }
6079
+ /**
6080
+ * Cancels the publication and cleans up resources.
6081
+ * Removes the publication from the client's publication map.
6082
+ */
6083
+ cancel() {
6084
+ if (this.#cancelPublishing) {
6085
+ this.#cancelPublishing();
6086
+ this.client.publications.delete(this.publishMsg.requestId);
6087
+ }
6088
+ this.#isCompleted = true;
6089
+ this.#lock.acquire().then(() => {
6090
+ for (const [groupId, stream] of this.#streams.entries()) {
6091
+ stream.close().catch((e) => console.warn(`Failed to close stream for group ${groupId}:`, e));
6092
+ }
6093
+ this.#streams.clear();
6094
+ this.#lock.release();
6095
+ });
6096
+ }
6097
+ /**
6098
+ * Publishes MOQT objects to the relay as they become available.
6099
+ * Handles stream creation, object writing, and stream closure.
6100
+ * @throws :{@link InternalError} If the track does not support live content.
6101
+ */
6102
+ async publishToRelay() {
6103
+ if (!this.track.trackSource.live)
6104
+ throw new InternalError("PublishPublication.publishToRelay", "Track does not support live content");
6105
+ this.track.trackSource.live.onDone(() => {
6106
+ this.cancel();
6107
+ });
6108
+ this.#cancelPublishing = this.track.trackSource.live.onNewObject(async (obj) => {
6109
+ if (this.#isCompleted) return;
6110
+ try {
6111
+ if (!this.#streams.has(obj.location.group)) {
6112
+ await this.#lock.acquire();
6113
+ if (!this.#streams.has(obj.location.group)) {
6114
+ const writeStream = await this.client.webTransport.createUnidirectionalStream({
6115
+ sendOrder: this.#streamPriority
6116
+ });
6117
+ let subgroupId;
6118
+ if (SubgroupHeaderType.hasExplicitSubgroupId(obj.getSubgroupHeaderType(true))) subgroupId = obj.subgroupId;
6119
+ const header = new SubgroupHeader(
6120
+ obj.getSubgroupHeaderType(true),
6121
+ this.#trackAlias,
6122
+ obj.location.group,
6123
+ subgroupId,
6124
+ this.#publisherPriority
6125
+ );
6126
+ const sendStream2 = await SendStream.new(writeStream, header);
6127
+ this.#streams.set(obj.location.group, sendStream2);
6128
+ this.#streamsOpened++;
6129
+ }
6130
+ await this.#lock.release();
6131
+ }
6132
+ const sendStream = this.#streams.get(obj.location.group);
6133
+ await this.#lock.acquire();
6134
+ await sendStream.write(obj.tryIntoSubgroupObject());
6135
+ await this.#lock.release();
6136
+ if (this.latestLocation && this.latestLocation.group !== obj.location.group) {
6137
+ const prevGroup = this.latestLocation.group;
6138
+ try {
6139
+ await this.#lock.acquire();
6140
+ const prevStream = this.#streams.get(prevGroup);
6141
+ if (prevStream) {
6142
+ try {
6143
+ await prevStream.close();
6144
+ } catch (err) {
6145
+ console.warn("error in closing stream", prevGroup, err);
6146
+ }
6147
+ this.#streams.delete(prevGroup);
6148
+ }
6149
+ await this.#lock.release();
6150
+ } catch (err) {
6151
+ console.warn(
6152
+ "error in closing stream: id, latestLocation.group, err",
6153
+ this.#id,
6154
+ this.latestLocation.group,
6155
+ err
6156
+ );
6157
+ }
6158
+ }
6159
+ await this.#lock.acquire();
6160
+ this.latestLocation = obj.location;
6161
+ await this.#lock.release();
6162
+ } catch (err) {
6163
+ this.cancel();
6164
+ throw err;
6165
+ }
6166
+ });
6167
+ }
6168
+ };
6169
+
6170
+ // src/client/handler/publish_ok.ts
6171
+ var handlerPublishOk = async (client, msg) => {
6172
+ const request = client.requests.get(msg.requestId);
6173
+ if (request instanceof PublishRequest) {
6174
+ request.resolve(msg);
6175
+ const fullTrackName = client.requestIdMap.getNameByRequestId(msg.requestId);
6176
+ if (!fullTrackName) {
6177
+ console.warn(`[MOQtail] No track mapped for PublishOk requestId: ${msg.requestId}`);
6178
+ return;
6179
+ }
6180
+ const track = client.trackSources.get(fullTrackName.toString());
6181
+ if (!track || !track.trackSource.live) {
6182
+ console.warn(`[MOQtail] Live track source not found for ${fullTrackName.toString()}`);
6183
+ return;
6184
+ }
6185
+ const publication = new PublishPublication(client, track, request.message);
6186
+ client.publications.set(msg.requestId, publication);
6187
+ } else {
6188
+ throw new ProtocolViolationError("handlerPublishOk", "No publish request was found with the given request id");
6189
+ }
6190
+ };
6191
+
6192
+ // src/client/handler/publish_error.ts
6193
+ var handlerPublishError = async (client, msg) => {
6194
+ const request = client.requests.get(msg.requestId);
6195
+ if (request instanceof PublishRequest) {
6196
+ request.resolve(msg);
6197
+ } else {
6198
+ throw new ProtocolViolationError("handlerPublishError", "No publish request was found with the given request id");
6199
+ }
6200
+ };
6201
+
5852
6202
  // src/client/handler/handler.ts
5853
6203
  function getHandlerForControlMessage(msg) {
6204
+ if (msg instanceof Publish) return handlerPublish;
6205
+ if (msg instanceof PublishOk) return handlerPublishOk;
6206
+ if (msg instanceof PublishError) return handlerPublishError;
5854
6207
  if (msg instanceof PublishDone) return handlerPublishDone;
5855
6208
  if (msg instanceof PublishNamespace) return handlerPublishNamespace;
5856
6209
  if (msg instanceof PublishNamespaceCancel) return handlerPublishNamespaceCancel;
@@ -6004,7 +6357,7 @@ var RecvDatagramStream = class _RecvDatagramStream {
6004
6357
  }
6005
6358
  try {
6006
6359
  const firstByte = datagramBytes[0];
6007
- const isStatus = firstByte === 2 || firstByte === 3;
6360
+ const isStatus = firstByte === 32 || firstByte === 33;
6008
6361
  let moqtObject;
6009
6362
  if (isStatus) {
6010
6363
  const datagramStatus = DatagramStatus.deserialize(
@@ -6180,6 +6533,10 @@ var MOQtailClient = class _MOQtailClient {
6180
6533
  onDatagramReceived;
6181
6534
  /** Invoked after enqueuing each outbound datagram object/status. */
6182
6535
  onDatagramSent;
6536
+ /** Fired when an inbound PUBLISH control message is received. */
6537
+ onPeerPublish;
6538
+ /** Fired when an inbound SUBSCRIBE_NAMESPACE control message is received. */
6539
+ onPeerSubscribeNamespace;
6183
6540
  /** Datagram writer for sending datagrams. */
6184
6541
  #datagramWriter;
6185
6542
  /** Datagram reader for receiving datagrams. */
@@ -6207,6 +6564,12 @@ var MOQtailClient = class _MOQtailClient {
6207
6564
  this.#dontUseRequestId += 2n;
6208
6565
  return id;
6209
6566
  }
6567
+ /**
6568
+ * Generates a safe, sequential local request ID for tracking pushed/incoming tracks.
6569
+ */
6570
+ allocatePseudoRequestId() {
6571
+ return this.#nextClientRequestId;
6572
+ }
6210
6573
  /**
6211
6574
  * Gets the current server setup configuration.
6212
6575
  *
@@ -6486,7 +6849,7 @@ var MOQtailClient = class _MOQtailClient {
6486
6849
  }
6487
6850
  const firstByte = datagramBytes[0];
6488
6851
  try {
6489
- const isStatus = firstByte === 2 || firstByte === 3;
6852
+ const isStatus = firstByte === 32 || firstByte === 33;
6490
6853
  let moqtObject;
6491
6854
  let trackAlias;
6492
6855
  if (isStatus) {
@@ -7212,6 +7575,73 @@ var MOQtailClient = class _MOQtailClient {
7212
7575
  throw error;
7213
7576
  }
7214
7577
  }
7578
+ /**
7579
+ * Proactively push a track to the relay/peer.
7580
+ */
7581
+ async publish(fullTrackName, forward, trackAlias, parameters) {
7582
+ this.#ensureActive();
7583
+ try {
7584
+ const params = parameters ? parameters.build() : new VersionSpecificParameters().build();
7585
+ const requestId = this.#nextClientRequestId;
7586
+ const msg = new Publish(
7587
+ requestId,
7588
+ fullTrackName,
7589
+ trackAlias,
7590
+ 1 /* Ascending */,
7591
+ 0,
7592
+ // ContentExists (0 = Unknown/No)
7593
+ void 0,
7594
+ // Largest Location
7595
+ forward ? 1 : 0,
7596
+ params
7597
+ );
7598
+ const request = new PublishRequest(msg);
7599
+ this.requests.set(msg.requestId, request);
7600
+ this.requestIdMap.addMapping(msg.requestId, fullTrackName);
7601
+ this.subscriptionAliasMap.set(msg.requestId, trackAlias);
7602
+ await this.controlStream.send(msg);
7603
+ const response = await request;
7604
+ if (response instanceof PublishError) {
7605
+ this.requests.delete(msg.requestId);
7606
+ this.requestIdMap.removeMappingByRequestId(msg.requestId);
7607
+ this.subscriptionAliasMap.delete(msg.requestId);
7608
+ return response;
7609
+ } else {
7610
+ return { requestId: msg.requestId, trackAlias };
7611
+ }
7612
+ } catch (error) {
7613
+ await this.disconnect(
7614
+ new InternalError("MOQtailClient.publish", error instanceof Error ? error.message : String(error))
7615
+ );
7616
+ throw error;
7617
+ }
7618
+ }
7619
+ /**
7620
+ * Registers an incoming PUBLISH announcement as a valid data receiver.
7621
+ * This prepares the client to ingest pushed data streams matching the published alias.
7622
+ * * @param msg - The incoming Publish control message
7623
+ * @returns - A stream of MoqtObjects being pushed by the publisher
7624
+ */
7625
+ acceptPushedTrack(msg) {
7626
+ this.#ensureActive();
7627
+ let streamController;
7628
+ const stream = new ReadableStream({
7629
+ start(c) {
7630
+ streamController = c;
7631
+ }
7632
+ });
7633
+ this.requestIdMap.addMapping(msg.requestId, msg.fullTrackName);
7634
+ this.subscriptionAliasMap.set(msg.requestId, msg.trackAlias);
7635
+ this.aliasFullTrackNameMap.set(msg.trackAlias, msg.fullTrackName);
7636
+ const receiver = {
7637
+ requestId: msg.requestId,
7638
+ streamsAccepted: 0,
7639
+ largestLocation: void 0,
7640
+ controller: streamController
7641
+ };
7642
+ this.subscriptions.set(msg.trackAlias, receiver);
7643
+ return stream;
7644
+ }
7215
7645
  // TODO: Each announced track should checked against ongoing subscribe_namespace
7216
7646
  // If matches it should send an announce to that peer automatically
7217
7647
  /**
@@ -7360,10 +7790,20 @@ var MOQtailClient = class _MOQtailClient {
7360
7790
  }
7361
7791
  }
7362
7792
  // INFO: Subscriber calls this the get matching announce messages with this prefix
7363
- async subscribeNamespace(msg) {
7793
+ async subscribeNamespace(trackNamespacePrefix, parameters) {
7364
7794
  this.#ensureActive();
7365
7795
  try {
7366
- await this.controlStream.send(msg);
7796
+ const params = parameters ? parameters.build() : new VersionSpecificParameters().build();
7797
+ const msg = new SubscribeNamespace(this.#nextClientRequestId, trackNamespacePrefix, params);
7798
+ const request = new SubscribeNamespaceRequest(msg);
7799
+ this.requests.set(msg.requestId, request);
7800
+ this.controlStream.send(msg);
7801
+ const response = await request;
7802
+ if (response instanceof SubscribeNamespaceOk) {
7803
+ this.subscribedAnnounces.add(msg.trackNamespacePrefix);
7804
+ }
7805
+ this.requests.delete(msg.requestId);
7806
+ return response;
7367
7807
  } catch (error) {
7368
7808
  await this.disconnect(
7369
7809
  new InternalError("MOQtailClient.subscribeNamespace", error instanceof Error ? error.message : String(error))
@@ -7516,8 +7956,9 @@ var MOQtailClient = class _MOQtailClient {
7516
7956
  subgroupId = header.subgroupId;
7517
7957
  }
7518
7958
  const fullTrackName = this.aliasFullTrackNameMap.get(header.trackAlias);
7519
- if (!fullTrackName)
7959
+ if (!fullTrackName) {
7520
7960
  throw new ProtocolViolationError("MOQtailClient", "No full track name for received track alias");
7961
+ }
7521
7962
  const moqtObject = MoqtObject.fromSubgroupObject(
7522
7963
  nextObject,
7523
7964
  header.groupId,
@@ -7732,36 +8173,4 @@ var RingBufferObjectCache = class {
7732
8173
  }
7733
8174
  };
7734
8175
 
7735
- // src/client/request/subscribe_namespace.ts
7736
- var SubscribeNamespaceRequest = class {
7737
- requestId;
7738
- message;
7739
- _resolve;
7740
- _reject;
7741
- promise;
7742
- constructor(requestId, message) {
7743
- this.requestId = requestId;
7744
- this.message = message;
7745
- this.promise = new Promise((resolve, reject) => {
7746
- this._resolve = resolve;
7747
- this._reject = reject;
7748
- });
7749
- }
7750
- resolve(value) {
7751
- this._resolve(value);
7752
- }
7753
- reject(reason) {
7754
- this._reject(reason);
7755
- }
7756
- then(onfulfilled, onrejected) {
7757
- return this.promise.then(onfulfilled, onrejected);
7758
- }
7759
- catch(onrejected) {
7760
- return this.promise.catch(onrejected);
7761
- }
7762
- finally(onfinally) {
7763
- return this.promise.finally(onfinally);
7764
- }
7765
- };
7766
-
7767
- export { ControlStream, FetchPublication, FetchRequest, HybridTrackSource, LiveTrackSource, MOQtailClient, MemoryObjectCache, PublishNamespaceRequest, RecvDatagramStream, RecvStream, RingBufferObjectCache, SendDatagramStream, SendStream, StaticTrackSource, SubscribeNamespaceRequest, SubscribePublication, SubscribeRequest };
8176
+ export { ControlStream, FetchPublication, FetchRequest, HybridTrackSource, LiveTrackSource, MOQtailClient, MemoryObjectCache, PublishNamespaceRequest, PublishPublication, PublishRequest, RecvDatagramStream, RecvStream, RingBufferObjectCache, SendDatagramStream, SendStream, StaticTrackSource, SubscribeNamespaceRequest, SubscribePublication, SubscribeRequest };