werift 0.24.3 → 0.24.4

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/lib/index.mjs CHANGED
@@ -517,7 +517,7 @@ var Event2 = class {
517
517
  };
518
518
  allUnsubscribe = () => {
519
519
  if (this.ended) {
520
- throw new Error("event completed");
520
+ return;
521
521
  }
522
522
  this.event = {
523
523
  stack: [],
@@ -7928,6 +7928,12 @@ var UDP_TRANSPORT = 285212672;
7928
7928
  function isStreamTransport(transport) {
7929
7929
  return transport.type === "tcp" || transport.type === "tls";
7930
7930
  }
7931
+ function permissionKey(addr) {
7932
+ return addr[0];
7933
+ }
7934
+ function channelKey(addr) {
7935
+ return JSON.stringify(addr);
7936
+ }
7931
7937
  var StunOverTurnProtocol = class _StunOverTurnProtocol {
7932
7938
  constructor(turn) {
7933
7939
  this.turn = turn;
@@ -8030,11 +8036,24 @@ var TurnProtocol = class _TurnProtocol {
8030
8036
  addrByChannel = {};
8031
8037
  /**sec */
8032
8038
  channelRefreshTime;
8033
- channelBinding;
8034
- channelRefreshAt = 0;
8039
+ /**
8040
+ * Serializes ChannelBind requests so allocation-wide auth state
8041
+ * (nonce/realm/integrityKey) is not updated concurrently. Rejections
8042
+ * must not poison this tail — see channelBindQueue assignment sites.
8043
+ */
8044
+ channelBindQueue = Promise.resolve();
8045
+ /** In-flight ChannelBind per peer transport address (dedupe concurrent). */
8046
+ channelBindingByAddr = /* @__PURE__ */ new Map();
8035
8047
  tcpBuffer = Buffer.alloc(0);
8048
+ /** Permission cache keyed by peer IP only (RFC 8656). */
8036
8049
  permissionByAddr = {};
8037
- creatingPermission = Promise.resolve();
8050
+ /**
8051
+ * Serializes CreatePermission requests (auth state race avoidance).
8052
+ * Rejections must not poison this tail.
8053
+ */
8054
+ permissionQueue = Promise.resolve();
8055
+ /** In-flight CreatePermission per peer IP (dedupe concurrent). */
8056
+ creatingPermissionByAddr = /* @__PURE__ */ new Map();
8038
8057
  async connectionMade() {
8039
8058
  this.transport.onData = (data, addr) => {
8040
8059
  this.dataReceived(data, addr);
@@ -8119,10 +8138,7 @@ var TurnProtocol = class _TurnProtocol {
8119
8138
  async createPermission(peerAddress) {
8120
8139
  const request = new Message(8 /* CREATE_PERMISSION */, 0 /* REQUEST */);
8121
8140
  request.setAttribute("XOR-PEER-ADDRESS", peerAddress).setAttribute("USERNAME", this.username).setAttribute("REALM", this.realm).setAttribute("NONCE", this.nonce);
8122
- await this.request(request, this.server).catch((e) => {
8123
- request;
8124
- throw e;
8125
- });
8141
+ await this.requestWithRetry(request, this.server);
8126
8142
  }
8127
8143
  refresh = (exp) => {
8128
8144
  this.refreshHandle = cancelable(async (_, __, onCancel) => {
@@ -8202,10 +8218,13 @@ var TurnProtocol = class _TurnProtocol {
8202
8218
  return [message, address];
8203
8219
  }
8204
8220
  async sendData(data, addr) {
8205
- const channel = await this.getChannel(addr).catch((e) => {
8206
- return new Error("channelBind error");
8207
- });
8208
- if (channel instanceof Error) {
8221
+ let channel;
8222
+ try {
8223
+ channel = await this.getChannel(addr);
8224
+ } catch (e) {
8225
+ log21("channelBind error; falling back to Send Indication", e);
8226
+ }
8227
+ if (!channel) {
8209
8228
  await this.getPermission(addr);
8210
8229
  const indicate = new Message(6 /* SEND */, 16 /* INDICATION */).setAttribute("DATA", data).setAttribute("XOR-PEER-ADDRESS", addr);
8211
8230
  await this.sendStun(indicate, this.server);
@@ -8213,49 +8232,111 @@ var TurnProtocol = class _TurnProtocol {
8213
8232
  }
8214
8233
  await this.send(encodeChannelData(channel.number, data), this.server);
8215
8234
  }
8235
+ /**
8236
+ * Ensure a CreatePermission exists for the peer IP.
8237
+ * Peer failures are isolated: a rejection for peer A does not poison peer B.
8238
+ */
8216
8239
  async getPermission(addr) {
8217
- await this.creatingPermission;
8218
- const permitted = this.permissionByAddr[addr.join(":")];
8219
- if (!permitted) {
8220
- this.creatingPermission = this.createPermission(addr);
8221
- this.permissionByAddr[addr.join(":")] = true;
8222
- await this.creatingPermission.catch((e) => {
8223
- log21("createPermission error", e);
8224
- throw e;
8225
- });
8240
+ const key = permissionKey(addr);
8241
+ if (this.permissionByAddr[key]) {
8242
+ return;
8243
+ }
8244
+ const existing = this.creatingPermissionByAddr.get(key);
8245
+ if (existing) {
8246
+ return existing;
8247
+ }
8248
+ const operation = this.permissionQueue.then(async () => {
8249
+ if (this.permissionByAddr[key]) {
8250
+ return;
8251
+ }
8252
+ await this.createPermission(addr);
8253
+ this.permissionByAddr[key] = true;
8254
+ });
8255
+ this.permissionQueue = operation.then(
8256
+ () => void 0,
8257
+ () => void 0
8258
+ );
8259
+ this.creatingPermissionByAddr.set(key, operation);
8260
+ try {
8261
+ await operation;
8262
+ } catch (error) {
8263
+ log21("createPermission error", error);
8264
+ throw error;
8265
+ } finally {
8266
+ if (this.creatingPermissionByAddr.get(key) === operation) {
8267
+ this.creatingPermissionByAddr.delete(key);
8268
+ }
8226
8269
  }
8227
8270
  }
8271
+ /**
8272
+ * Ensure a ChannelBind exists for the peer transport address.
8273
+ * Peer failures are isolated; concurrent same-peer calls share one Promise.
8274
+ */
8228
8275
  async getChannel(addr) {
8229
- if (this.channelBinding) {
8230
- await this.channelBinding;
8276
+ const key = channelKey(addr);
8277
+ const existing = this.channelBindingByAddr.get(key);
8278
+ if (existing) {
8279
+ return existing;
8280
+ }
8281
+ const cached = this.channelByAddr[key];
8282
+ const now = int(Date.now() / 1e3);
8283
+ if (cached && cached.refreshAt > now) {
8284
+ return cached;
8231
8285
  }
8232
- let channel = this.channelByAddr[addr.join(":")];
8286
+ const operation = this.channelBindQueue.then(
8287
+ () => this.ensureChannel(addr)
8288
+ );
8289
+ this.channelBindQueue = operation.then(
8290
+ () => void 0,
8291
+ () => void 0
8292
+ );
8293
+ this.channelBindingByAddr.set(key, operation);
8294
+ try {
8295
+ return await operation;
8296
+ } catch (error) {
8297
+ log21("channelBind error", error);
8298
+ throw error;
8299
+ } finally {
8300
+ if (this.channelBindingByAddr.get(key) === operation) {
8301
+ this.channelBindingByAddr.delete(key);
8302
+ }
8303
+ }
8304
+ }
8305
+ /**
8306
+ * Create or refresh a channel for addr. Provisional mapping is installed
8307
+ * before the request so early ChannelData can be decoded; only a failed
8308
+ * *initial* bind rolls the mapping back. Failed channel numbers are never
8309
+ * reused.
8310
+ */
8311
+ async ensureChannel(addr) {
8312
+ const key = channelKey(addr);
8313
+ const now = int(Date.now() / 1e3);
8314
+ let channel = this.channelByAddr[key];
8315
+ if (channel && channel.refreshAt > now) {
8316
+ return channel;
8317
+ }
8318
+ const isNew = !channel;
8233
8319
  if (!channel) {
8234
- this.channelByAddr[addr.join(":")] = {
8320
+ channel = {
8235
8321
  number: this.channelNumber++,
8236
- address: addr
8322
+ address: addr,
8323
+ refreshAt: 0
8237
8324
  };
8238
- channel = this.channelByAddr[addr.join(":")];
8325
+ this.channelByAddr[key] = channel;
8239
8326
  this.addrByChannel[channel.number] = addr;
8240
- this.channelBinding = this.channelBind(channel.number, addr);
8241
- await this.channelBinding.catch((e) => {
8242
- log21("channelBind error", e);
8243
- throw e;
8244
- });
8245
- this.channelRefreshAt = int(Date.now() / 1e3) + this.channelRefreshTime;
8246
- this.channelBinding = void 0;
8247
- log21("channelBind", channel);
8248
- } else if (this.channelRefreshAt < int(Date.now() / 1e3)) {
8249
- this.channelBinding = this.channelBind(channel.number, addr);
8250
- this.channelRefreshAt = int(Date.now() / 1e3) + this.channelRefreshTime;
8251
- await this.channelBinding.catch((e) => {
8252
- log21("channelBind error", e);
8253
- throw e;
8254
- });
8255
- this.channelBinding = void 0;
8256
- log21("channelBind refresh", channel);
8257
8327
  }
8258
- return channel;
8328
+ try {
8329
+ await this.channelBind(channel.number, addr);
8330
+ channel.refreshAt = int(Date.now() / 1e3) + this.channelRefreshTime;
8331
+ log21(isNew ? "channelBind" : "channelBind refresh", channel);
8332
+ return channel;
8333
+ } catch (error) {
8334
+ if (isNew) {
8335
+ delete this.channelByAddr[key];
8336
+ delete this.addrByChannel[channel.number];
8337
+ }
8338
+ throw error;
8339
+ }
8259
8340
  }
8260
8341
  async channelBind(channelNumber, addr) {
8261
8342
  const request = new Message(9 /* CHANNEL_BIND */, 0 /* REQUEST */);
@@ -17883,15 +17964,27 @@ var RTCPeerConnection = class extends EventTarget {
17883
17964
  this.transceiverManager.close();
17884
17965
  await this.secureManager.close();
17885
17966
  await this.sctpManager.close();
17886
- this.onDataChannel.allUnsubscribe();
17887
- this.iceGatheringStateChange.allUnsubscribe();
17888
- this.iceConnectionStateChange.allUnsubscribe();
17889
- this.signalingStateChange.allUnsubscribe();
17890
- this.onTransceiverAdded.allUnsubscribe();
17891
- this.onRemoteTransceiverAdded.allUnsubscribe();
17892
- this.onIceCandidate.allUnsubscribe();
17967
+ this.completePeerEvents();
17893
17968
  log37("peerConnection closed");
17894
17969
  }
17970
+ completePeerEvents() {
17971
+ const events = [
17972
+ this.onDataChannel,
17973
+ this.iceGatheringStateChange,
17974
+ this.iceConnectionStateChange,
17975
+ this.signalingStateChange,
17976
+ this.connectionStateChange,
17977
+ this.onTransceiverAdded,
17978
+ this.onRemoteTransceiverAdded,
17979
+ this.onIceCandidate,
17980
+ this.onNegotiationneeded
17981
+ ];
17982
+ for (const event of events) {
17983
+ if (!event.ended) {
17984
+ event.complete();
17985
+ }
17986
+ }
17987
+ }
17895
17988
  };
17896
17989
  var findCodecByMimeType = (codecs, target) => codecs.find(
17897
17990
  (localCodec) => localCodec.mimeType.toLowerCase() === target.mimeType.toLowerCase()
@@ -527,7 +527,7 @@ var Event2 = class {
527
527
  };
528
528
  allUnsubscribe = () => {
529
529
  if (this.ended) {
530
- throw new Error("event completed");
530
+ return;
531
531
  }
532
532
  this.event = {
533
533
  stack: [],
@@ -198,6 +198,7 @@ export declare class RTCPeerConnection extends EventTarget {
198
198
  private createPeerConnectionStats;
199
199
  getStats(selector?: MediaStreamTrack | null): Promise<RTCStatsReport>;
200
200
  close(): Promise<void>;
201
+ private completePeerEvents;
201
202
  }
202
203
  export type DebugConfig = Partial<{
203
204
  /**% */
@@ -1047,15 +1047,28 @@ class RTCPeerConnection extends helper_1.EventTarget {
1047
1047
  this.transceiverManager.close();
1048
1048
  await this.secureManager.close();
1049
1049
  await this.sctpManager.close();
1050
- this.onDataChannel.allUnsubscribe();
1051
- this.iceGatheringStateChange.allUnsubscribe();
1052
- this.iceConnectionStateChange.allUnsubscribe();
1053
- this.signalingStateChange.allUnsubscribe();
1054
- this.onTransceiverAdded.allUnsubscribe();
1055
- this.onRemoteTransceiverAdded.allUnsubscribe();
1056
- this.onIceCandidate.allUnsubscribe();
1050
+ // 公開 Event を完了させ、購読者・クロージャが PeerConnection を保持し続けないようにする
1051
+ this.completePeerEvents();
1057
1052
  log("peerConnection closed");
1058
1053
  }
1054
+ completePeerEvents() {
1055
+ const events = [
1056
+ this.onDataChannel,
1057
+ this.iceGatheringStateChange,
1058
+ this.iceConnectionStateChange,
1059
+ this.signalingStateChange,
1060
+ this.connectionStateChange,
1061
+ this.onTransceiverAdded,
1062
+ this.onRemoteTransceiverAdded,
1063
+ this.onIceCandidate,
1064
+ this.onNegotiationneeded,
1065
+ ];
1066
+ for (const event of events) {
1067
+ if (!event.ended) {
1068
+ event.complete();
1069
+ }
1070
+ }
1071
+ }
1059
1072
  }
1060
1073
  exports.RTCPeerConnection = RTCPeerConnection;
1061
1074
  const findCodecByMimeType = (codecs, target) => codecs.find((localCodec) => localCodec.mimeType.toLowerCase() === target.mimeType.toLowerCase())