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