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.
package/dist/index.cjs CHANGED
@@ -583,27 +583,37 @@ exports.ObjectDatagramStatusType = void 0; exports.ObjectDatagramType = void 0;
583
583
  var init_constant = __esm({
584
584
  "src/model/data/constant.ts"() {
585
585
  exports.ObjectDatagramStatusType = /* @__PURE__ */ ((ObjectDatagramStatusType2) => {
586
- ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithoutExtensions"] = 2] = "WithoutExtensions";
587
- ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithExtensions"] = 3] = "WithExtensions";
586
+ ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithoutExtensions"] = 32] = "WithoutExtensions";
587
+ ObjectDatagramStatusType2[ObjectDatagramStatusType2["WithExtensions"] = 33] = "WithExtensions";
588
588
  return ObjectDatagramStatusType2;
589
589
  })(exports.ObjectDatagramStatusType || {});
590
590
  ((ObjectDatagramStatusType2) => {
591
591
  function tryFrom(value) {
592
592
  const v = typeof value === "bigint" ? Number(value) : value;
593
593
  switch (v) {
594
- case 2:
595
- return 2 /* WithoutExtensions */;
596
- case 3:
597
- return 3 /* WithExtensions */;
594
+ case 32:
595
+ return 32 /* WithoutExtensions */;
596
+ case 33:
597
+ return 33 /* WithExtensions */;
598
598
  default:
599
599
  throw new Error(`Invalid ObjectDatagramStatusType: ${value}`);
600
600
  }
601
601
  }
602
602
  ObjectDatagramStatusType2.tryFrom = tryFrom;
603
+ function hasExtensions(t) {
604
+ return t === 33 /* WithExtensions */;
605
+ }
606
+ ObjectDatagramStatusType2.hasExtensions = hasExtensions;
603
607
  })(exports.ObjectDatagramStatusType || (exports.ObjectDatagramStatusType = {}));
604
608
  exports.ObjectDatagramType = /* @__PURE__ */ ((ObjectDatagramType2) => {
605
- ObjectDatagramType2[ObjectDatagramType2["WithoutExtensions"] = 0] = "WithoutExtensions";
606
- ObjectDatagramType2[ObjectDatagramType2["WithExtensions"] = 1] = "WithExtensions";
609
+ ObjectDatagramType2[ObjectDatagramType2["Type0x00"] = 0] = "Type0x00";
610
+ ObjectDatagramType2[ObjectDatagramType2["Type0x01"] = 1] = "Type0x01";
611
+ ObjectDatagramType2[ObjectDatagramType2["Type0x02"] = 2] = "Type0x02";
612
+ ObjectDatagramType2[ObjectDatagramType2["Type0x03"] = 3] = "Type0x03";
613
+ ObjectDatagramType2[ObjectDatagramType2["Type0x04"] = 4] = "Type0x04";
614
+ ObjectDatagramType2[ObjectDatagramType2["Type0x05"] = 5] = "Type0x05";
615
+ ObjectDatagramType2[ObjectDatagramType2["Type0x06"] = 6] = "Type0x06";
616
+ ObjectDatagramType2[ObjectDatagramType2["Type0x07"] = 7] = "Type0x07";
607
617
  return ObjectDatagramType2;
608
618
  })(exports.ObjectDatagramType || {});
609
619
  ((ObjectDatagramType2) => {
@@ -611,14 +621,46 @@ var init_constant = __esm({
611
621
  const v = typeof value === "bigint" ? Number(value) : value;
612
622
  switch (v) {
613
623
  case 0:
614
- return 0 /* WithoutExtensions */;
624
+ return 0 /* Type0x00 */;
615
625
  case 1:
616
- return 1 /* WithExtensions */;
626
+ return 1 /* Type0x01 */;
627
+ case 2:
628
+ return 2 /* Type0x02 */;
629
+ case 3:
630
+ return 3 /* Type0x03 */;
631
+ case 4:
632
+ return 4 /* Type0x04 */;
633
+ case 5:
634
+ return 5 /* Type0x05 */;
635
+ case 6:
636
+ return 6 /* Type0x06 */;
637
+ case 7:
638
+ return 7 /* Type0x07 */;
617
639
  default:
618
640
  throw new Error(`Invalid ObjectDatagramType: ${value}`);
619
641
  }
620
642
  }
621
643
  ObjectDatagramType2.tryFrom = tryFrom;
644
+ function hasExtensions(t) {
645
+ return (t & 1) !== 0;
646
+ }
647
+ ObjectDatagramType2.hasExtensions = hasExtensions;
648
+ function isEndOfGroup(t) {
649
+ return (t & 2) !== 0;
650
+ }
651
+ ObjectDatagramType2.isEndOfGroup = isEndOfGroup;
652
+ function hasObjectId(t) {
653
+ return (t & 4) === 0;
654
+ }
655
+ ObjectDatagramType2.hasObjectId = hasObjectId;
656
+ function fromProperties(hasExtensions2, endOfGroup, objectIdIsZero) {
657
+ let type = 0;
658
+ if (hasExtensions2) type |= 1;
659
+ if (endOfGroup) type |= 2;
660
+ if (objectIdIsZero) type |= 4;
661
+ return type;
662
+ }
663
+ ObjectDatagramType2.fromProperties = fromProperties;
622
664
  })(exports.ObjectDatagramType || (exports.ObjectDatagramType = {}));
623
665
  exports.FetchHeaderType = /* @__PURE__ */ ((FetchHeaderType3) => {
624
666
  FetchHeaderType3[FetchHeaderType3["Type0x05"] = 5] = "Type0x05";
@@ -773,11 +815,12 @@ var init_datagram_object = __esm({
773
815
  init_constant();
774
816
  init_location();
775
817
  exports.DatagramObject = class _DatagramObject {
776
- constructor(type, trackAlias, location, publisherPriority, extensionHeaders, payload) {
818
+ constructor(type, trackAlias, location, publisherPriority, extensionHeaders, payload, endOfGroup) {
777
819
  this.type = type;
778
820
  this.publisherPriority = publisherPriority;
779
821
  this.extensionHeaders = extensionHeaders;
780
822
  this.payload = payload;
823
+ this.endOfGroup = endOfGroup;
781
824
  this.trackAlias = BigInt(trackAlias);
782
825
  this.location = location;
783
826
  }
@@ -789,34 +832,48 @@ var init_datagram_object = __esm({
789
832
  get objectId() {
790
833
  return this.location.object;
791
834
  }
792
- static newWithExtensions(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload) {
835
+ /**
836
+ * Create a new DatagramObject with all properties specified.
837
+ * The type is automatically determined based on extensions, endOfGroup, and objectId.
838
+ */
839
+ static new(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload, endOfGroup = false) {
840
+ const hasExtensions = extensionHeaders !== null && extensionHeaders.length > 0;
841
+ const objectIdIsZero = objectId === 0n;
842
+ const type = exports.ObjectDatagramType.fromProperties(hasExtensions, endOfGroup, objectIdIsZero);
793
843
  return new _DatagramObject(
794
- 1 /* WithExtensions */,
844
+ type,
795
845
  trackAlias,
796
846
  new exports.Location(groupId, objectId),
797
847
  publisherPriority,
798
- extensionHeaders,
799
- payload
848
+ hasExtensions ? extensionHeaders : null,
849
+ payload,
850
+ endOfGroup
800
851
  );
801
852
  }
802
- static newWithoutExtensions(trackAlias, groupId, objectId, publisherPriority, payload) {
803
- return new _DatagramObject(
804
- 0 /* WithoutExtensions */,
805
- trackAlias,
806
- new exports.Location(groupId, objectId),
807
- publisherPriority,
808
- null,
809
- payload
810
- );
853
+ /**
854
+ * Create a DatagramObject with extensions.
855
+ * @deprecated Use DatagramObject.new() instead for Draft-14 compliance.
856
+ */
857
+ static newWithExtensions(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload, endOfGroup = false) {
858
+ return _DatagramObject.new(trackAlias, groupId, objectId, publisherPriority, extensionHeaders, payload, endOfGroup);
859
+ }
860
+ /**
861
+ * Create a DatagramObject without extensions.
862
+ * @deprecated Use DatagramObject.new() instead for Draft-14 compliance.
863
+ */
864
+ static newWithoutExtensions(trackAlias, groupId, objectId, publisherPriority, payload, endOfGroup = false) {
865
+ return _DatagramObject.new(trackAlias, groupId, objectId, publisherPriority, null, payload, endOfGroup);
811
866
  }
812
867
  serialize() {
813
868
  const buf = new exports.ByteBuffer();
814
869
  buf.putVI(this.type);
815
870
  buf.putVI(this.trackAlias);
816
871
  buf.putVI(this.location.group);
817
- buf.putVI(this.location.object);
872
+ if (exports.ObjectDatagramType.hasObjectId(this.type)) {
873
+ buf.putVI(this.location.object);
874
+ }
818
875
  buf.putU8(this.publisherPriority);
819
- if (this.type === 1 /* WithExtensions */) {
876
+ if (exports.ObjectDatagramType.hasExtensions(this.type)) {
820
877
  const extBuf = new exports.ByteBuffer();
821
878
  if (this.extensionHeaders) {
822
879
  for (const header of this.extensionHeaders) {
@@ -834,28 +891,32 @@ var init_datagram_object = __esm({
834
891
  const msgType = exports.ObjectDatagramType.tryFrom(msgTypeRaw);
835
892
  const trackAlias = buf.getVI();
836
893
  const groupId = buf.getVI();
837
- const objectId = buf.getVI();
894
+ let objectId;
895
+ if (exports.ObjectDatagramType.hasObjectId(msgType)) {
896
+ objectId = buf.getVI();
897
+ } else {
898
+ objectId = 0n;
899
+ }
838
900
  const publisherPriority = buf.getU8();
839
901
  let extensionHeaders = null;
840
- switch (msgType) {
841
- case 1 /* WithExtensions */: {
842
- const extBytes = buf.getLengthPrefixedBytes();
843
- const headerBytes = new exports.FrozenByteBuffer(extBytes);
844
- extensionHeaders = [];
845
- while (headerBytes.remaining > 0) {
846
- extensionHeaders.push(headerBytes.getKeyValuePair());
847
- }
848
- break;
902
+ if (exports.ObjectDatagramType.hasExtensions(msgType)) {
903
+ const extBytes = buf.getLengthPrefixedBytes();
904
+ const headerBytes = new exports.FrozenByteBuffer(extBytes);
905
+ extensionHeaders = [];
906
+ while (headerBytes.remaining > 0) {
907
+ extensionHeaders.push(headerBytes.getKeyValuePair());
849
908
  }
850
909
  }
851
910
  const payload = buf.getBytes(buf.remaining);
911
+ const endOfGroup = exports.ObjectDatagramType.isEndOfGroup(msgType);
852
912
  return new _DatagramObject(
853
913
  msgType,
854
914
  trackAlias,
855
915
  new exports.Location(groupId, objectId),
856
916
  publisherPriority,
857
917
  extensionHeaders,
858
- payload
918
+ payload,
919
+ endOfGroup
859
920
  );
860
921
  }
861
922
  };
@@ -887,25 +948,35 @@ var init_datagram_status = __esm({
887
948
  get objectId() {
888
949
  return this.location.object;
889
950
  }
890
- static withExtensions(trackAlias, location, publisherPriority, extensionHeaders, objectStatus) {
951
+ /**
952
+ * Create a new DatagramStatus with all properties specified.
953
+ * The type is automatically determined based on whether extensions are present.
954
+ */
955
+ static new(trackAlias, location, publisherPriority, extensionHeaders, objectStatus) {
956
+ const hasExtensions = extensionHeaders !== null && extensionHeaders.length > 0;
957
+ const type = hasExtensions ? 33 /* WithExtensions */ : 32 /* WithoutExtensions */;
891
958
  return new _DatagramStatus(
892
- 3 /* WithExtensions */,
959
+ type,
893
960
  trackAlias,
894
961
  location,
895
962
  publisherPriority,
896
- extensionHeaders,
963
+ hasExtensions ? extensionHeaders : null,
897
964
  objectStatus
898
965
  );
899
966
  }
967
+ /**
968
+ * Create a DatagramStatus with extensions.
969
+ * @deprecated Use DatagramStatus.new() instead for Draft-14 compliance.
970
+ */
971
+ static withExtensions(trackAlias, location, publisherPriority, extensionHeaders, objectStatus) {
972
+ return _DatagramStatus.new(trackAlias, location, publisherPriority, extensionHeaders, objectStatus);
973
+ }
974
+ /**
975
+ * Create a DatagramStatus without extensions.
976
+ * @deprecated Use DatagramStatus.new() instead for Draft-14 compliance.
977
+ */
900
978
  static newWithoutExtensions(trackAlias, location, publisherPriority, objectStatus) {
901
- return new _DatagramStatus(
902
- 2 /* WithoutExtensions */,
903
- trackAlias,
904
- location,
905
- publisherPriority,
906
- null,
907
- objectStatus
908
- );
979
+ return _DatagramStatus.new(trackAlias, location, publisherPriority, null, objectStatus);
909
980
  }
910
981
  serialize() {
911
982
  const buf = new exports.ByteBuffer();
@@ -914,7 +985,7 @@ var init_datagram_status = __esm({
914
985
  buf.putVI(this.location.group);
915
986
  buf.putVI(this.location.object);
916
987
  buf.putU8(this.publisherPriority);
917
- if (this.type === 3 /* WithExtensions */) {
988
+ if (exports.ObjectDatagramStatusType.hasExtensions(this.type)) {
918
989
  const extBuf = new exports.ByteBuffer();
919
990
  if (this.extensionHeaders) {
920
991
  for (const header of this.extensionHeaders) {
@@ -935,18 +1006,14 @@ var init_datagram_status = __esm({
935
1006
  const objectId = buf.getVI();
936
1007
  const publisherPriority = buf.getU8();
937
1008
  let extensionHeaders = null;
938
- switch (msgType) {
939
- case 3 /* WithExtensions */: {
940
- const extBytes = buf.getLengthPrefixedBytes();
941
- const headerBytes = new exports.FrozenByteBuffer(extBytes);
942
- extensionHeaders = [];
943
- while (headerBytes.remaining > 0) {
944
- extensionHeaders.push(headerBytes.getKeyValuePair());
945
- }
946
- break;
1009
+ if (exports.ObjectDatagramStatusType.hasExtensions(msgType)) {
1010
+ const extBytes = buf.getLengthPrefixedBytes();
1011
+ const headerBytes = new exports.FrozenByteBuffer(extBytes);
1012
+ extensionHeaders = [];
1013
+ while (headerBytes.remaining > 0) {
1014
+ extensionHeaders.push(headerBytes.getKeyValuePair());
947
1015
  }
948
1016
  }
949
- console.log("Came here for trying tryFrom with object status");
950
1017
  const objectStatus = exports.ObjectStatus.tryFrom(buf.getVI());
951
1018
  return new _DatagramStatus(
952
1019
  msgType,
@@ -1662,6 +1729,14 @@ var init_object = __esm({
1662
1729
  datagramObject.payload
1663
1730
  );
1664
1731
  }
1732
+ /**
1733
+ * Returns the endOfGroup flag from the source DatagramObject.
1734
+ * This is separate from ObjectStatus.EndOfGroup - the flag indicates
1735
+ * this is the last object in the group even with Normal status.
1736
+ */
1737
+ static isDatagramEndOfGroup(datagramObject) {
1738
+ return datagramObject.endOfGroup;
1739
+ }
1665
1740
  static fromDatagramStatus(datagramStatus, fullTrackName) {
1666
1741
  return new _MoqtObject(
1667
1742
  fullTrackName,
@@ -1698,7 +1773,12 @@ var init_object = __esm({
1698
1773
  subgroupObject.payload
1699
1774
  );
1700
1775
  }
1701
- tryIntoDatagramObject(trackAlias) {
1776
+ /**
1777
+ * Convert to DatagramObject for wire transmission.
1778
+ * @param trackAlias - The track alias to use
1779
+ * @param endOfGroup - Draft-14: Whether this is the last object in the group
1780
+ */
1781
+ tryIntoDatagramObject(trackAlias, endOfGroup = false) {
1702
1782
  if (this.objectForwardingPreference !== "Datagram" /* Datagram */) {
1703
1783
  throw new exports.CastingError(
1704
1784
  "MoqtObject.tryIntoDatagramObject",
@@ -1714,24 +1794,15 @@ var init_object = __esm({
1714
1794
  );
1715
1795
  }
1716
1796
  const alias = BigInt(trackAlias);
1717
- if (this.extensionHeaders && this.extensionHeaders.length > 0) {
1718
- return exports.DatagramObject.newWithExtensions(
1719
- alias,
1720
- this.groupId,
1721
- this.objectId,
1722
- this.publisherPriority,
1723
- this.extensionHeaders,
1724
- this.payload
1725
- );
1726
- } else {
1727
- return exports.DatagramObject.newWithoutExtensions(
1728
- alias,
1729
- this.groupId,
1730
- this.objectId,
1731
- this.publisherPriority,
1732
- this.payload
1733
- );
1734
- }
1797
+ return exports.DatagramObject.new(
1798
+ alias,
1799
+ this.groupId,
1800
+ this.objectId,
1801
+ this.publisherPriority,
1802
+ this.extensionHeaders,
1803
+ this.payload,
1804
+ endOfGroup
1805
+ );
1735
1806
  }
1736
1807
  tryIntoDatagramStatus(trackAlias) {
1737
1808
  if (this.objectForwardingPreference !== "Datagram" /* Datagram */) {
@@ -2534,11 +2605,11 @@ function fetchTypeFromBigInt(v) {
2534
2605
  throw new exports.CastingError("fetchTypeFromBigInt", "bigint", "FetchType", `Invalid FetchType:${v}`);
2535
2606
  }
2536
2607
  }
2537
- var GroupOrder = /* @__PURE__ */ ((GroupOrder7) => {
2538
- GroupOrder7[GroupOrder7["Original"] = 0] = "Original";
2539
- GroupOrder7[GroupOrder7["Ascending"] = 1] = "Ascending";
2540
- GroupOrder7[GroupOrder7["Descending"] = 2] = "Descending";
2541
- return GroupOrder7;
2608
+ var GroupOrder = /* @__PURE__ */ ((GroupOrder6) => {
2609
+ GroupOrder6[GroupOrder6["Original"] = 0] = "Original";
2610
+ GroupOrder6[GroupOrder6["Ascending"] = 1] = "Ascending";
2611
+ GroupOrder6[GroupOrder6["Descending"] = 2] = "Descending";
2612
+ return GroupOrder6;
2542
2613
  })(GroupOrder || {});
2543
2614
  function groupOrderFromNumber(v) {
2544
2615
  switch (v) {
@@ -3544,15 +3615,14 @@ var PublishDone = class _PublishDone {
3544
3615
 
3545
3616
  // src/model/control/publish.ts
3546
3617
  init_byte_buffer();
3547
- init_tuple();
3548
3618
  init_location();
3549
3619
  init_pair();
3550
3620
  init_error();
3621
+ init_data();
3551
3622
  var Publish = class _Publish {
3552
- constructor(requestId, trackNamespace, trackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3623
+ constructor(requestId, fullTrackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3553
3624
  this.requestId = requestId;
3554
- this.trackNamespace = trackNamespace;
3555
- this.trackName = trackName;
3625
+ this.fullTrackName = fullTrackName;
3556
3626
  this.trackAlias = trackAlias;
3557
3627
  this.groupOrder = groupOrder;
3558
3628
  this.contentExists = contentExists;
@@ -3560,11 +3630,10 @@ var Publish = class _Publish {
3560
3630
  this.forward = forward;
3561
3631
  this.parameters = parameters;
3562
3632
  }
3563
- static new(requestId, trackNamespace, trackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3633
+ static new(requestId, fullTrackName, trackAlias, groupOrder, contentExists, largestLocation, forward, parameters) {
3564
3634
  return new _Publish(
3565
3635
  BigInt(requestId),
3566
- trackNamespace,
3567
- trackName,
3636
+ fullTrackName,
3568
3637
  BigInt(trackAlias),
3569
3638
  groupOrder,
3570
3639
  contentExists,
@@ -3581,9 +3650,7 @@ var Publish = class _Publish {
3581
3650
  buf.putVI(29 /* Publish */);
3582
3651
  const payload = new exports.ByteBuffer();
3583
3652
  payload.putVI(this.requestId);
3584
- payload.putTuple(this.trackNamespace);
3585
- payload.putVI(this.trackName.length);
3586
- payload.putBytes(new TextEncoder().encode(this.trackName));
3653
+ payload.putBytes(this.fullTrackName.serialize().toUint8Array());
3587
3654
  payload.putVI(this.trackAlias);
3588
3655
  payload.putU8(this.groupOrder);
3589
3656
  payload.putU8(this.contentExists);
@@ -3605,10 +3672,7 @@ var Publish = class _Publish {
3605
3672
  }
3606
3673
  static parsePayload(buf) {
3607
3674
  const requestId = buf.getVI();
3608
- const trackNamespace = buf.getTuple();
3609
- const trackNameLength = buf.getVI();
3610
- const trackNameBytes = buf.getBytes(Number(trackNameLength));
3611
- const trackName = new TextDecoder().decode(trackNameBytes);
3675
+ const fullTrackName = buf.getFullTrackName();
3612
3676
  const trackAlias = buf.getVI();
3613
3677
  const groupOrder = buf.getU8();
3614
3678
  const contentExists = buf.getU8();
@@ -3624,8 +3688,7 @@ var Publish = class _Publish {
3624
3688
  }
3625
3689
  return new _Publish(
3626
3690
  requestId,
3627
- trackNamespace,
3628
- trackName,
3691
+ fullTrackName,
3629
3692
  trackAlias,
3630
3693
  groupOrder,
3631
3694
  contentExists,
@@ -5497,6 +5560,70 @@ var SubscribeRequest = class {
5497
5560
  }
5498
5561
  };
5499
5562
 
5563
+ // src/client/request/subscribe_namespace.ts
5564
+ var SubscribeNamespaceRequest = class {
5565
+ requestId;
5566
+ message;
5567
+ _resolve;
5568
+ _reject;
5569
+ promise;
5570
+ constructor(msg) {
5571
+ this.requestId = msg.requestId;
5572
+ this.message = msg;
5573
+ this.promise = new Promise((resolve, reject) => {
5574
+ this._resolve = resolve;
5575
+ this._reject = reject;
5576
+ });
5577
+ }
5578
+ resolve(value) {
5579
+ this._resolve(value);
5580
+ }
5581
+ reject(reason) {
5582
+ this._reject(reason);
5583
+ }
5584
+ then(onfulfilled, onrejected) {
5585
+ return this.promise.then(onfulfilled, onrejected);
5586
+ }
5587
+ catch(onrejected) {
5588
+ return this.promise.catch(onrejected);
5589
+ }
5590
+ finally(onfinally) {
5591
+ return this.promise.finally(onfinally);
5592
+ }
5593
+ };
5594
+
5595
+ // src/client/request/publish.ts
5596
+ var PublishRequest = class {
5597
+ requestId;
5598
+ message;
5599
+ _resolve;
5600
+ _reject;
5601
+ promise;
5602
+ constructor(msg) {
5603
+ this.requestId = msg.requestId;
5604
+ this.message = msg;
5605
+ this.promise = new Promise((resolve, reject) => {
5606
+ this._resolve = resolve;
5607
+ this._reject = reject;
5608
+ });
5609
+ }
5610
+ resolve(value) {
5611
+ this._resolve(value);
5612
+ }
5613
+ reject(reason) {
5614
+ this._reject(reason);
5615
+ }
5616
+ then(onfulfilled, onrejected) {
5617
+ return this.promise.then(onfulfilled, onrejected);
5618
+ }
5619
+ catch(onrejected) {
5620
+ return this.promise.catch(onrejected);
5621
+ }
5622
+ finally(onfinally) {
5623
+ return this.promise.finally(onfinally);
5624
+ }
5625
+ };
5626
+
5500
5627
  // src/client/handler/publish_namespace.ts
5501
5628
  var handlerPublishNamespace = async (client, msg) => {
5502
5629
  if (client.onNamespacePublished) {
@@ -6033,7 +6160,12 @@ var handlerSubscribe = async (client, msg) => {
6033
6160
  };
6034
6161
 
6035
6162
  // src/client/handler/subscribe_namespace.ts
6036
- var handlerSubscribeNamespace = async (_client, _msg) => {
6163
+ var handlerSubscribeNamespace = async (client, msg) => {
6164
+ if (client.onPeerSubscribeNamespace) {
6165
+ client.onPeerSubscribeNamespace(msg);
6166
+ }
6167
+ const okMsg = new SubscribeNamespaceOk(msg.requestId);
6168
+ await client.controlStream.send(okMsg);
6037
6169
  };
6038
6170
 
6039
6171
  // src/client/handler/subscribe_namespace_error.ts
@@ -6119,8 +6251,229 @@ var handlerUnsubscribe = async (client, msg) => {
6119
6251
  var handlerUnsubscribeNamespace = async (_client, _msg) => {
6120
6252
  };
6121
6253
 
6254
+ // src/client/handler/publish.ts
6255
+ var handlerPublish = async (client, msg) => {
6256
+ let streamController;
6257
+ const stream = new ReadableStream({
6258
+ start(c) {
6259
+ streamController = c;
6260
+ }
6261
+ });
6262
+ const localPseudoRequestId = client.allocatePseudoRequestId();
6263
+ client.requestIdMap.addMapping(localPseudoRequestId, msg.fullTrackName);
6264
+ client.subscriptionAliasMap.set(localPseudoRequestId, msg.trackAlias);
6265
+ client.aliasFullTrackNameMap.set(msg.trackAlias, msg.fullTrackName);
6266
+ const receiver = {
6267
+ requestId: localPseudoRequestId,
6268
+ streamsAccepted: 0,
6269
+ largestLocation: void 0,
6270
+ controller: streamController
6271
+ };
6272
+ client.subscriptions.set(msg.trackAlias, receiver);
6273
+ if (client.onPeerPublish) {
6274
+ client.onPeerPublish(msg, stream);
6275
+ }
6276
+ const publishOk = new PublishOk(
6277
+ msg.requestId,
6278
+ 1,
6279
+ 255,
6280
+ 1 /* Ascending */,
6281
+ 2 /* LatestObject */,
6282
+ void 0,
6283
+ void 0,
6284
+ []
6285
+ );
6286
+ await client.controlStream.send(publishOk);
6287
+ };
6288
+
6289
+ // src/client/publication/publish.ts
6290
+ init_subgroup_header();
6291
+ var PublishPublication = class {
6292
+ /**
6293
+ * Creates a new PublishPublication instance.
6294
+ * @param client - The MOQT client managing the connection.
6295
+ * @param track - The track being proactively published.
6296
+ * @param publishMsg - The publish message that initiated this session.
6297
+ */
6298
+ constructor(client, track, publishMsg) {
6299
+ this.client = client;
6300
+ this.track = track;
6301
+ this.publishMsg = publishMsg;
6302
+ this.#trackAlias = track.trackAlias;
6303
+ this.#publisherPriority = track.publisherPriority;
6304
+ this.publishToRelay();
6305
+ }
6306
+ /**
6307
+ * The latest location that was published to the relay.
6308
+ */
6309
+ latestLocation;
6310
+ /**
6311
+ * The alias for the track being published.
6312
+ */
6313
+ #trackAlias;
6314
+ /**
6315
+ * The priority of the publisher.
6316
+ */
6317
+ #publisherPriority;
6318
+ /**
6319
+ * The number of streams opened for this publication.
6320
+ */
6321
+ #streamsOpened = 0n;
6322
+ /**
6323
+ * Function to cancel publishing, if set.
6324
+ */
6325
+ #cancelPublishing;
6326
+ /**
6327
+ * Whether publishing is completed/cancelled.
6328
+ */
6329
+ #isCompleted = false;
6330
+ /**
6331
+ * Lock for synchronizing stream operations.
6332
+ */
6333
+ #lock = new SimpleLock();
6334
+ /**
6335
+ * Map of group IDs to their corresponding send streams.
6336
+ */
6337
+ #streams = /* @__PURE__ */ new Map();
6338
+ /**
6339
+ * Unique identifier for this publication instance.
6340
+ */
6341
+ #id = Math.floor(Math.random() * 1e6);
6342
+ /**
6343
+ * Calculates the stream priority based on publisher priority.
6344
+ * (Since this is a proactive push, there is no subscriber priority to average with).
6345
+ */
6346
+ get #streamPriority() {
6347
+ return getTransportPriority(this.#publisherPriority);
6348
+ }
6349
+ /**
6350
+ * Cancels the publication and cleans up resources.
6351
+ * Removes the publication from the client's publication map.
6352
+ */
6353
+ cancel() {
6354
+ if (this.#cancelPublishing) {
6355
+ this.#cancelPublishing();
6356
+ this.client.publications.delete(this.publishMsg.requestId);
6357
+ }
6358
+ this.#isCompleted = true;
6359
+ this.#lock.acquire().then(() => {
6360
+ for (const [groupId, stream] of this.#streams.entries()) {
6361
+ stream.close().catch((e) => console.warn(`Failed to close stream for group ${groupId}:`, e));
6362
+ }
6363
+ this.#streams.clear();
6364
+ this.#lock.release();
6365
+ });
6366
+ }
6367
+ /**
6368
+ * Publishes MOQT objects to the relay as they become available.
6369
+ * Handles stream creation, object writing, and stream closure.
6370
+ * @throws :{@link InternalError} If the track does not support live content.
6371
+ */
6372
+ async publishToRelay() {
6373
+ if (!this.track.trackSource.live)
6374
+ throw new exports.InternalError("PublishPublication.publishToRelay", "Track does not support live content");
6375
+ this.track.trackSource.live.onDone(() => {
6376
+ this.cancel();
6377
+ });
6378
+ this.#cancelPublishing = this.track.trackSource.live.onNewObject(async (obj) => {
6379
+ if (this.#isCompleted) return;
6380
+ try {
6381
+ if (!this.#streams.has(obj.location.group)) {
6382
+ await this.#lock.acquire();
6383
+ if (!this.#streams.has(obj.location.group)) {
6384
+ const writeStream = await this.client.webTransport.createUnidirectionalStream({
6385
+ sendOrder: this.#streamPriority
6386
+ });
6387
+ let subgroupId;
6388
+ if (exports.SubgroupHeaderType.hasExplicitSubgroupId(obj.getSubgroupHeaderType(true))) subgroupId = obj.subgroupId;
6389
+ const header = new exports.SubgroupHeader(
6390
+ obj.getSubgroupHeaderType(true),
6391
+ this.#trackAlias,
6392
+ obj.location.group,
6393
+ subgroupId,
6394
+ this.#publisherPriority
6395
+ );
6396
+ const sendStream2 = await SendStream.new(writeStream, header);
6397
+ this.#streams.set(obj.location.group, sendStream2);
6398
+ this.#streamsOpened++;
6399
+ }
6400
+ await this.#lock.release();
6401
+ }
6402
+ const sendStream = this.#streams.get(obj.location.group);
6403
+ await this.#lock.acquire();
6404
+ await sendStream.write(obj.tryIntoSubgroupObject());
6405
+ await this.#lock.release();
6406
+ if (this.latestLocation && this.latestLocation.group !== obj.location.group) {
6407
+ const prevGroup = this.latestLocation.group;
6408
+ try {
6409
+ await this.#lock.acquire();
6410
+ const prevStream = this.#streams.get(prevGroup);
6411
+ if (prevStream) {
6412
+ try {
6413
+ await prevStream.close();
6414
+ } catch (err) {
6415
+ console.warn("error in closing stream", prevGroup, err);
6416
+ }
6417
+ this.#streams.delete(prevGroup);
6418
+ }
6419
+ await this.#lock.release();
6420
+ } catch (err) {
6421
+ console.warn(
6422
+ "error in closing stream: id, latestLocation.group, err",
6423
+ this.#id,
6424
+ this.latestLocation.group,
6425
+ err
6426
+ );
6427
+ }
6428
+ }
6429
+ await this.#lock.acquire();
6430
+ this.latestLocation = obj.location;
6431
+ await this.#lock.release();
6432
+ } catch (err) {
6433
+ this.cancel();
6434
+ throw err;
6435
+ }
6436
+ });
6437
+ }
6438
+ };
6439
+
6440
+ // src/client/handler/publish_ok.ts
6441
+ var handlerPublishOk = async (client, msg) => {
6442
+ const request = client.requests.get(msg.requestId);
6443
+ if (request instanceof PublishRequest) {
6444
+ request.resolve(msg);
6445
+ const fullTrackName = client.requestIdMap.getNameByRequestId(msg.requestId);
6446
+ if (!fullTrackName) {
6447
+ console.warn(`[MOQtail] No track mapped for PublishOk requestId: ${msg.requestId}`);
6448
+ return;
6449
+ }
6450
+ const track = client.trackSources.get(fullTrackName.toString());
6451
+ if (!track || !track.trackSource.live) {
6452
+ console.warn(`[MOQtail] Live track source not found for ${fullTrackName.toString()}`);
6453
+ return;
6454
+ }
6455
+ const publication = new PublishPublication(client, track, request.message);
6456
+ client.publications.set(msg.requestId, publication);
6457
+ } else {
6458
+ throw new exports.ProtocolViolationError("handlerPublishOk", "No publish request was found with the given request id");
6459
+ }
6460
+ };
6461
+
6462
+ // src/client/handler/publish_error.ts
6463
+ var handlerPublishError = async (client, msg) => {
6464
+ const request = client.requests.get(msg.requestId);
6465
+ if (request instanceof PublishRequest) {
6466
+ request.resolve(msg);
6467
+ } else {
6468
+ throw new exports.ProtocolViolationError("handlerPublishError", "No publish request was found with the given request id");
6469
+ }
6470
+ };
6471
+
6122
6472
  // src/client/handler/handler.ts
6123
6473
  function getHandlerForControlMessage(msg) {
6474
+ if (msg instanceof Publish) return handlerPublish;
6475
+ if (msg instanceof PublishOk) return handlerPublishOk;
6476
+ if (msg instanceof PublishError) return handlerPublishError;
6124
6477
  if (msg instanceof PublishDone) return handlerPublishDone;
6125
6478
  if (msg instanceof PublishNamespace) return handlerPublishNamespace;
6126
6479
  if (msg instanceof PublishNamespaceCancel) return handlerPublishNamespaceCancel;
@@ -6274,7 +6627,7 @@ var RecvDatagramStream = class _RecvDatagramStream {
6274
6627
  }
6275
6628
  try {
6276
6629
  const firstByte = datagramBytes[0];
6277
- const isStatus = firstByte === 2 || firstByte === 3;
6630
+ const isStatus = firstByte === 32 || firstByte === 33;
6278
6631
  let moqtObject;
6279
6632
  if (isStatus) {
6280
6633
  const datagramStatus = exports.DatagramStatus.deserialize(
@@ -6450,6 +6803,10 @@ var MOQtailClient = class _MOQtailClient {
6450
6803
  onDatagramReceived;
6451
6804
  /** Invoked after enqueuing each outbound datagram object/status. */
6452
6805
  onDatagramSent;
6806
+ /** Fired when an inbound PUBLISH control message is received. */
6807
+ onPeerPublish;
6808
+ /** Fired when an inbound SUBSCRIBE_NAMESPACE control message is received. */
6809
+ onPeerSubscribeNamespace;
6453
6810
  /** Datagram writer for sending datagrams. */
6454
6811
  #datagramWriter;
6455
6812
  /** Datagram reader for receiving datagrams. */
@@ -6477,6 +6834,12 @@ var MOQtailClient = class _MOQtailClient {
6477
6834
  this.#dontUseRequestId += 2n;
6478
6835
  return id;
6479
6836
  }
6837
+ /**
6838
+ * Generates a safe, sequential local request ID for tracking pushed/incoming tracks.
6839
+ */
6840
+ allocatePseudoRequestId() {
6841
+ return this.#nextClientRequestId;
6842
+ }
6480
6843
  /**
6481
6844
  * Gets the current server setup configuration.
6482
6845
  *
@@ -6756,7 +7119,7 @@ var MOQtailClient = class _MOQtailClient {
6756
7119
  }
6757
7120
  const firstByte = datagramBytes[0];
6758
7121
  try {
6759
- const isStatus = firstByte === 2 || firstByte === 3;
7122
+ const isStatus = firstByte === 32 || firstByte === 33;
6760
7123
  let moqtObject;
6761
7124
  let trackAlias;
6762
7125
  if (isStatus) {
@@ -7482,6 +7845,73 @@ var MOQtailClient = class _MOQtailClient {
7482
7845
  throw error;
7483
7846
  }
7484
7847
  }
7848
+ /**
7849
+ * Proactively push a track to the relay/peer.
7850
+ */
7851
+ async publish(fullTrackName, forward, trackAlias, parameters) {
7852
+ this.#ensureActive();
7853
+ try {
7854
+ const params = parameters ? parameters.build() : new VersionSpecificParameters().build();
7855
+ const requestId = this.#nextClientRequestId;
7856
+ const msg = new Publish(
7857
+ requestId,
7858
+ fullTrackName,
7859
+ trackAlias,
7860
+ 1 /* Ascending */,
7861
+ 0,
7862
+ // ContentExists (0 = Unknown/No)
7863
+ void 0,
7864
+ // Largest Location
7865
+ forward ? 1 : 0,
7866
+ params
7867
+ );
7868
+ const request = new PublishRequest(msg);
7869
+ this.requests.set(msg.requestId, request);
7870
+ this.requestIdMap.addMapping(msg.requestId, fullTrackName);
7871
+ this.subscriptionAliasMap.set(msg.requestId, trackAlias);
7872
+ await this.controlStream.send(msg);
7873
+ const response = await request;
7874
+ if (response instanceof PublishError) {
7875
+ this.requests.delete(msg.requestId);
7876
+ this.requestIdMap.removeMappingByRequestId(msg.requestId);
7877
+ this.subscriptionAliasMap.delete(msg.requestId);
7878
+ return response;
7879
+ } else {
7880
+ return { requestId: msg.requestId, trackAlias };
7881
+ }
7882
+ } catch (error) {
7883
+ await this.disconnect(
7884
+ new exports.InternalError("MOQtailClient.publish", error instanceof Error ? error.message : String(error))
7885
+ );
7886
+ throw error;
7887
+ }
7888
+ }
7889
+ /**
7890
+ * Registers an incoming PUBLISH announcement as a valid data receiver.
7891
+ * This prepares the client to ingest pushed data streams matching the published alias.
7892
+ * * @param msg - The incoming Publish control message
7893
+ * @returns - A stream of MoqtObjects being pushed by the publisher
7894
+ */
7895
+ acceptPushedTrack(msg) {
7896
+ this.#ensureActive();
7897
+ let streamController;
7898
+ const stream = new ReadableStream({
7899
+ start(c) {
7900
+ streamController = c;
7901
+ }
7902
+ });
7903
+ this.requestIdMap.addMapping(msg.requestId, msg.fullTrackName);
7904
+ this.subscriptionAliasMap.set(msg.requestId, msg.trackAlias);
7905
+ this.aliasFullTrackNameMap.set(msg.trackAlias, msg.fullTrackName);
7906
+ const receiver = {
7907
+ requestId: msg.requestId,
7908
+ streamsAccepted: 0,
7909
+ largestLocation: void 0,
7910
+ controller: streamController
7911
+ };
7912
+ this.subscriptions.set(msg.trackAlias, receiver);
7913
+ return stream;
7914
+ }
7485
7915
  // TODO: Each announced track should checked against ongoing subscribe_namespace
7486
7916
  // If matches it should send an announce to that peer automatically
7487
7917
  /**
@@ -7630,10 +8060,20 @@ var MOQtailClient = class _MOQtailClient {
7630
8060
  }
7631
8061
  }
7632
8062
  // INFO: Subscriber calls this the get matching announce messages with this prefix
7633
- async subscribeNamespace(msg) {
8063
+ async subscribeNamespace(trackNamespacePrefix, parameters) {
7634
8064
  this.#ensureActive();
7635
8065
  try {
7636
- await this.controlStream.send(msg);
8066
+ const params = parameters ? parameters.build() : new VersionSpecificParameters().build();
8067
+ const msg = new SubscribeNamespace(this.#nextClientRequestId, trackNamespacePrefix, params);
8068
+ const request = new SubscribeNamespaceRequest(msg);
8069
+ this.requests.set(msg.requestId, request);
8070
+ this.controlStream.send(msg);
8071
+ const response = await request;
8072
+ if (response instanceof SubscribeNamespaceOk) {
8073
+ this.subscribedAnnounces.add(msg.trackNamespacePrefix);
8074
+ }
8075
+ this.requests.delete(msg.requestId);
8076
+ return response;
7637
8077
  } catch (error) {
7638
8078
  await this.disconnect(
7639
8079
  new exports.InternalError("MOQtailClient.subscribeNamespace", error instanceof Error ? error.message : String(error))
@@ -7786,8 +8226,9 @@ var MOQtailClient = class _MOQtailClient {
7786
8226
  subgroupId = header.subgroupId;
7787
8227
  }
7788
8228
  const fullTrackName = this.aliasFullTrackNameMap.get(header.trackAlias);
7789
- if (!fullTrackName)
8229
+ if (!fullTrackName) {
7790
8230
  throw new exports.ProtocolViolationError("MOQtailClient", "No full track name for received track alias");
8231
+ }
7791
8232
  const moqtObject = exports.MoqtObject.fromSubgroupObject(
7792
8233
  nextObject,
7793
8234
  header.groupId,
@@ -8002,38 +8443,6 @@ var RingBufferObjectCache = class {
8002
8443
  }
8003
8444
  };
8004
8445
 
8005
- // src/client/request/subscribe_namespace.ts
8006
- var SubscribeNamespaceRequest = class {
8007
- requestId;
8008
- message;
8009
- _resolve;
8010
- _reject;
8011
- promise;
8012
- constructor(requestId, message) {
8013
- this.requestId = requestId;
8014
- this.message = message;
8015
- this.promise = new Promise((resolve, reject) => {
8016
- this._resolve = resolve;
8017
- this._reject = reject;
8018
- });
8019
- }
8020
- resolve(value) {
8021
- this._resolve(value);
8022
- }
8023
- reject(reason) {
8024
- this._reject(reason);
8025
- }
8026
- then(onfulfilled, onrejected) {
8027
- return this.promise.then(onfulfilled, onrejected);
8028
- }
8029
- catch(onrejected) {
8030
- return this.promise.catch(onrejected);
8031
- }
8032
- finally(onfinally) {
8033
- return this.promise.finally(onfinally);
8034
- }
8035
- };
8036
-
8037
8446
  // src/util/telemetry.ts
8038
8447
  var NetworkTelemetry = class {
8039
8448
  events = [];
@@ -8426,43 +8835,6 @@ var ClockNormalizer = class _ClockNormalizer {
8426
8835
  }
8427
8836
  };
8428
8837
 
8429
- // src/util/get_akamai_offset.ts
8430
- var AkamaiOffset = class _AkamaiOffset {
8431
- static _offset = null;
8432
- static _promise = null;
8433
- static async getClockSkew() {
8434
- if (_AkamaiOffset._offset !== null) {
8435
- return _AkamaiOffset._offset;
8436
- }
8437
- if (_AkamaiOffset._promise) {
8438
- return _AkamaiOffset._promise;
8439
- }
8440
- _AkamaiOffset._promise = _AkamaiOffset.ClockSkew().then((offset2) => {
8441
- _AkamaiOffset._offset = offset2;
8442
- return offset2;
8443
- });
8444
- const offset = await _AkamaiOffset._promise;
8445
- return Math.round(offset);
8446
- }
8447
- static async ClockSkew() {
8448
- const akamaiUrl = "https://time.akamai.com?ms";
8449
- performance.clearResourceTimings();
8450
- const response = await fetch(akamaiUrl);
8451
- const text = await response.text();
8452
- const TR = parseFloat(text.trim()) * 1e3;
8453
- const entry = performance.getEntriesByType("resource").find((e) => e.name.includes("time.akamai.com"));
8454
- if (!entry) {
8455
- console.warn("No resource entry found for Akamai time request");
8456
- return 0;
8457
- }
8458
- const T0 = entry.fetchStart + performance.timeOrigin;
8459
- const T1 = entry.responseStart + performance.timeOrigin;
8460
- const offset = (T0 + T1) / 2 - TR;
8461
- return offset;
8462
- }
8463
- };
8464
-
8465
- exports.AkamaiOffset = AkamaiOffset;
8466
8838
  exports.AuthorizationToken = AuthorizationToken;
8467
8839
  exports.ClientSetup = ClientSetup;
8468
8840
  exports.ClockNormalizer = ClockNormalizer;
@@ -8506,6 +8878,8 @@ exports.PublishNamespaceErrorCode = PublishNamespaceErrorCode;
8506
8878
  exports.PublishNamespaceOk = PublishNamespaceOk;
8507
8879
  exports.PublishNamespaceRequest = PublishNamespaceRequest;
8508
8880
  exports.PublishOk = PublishOk;
8881
+ exports.PublishPublication = PublishPublication;
8882
+ exports.PublishRequest = PublishRequest;
8509
8883
  exports.PullPlayoutBuffer = PullPlayoutBuffer;
8510
8884
  exports.RecvDatagramStream = RecvDatagramStream;
8511
8885
  exports.RecvStream = RecvStream;