"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
var __typeError = (msg) => {
  throw TypeError(msg);
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __using = (stack, value, async) => {
  if (value != null) {
    if (typeof value !== "object" && typeof value !== "function") __typeError("Object expected");
    var dispose, inner;
    if (async) dispose = value[__knownSymbol("asyncDispose")];
    if (dispose === void 0) {
      dispose = value[__knownSymbol("dispose")];
      if (async) inner = dispose;
    }
    if (typeof dispose !== "function") __typeError("Object not disposable");
    if (inner) dispose = function() {
      try {
        inner.call(this);
      } catch (e) {
        return Promise.reject(e);
      }
    };
    stack.push([async, dispose, value]);
  } else if (async) {
    stack.push([async]);
  }
  return value;
};
var __callDispose = (stack, error, hasError) => {
  var E = typeof SuppressedError === "function" ? SuppressedError : function(e, s, m, _) {
    return _ = Error(m), _.name = "SuppressedError", _.error = e, _.suppressed = s, _;
  };
  var fail = (e) => error = hasError ? new E(e, error, "An error was suppressed during disposal") : (hasError = true, e);
  var next = (it) => {
    while (it = stack.pop()) {
      try {
        var result = it[1] && it[1].call(it[2]);
        if (it[0]) return Promise.resolve(result).then(next, (e) => (fail(e), next()));
      } catch (e) {
        fail(e);
      }
    }
    if (hasError) throw error;
  };
  return next();
};
var ServerSubscription_exports = {};
__export(ServerSubscription_exports, {
  DEFAULT_RANDOMIZATION_WINDOW: () => DEFAULT_RANDOMIZATION_WINDOW,
  INTERNAL_INTERVAL_PUBLISHER_LIMIT: () => INTERNAL_INTERVAL_PUBLISHER_LIMIT,
  MAX_INTERVAL_PUBLISHER_LIMIT: () => MAX_INTERVAL_PUBLISHER_LIMIT,
  MIN_INTERVAL: () => MIN_INTERVAL,
  ServerSubscription: () => ServerSubscription,
  ServerSubscriptionConfig: () => ServerSubscriptionConfig
});
module.exports = __toCommonJS(ServerSubscription_exports);
var import_NodeActivity = require("#behavior/context/NodeActivity.js");
var import_RemoteActorContext = require("#behavior/context/server/RemoteActorContext.js");
var import_general = require("@matter/general");
var import_model = require("@matter/model");
var import_protocol = require("@matter/protocol");
var import_types = require("@matter/types");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("ServerSubscription");
const MAX_INTERVAL_PUBLISHER_LIMIT = import_general.Hours.one;
const INTERNAL_INTERVAL_PUBLISHER_LIMIT = (0, import_general.Minutes)(3);
const MIN_INTERVAL = (0, import_general.Seconds)(2);
const DEFAULT_RANDOMIZATION_WINDOW = (0, import_general.Seconds)(10);
var ServerSubscriptionConfig;
((ServerSubscriptionConfig2) => {
  function of(options) {
    return {
      maxInterval: options?.maxInterval ?? INTERNAL_INTERVAL_PUBLISHER_LIMIT,
      minInterval: import_general.Duration.max(options?.minInterval ?? MIN_INTERVAL, MIN_INTERVAL),
      randomizationWindow: options?.randomizationWindow ?? DEFAULT_RANDOMIZATION_WINDOW
    };
  }
  ServerSubscriptionConfig2.of = of;
})(ServerSubscriptionConfig || (ServerSubscriptionConfig = {}));
class ServerSubscription {
  #lifetime;
  #context;
  #id;
  #isClosed = false;
  #isCanceledByPeer = false;
  #request;
  #cancelled = (0, import_general.AsyncObservable)();
  #maxInterval;
  #lastUpdateTime = import_general.Timestamp.zero;
  #updateTimer;
  #sendDelayTimer;
  #outstandingAttributeUpdates;
  #outstandingEventsMinNumber;
  #changeHandlers = new import_general.ObserverGroup();
  #sendUpdatesActivated = false;
  #seededClusterDetails = /* @__PURE__ */ new Map();
  #latestSeededEventNumber = (0, import_types.EventNumber)(0);
  #sendInterval;
  #peerAddress;
  #sendNextUpdateImmediately = false;
  #sendUpdateErrorCounter = 0;
  #currentUpdatePromise;
  #currentSendExchange;
  constructor(options) {
    const { id, context, request, subscriptionOptions, useAsMaxInterval, useAsSendInterval } = options;
    this.#id = id;
    this.#request = request;
    this.#context = context;
    this.#peerAddress = this.session.peerAddress;
    let maxInterval;
    let sendInterval;
    if (useAsMaxInterval !== void 0 && useAsSendInterval !== void 0) {
      maxInterval = useAsMaxInterval;
      sendInterval = useAsSendInterval;
    } else {
      ({ maxInterval, sendInterval } = this.#determineSendingIntervals(
        subscriptionOptions.minInterval,
        subscriptionOptions.maxInterval,
        subscriptionOptions.randomizationWindow
      ));
    }
    this.maxInterval = maxInterval;
    this.#sendInterval = sendInterval;
    this.#sendDelayTimer = import_general.Time.getTimer(
      `Subscription ${this.idStr} delay`,
      (0, import_general.Millis)(50),
      () => this.#triggerSendUpdate()
    );
    this.#updateTimer = import_general.Time.getTimer(
      `Subscription ${this.idStr} update`,
      this.#sendInterval,
      () => this.#prepareDataUpdate()
    );
  }
  get subscriptionId() {
    return this.#id;
  }
  get idStr() {
    return import_general.hex.fixed(this.#id, 8);
  }
  get session() {
    return this.#context.session;
  }
  get isCanceledByPeer() {
    return this.#isCanceledByPeer;
  }
  get request() {
    return this.#request;
  }
  get cancelled() {
    return this.#cancelled;
  }
  get maxInterval() {
    if (this.#maxInterval === void 0) {
      throw new import_general.InternalError("Subscription maxInterval accessed before it was set");
    }
    return this.#maxInterval;
  }
  get sendInterval() {
    return this.#sendInterval;
  }
  get minIntervalFloor() {
    return (0, import_general.Seconds)(this.request.minIntervalFloorSeconds);
  }
  get maxIntervalCeiling() {
    return (0, import_general.Seconds)(this.request.maxIntervalCeilingSeconds);
  }
  set maxInterval(value) {
    if (this.#maxInterval !== void 0) {
      throw new import_general.InternalError("Subscription maxInterval set twice");
    }
    this.#maxInterval = value;
  }
  async handlePeerCancel() {
    this.#isCanceledByPeer = true;
    try {
      await this.#currentSendExchange?.close(new import_general.ClosedError("Subscription cancelled by peer"));
    } catch (error) {
      logger.debug("Error closing in-flight send exchange on peer cancel:", error);
    } finally {
      await this.close();
    }
  }
  #determineSendingIntervals(subscriptionMinInterval, subscriptionMaxInterval, subscriptionRandomizationWindow) {
    const maxInterval = import_general.Duration.max(
      this.minIntervalFloor,
      import_general.Duration.min(
        import_general.Millis.floor(
          (0, import_general.Millis)(
            import_general.Duration.max(
              subscriptionMinInterval,
              import_general.Duration.max(
                this.minIntervalFloor,
                import_general.Duration.min(subscriptionMaxInterval, this.maxIntervalCeiling)
              )
            ) + subscriptionRandomizationWindow * Math.random()
          )
        ),
        MAX_INTERVAL_PUBLISHER_LIMIT
      )
    );
    let sendInterval = import_general.Millis.floor((0, import_general.Millis)(maxInterval / 2));
    if (sendInterval < import_general.Minutes.one) {
      sendInterval = import_general.Duration.max(this.minIntervalFloor, import_general.Millis.floor((0, import_general.Millis)(maxInterval * 0.8)));
    }
    if (sendInterval < subscriptionMinInterval) {
      logger.warn(
        `Determined subscription send interval of ${import_general.Duration.format(sendInterval)} is too low. Using maxInterval (${import_general.Duration.format(maxInterval)}) instead.`
      );
      sendInterval = subscriptionMinInterval;
    }
    return { maxInterval, sendInterval };
  }
  #addOutstandingAttributes(endpointId, clusterId, changedAttrs) {
    if (!changedAttrs.length) {
      return;
    }
    this.#outstandingAttributeUpdates = this.#outstandingAttributeUpdates ?? {};
    this.#outstandingAttributeUpdates[endpointId] = this.#outstandingAttributeUpdates[endpointId] ?? {};
    this.#outstandingAttributeUpdates[endpointId][clusterId] = this.#outstandingAttributeUpdates[endpointId][clusterId] ?? /* @__PURE__ */ new Set();
    for (const attributeId of changedAttrs) {
      this.#outstandingAttributeUpdates[endpointId][clusterId].add(attributeId);
    }
  }
  #handleClusterStateChanges(endpointId, clusterId, changedAttrs, version) {
    if (this.#isClosed || !changedAttrs.length) {
      return;
    }
    if (this.#seededClusterDetails !== void 0) {
      const seededVersion = this.#seededClusterDetails.get(`${endpointId}-${clusterId}`);
      if (seededVersion !== void 0 && seededVersion === version) {
        return;
      }
    }
    this.#addOutstandingAttributes(endpointId, clusterId, changedAttrs);
    this.#prepareDataUpdate();
  }
  #handleAddedEvents(occurrence) {
    if (this.#isClosed) {
      return;
    }
    if (this.#outstandingEventsMinNumber === void 0 || this.#latestSeededEventNumber !== void 0) {
      this.#outstandingEventsMinNumber = occurrence.number;
    }
    if (this.#sendEventUrgently(occurrence)) {
      this.#prepareDataUpdate();
    }
  }
  #sendEventUrgently({ endpointId, clusterId, eventId }) {
    return (this.request.eventRequests ?? []).some(
      ({ endpointId: reqEndpointId, clusterId: reqClusterId, eventId: reqEventId, isUrgent }) => isUrgent && (reqEndpointId === void 0 || reqEndpointId === endpointId) && (reqClusterId === void 0 || reqClusterId === clusterId) && (reqEventId === void 0 || reqEventId === eventId)
    );
  }
  activate() {
    this.session.subscriptions.add(this);
    logger.debug(this.session.via, "New subscription", import_general.Diagnostic.strong(this.idStr));
    this.#lifetime = this.#context.session.join("subscription", import_general.Diagnostic.strong(this.#id));
    if (this.request.eventFilters !== void 0) this.request.eventFilters.length = 0;
    if (this.request.dataVersionFilters !== void 0) this.request.dataVersionFilters.length = 0;
    this.#sendUpdatesActivated = true;
    if (this.#outstandingEventsMinNumber !== void 0 && this.#latestSeededEventNumber !== void 0) {
      if (this.#latestSeededEventNumber < this.#outstandingEventsMinNumber) {
        this.#outstandingEventsMinNumber = (0, import_types.EventNumber)(BigInt(this.#latestSeededEventNumber) + BigInt(1));
      } else {
        this.#outstandingEventsMinNumber = void 0;
      }
    }
    this.#latestSeededEventNumber = void 0;
    this.#seededClusterDetails = void 0;
    if (this.#outstandingAttributeUpdates !== void 0 || this.#outstandingEventsMinNumber !== void 0) {
      this.#triggerSendUpdate();
    }
    this.#updateTimer = import_general.Time.getTimer(
      "Subscription update",
      this.#sendInterval,
      () => this.#prepareDataUpdate()
    ).start();
  }
  /**
   * Check if data should be sent straight away or delayed because the minimum interval is not reached. Delay real
   * sending by 50ms in any case to make sure to catch all updates.
   */
  #prepareDataUpdate() {
    if (this.#sendDelayTimer.isRunning || this.#isClosed) {
      return;
    }
    if (!this.#sendUpdatesActivated) {
      return;
    }
    this.#updateTimer.stop();
    const now = import_general.Time.nowMs;
    const timeSinceLastUpdate = (0, import_general.Millis)(now - this.#lastUpdateTime);
    if (timeSinceLastUpdate < this.minIntervalFloor) {
      this.#updateTimer = import_general.Time.getTimer(
        "Subscription update",
        (0, import_general.Millis)(this.minIntervalFloor - timeSinceLastUpdate),
        () => this.#prepareDataUpdate()
      ).start();
      return;
    }
    this.#sendDelayTimer.start();
    this.#updateTimer = import_general.Time.getTimer(
      `Subscription update ${this.idStr}`,
      this.#sendInterval,
      () => this.#prepareDataUpdate()
    ).start();
  }
  #triggerSendUpdate(onlyWithData = false, session) {
    if (this.#currentUpdatePromise !== void 0) {
      logger.debug("Sending update already in progress, delaying update ...");
      this.#sendNextUpdateImmediately = true;
      return;
    }
    this.#currentUpdatePromise = this.#sendUpdate(onlyWithData, session).catch((error) => logger.warn("Sending subscription update failed:", error)).finally(() => this.#currentUpdatePromise = void 0);
  }
  /**
   * Determine all attributes that have changed since the last update and send them out to the subscriber.
   */
  async #sendUpdate(onlyWithData = false, session) {
    var _stack3 = [];
    try {
      const updating = __using(_stack3, this.#lifetime?.join("updating"));
      while (true) {
        const attributeFilter = this.#outstandingAttributeUpdates;
        this.#outstandingAttributeUpdates = void 0;
        const eventsMinNumber = this.#outstandingEventsMinNumber;
        this.#outstandingEventsMinNumber = void 0;
        if (onlyWithData && attributeFilter === void 0 && eventsMinNumber === void 0) {
          break;
        }
        this.#lastUpdateTime = import_general.Time.nowMs;
        try {
          var _stack = [];
          try {
            const sending = __using(_stack, updating?.join("sending"));
            if (await this.#sendUpdateMessage(sending, attributeFilter, eventsMinNumber, onlyWithData, session)) {
              this.#sendUpdateErrorCounter = 0;
            }
          } catch (_) {
            var _error = _, _hasError = true;
          } finally {
            __callDispose(_stack, _error, _hasError);
          }
        } catch (error) {
          if (this.#isClosed || this.#isCanceledByPeer) {
            return;
          }
          this.#sendUpdateErrorCounter++;
          logger.info(
            `Error sending subscription update message (error count=${this.#sendUpdateErrorCounter}):`,
            error instanceof import_general.MatterError && error.message || error
          );
          if (this.#sendUpdateErrorCounter <= 2) {
            if (attributeFilter !== void 0) {
              for (const [endpointId, clusters] of Object.entries(attributeFilter)) {
                for (const [clusterId, attributes] of Object.entries(clusters)) {
                  this.#addOutstandingAttributes(
                    (0, import_types.EndpointNumber)(parseInt(endpointId)),
                    (0, import_types.ClusterId)(parseInt(clusterId)),
                    Array.from(attributes)
                  );
                }
              }
            }
            if (eventsMinNumber !== void 0) {
              this.#outstandingEventsMinNumber = eventsMinNumber;
            }
          } else {
            logger.info(
              `Sending update failed 3 times in a row, canceling subscription ${this.idStr} and let controller subscribe again.`
            );
            this.#sendNextUpdateImmediately = false;
            if (error instanceof import_general.NoResponseTimeoutError || error instanceof import_general.NetworkError || error instanceof import_protocol.SessionClosedError) {
              var _stack2 = [];
              try {
                const _messaging = __using(_stack2, updating?.join("canceling"));
                this.#isCanceledByPeer = true;
                await this.#cancel();
                break;
              } catch (_2) {
                var _error2 = _2, _hasError2 = true;
              } finally {
                __callDispose(_stack2, _error2, _hasError2);
              }
            } else {
              throw error;
            }
          }
        }
        if (!this.#sendNextUpdateImmediately) {
          break;
        }
        logger.debug("Sending delayed update immediately after last one was sent");
        this.#sendNextUpdateImmediately = false;
        onlyWithData = true;
      }
    } catch (_3) {
      var _error3 = _3, _hasError3 = true;
    } finally {
      __callDispose(_stack3, _error3, _hasError3);
    }
  }
  /**
   * Returns an iterator that yields the data reports and events data for the given read request.
   */
  async *#processAttributesAndEventsReport(context, suppressStatusReports = false) {
    const request = {
      ...this.request,
      interactionModelRevision: import_model.Specification.INTERACTION_MODEL_REVISION
      // irrelevant here, set to our version
    };
    const delayedStatusReports = new Array();
    let hasValuesInResponse = false;
    let validAttributes = 0;
    let validEvents = 0;
    const session = (0, import_RemoteActorContext.RemoteActorContext)(context).beginReadOnly();
    try {
      if (import_protocol.Read.containsAttribute(request)) {
        const attributeReader = new import_protocol.AttributeReadResponse(this.#context.node.protocol, session);
        for (const chunk of attributeReader.process(request)) {
          for await (const report of chunk) {
            if (report.kind === "attr-status") {
              if (suppressStatusReports) {
                continue;
              }
              if (!hasValuesInResponse) {
                delayedStatusReports.push(report);
                continue;
              }
            } else if (!hasValuesInResponse && report.kind === "attr-value") {
              for (const delayedReport of delayedStatusReports) {
                yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(delayedReport);
              }
              delayedStatusReports.length = 0;
              hasValuesInResponse = true;
            }
            if (this.#seededClusterDetails !== void 0 && report.kind === "attr-value") {
              const {
                path: { endpointId, clusterId },
                version
              } = report;
              this.#seededClusterDetails.set(`${endpointId}-${clusterId}`, version);
            }
            yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(report);
          }
        }
        validAttributes = attributeReader.counts.existent;
      }
      if (import_protocol.Read.containsEvent(request)) {
        const eventReader = new import_protocol.EventReadResponse(this.#context.node.protocol, session);
        for await (const chunk of eventReader.process(request)) {
          for await (const report of chunk) {
            if (report.kind === "event-status") {
              if (suppressStatusReports) {
                continue;
              }
              if (!hasValuesInResponse) {
                delayedStatusReports.push(report);
                continue;
              }
            } else if (!hasValuesInResponse && report.kind === "event-value") {
              for (const delayedReport of delayedStatusReports) {
                yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(delayedReport);
              }
              delayedStatusReports.length = 0;
              hasValuesInResponse = true;
            }
            if (this.#latestSeededEventNumber !== void 0 && report.kind === "event-value") {
              this.#latestSeededEventNumber = report.number;
            }
            yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(report);
          }
        }
        validEvents = eventReader.counts.existent;
      }
      if (validAttributes === 0 && validEvents === 0) {
        throw new import_types.StatusResponseError(
          "Subscription failed because no attributes or events are matching the query",
          import_types.Status.InvalidAction
        );
      } else if (!hasValuesInResponse && delayedStatusReports.length) {
        for (const delayedReport of delayedStatusReports) {
          yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(delayedReport);
        }
      }
    } finally {
      session[Symbol.dispose]();
    }
    this.#lastUpdateTime = import_general.Time.nowMs;
  }
  async sendInitialReport(messenger, readContext, suppressStatusReports) {
    this.#updateTimer.stop();
    if (this.request.attributeRequests?.length) {
      this.#changeHandlers.on(
        this.#context.node.protocol.attrsChanged,
        this.#handleClusterStateChanges.bind(this)
      );
    }
    if (this.request.eventRequests?.length) {
      this.#changeHandlers.on(this.#context.node.protocol.eventHandler.added, this.#handleAddedEvents.bind(this));
    }
    await messenger.sendDataReport({
      baseDataReport: {
        suppressResponse: false,
        // we always need proper response for initial report
        subscriptionId: this.subscriptionId,
        interactionModelRevision: import_model.Specification.INTERACTION_MODEL_REVISION
      },
      forFabricFilteredRead: this.request.isFabricFiltered,
      payload: this.#processAttributesAndEventsReport(readContext, suppressStatusReports)
    });
  }
  async #flush(flushViaSession) {
    this.#sendDelayTimer.stop();
    if (this.#outstandingAttributeUpdates !== void 0 || this.#outstandingEventsMinNumber !== void 0) {
      logger.debug(`Flushing subscription ${this.idStr}${this.#isClosed ? " (for closing)" : ""}`);
      this.#triggerSendUpdate(true, flushViaSession);
      if (this.#currentUpdatePromise) {
        var _stack = [];
        try {
          const _waiting = __using(_stack, this.#lifetime?.join("waiting on flush"));
          await this.#currentUpdatePromise;
        } catch (_) {
          var _error = _, _hasError = true;
        } finally {
          __callDispose(_stack, _error, _hasError);
        }
      }
    }
  }
  /**
   * Closes the subscription and flushes all outstanding data updates if requested.
   */
  async close(flushViaSession) {
    if (this.#isClosed) {
      return;
    }
    this.#isClosed = true;
    await this.#cancel(flushViaSession);
    if (this.#currentUpdatePromise) {
      var _stack = [];
      try {
        const _waiting = __using(_stack, this.#lifetime?.closing()?.join("waiting on update"));
        await this.#currentUpdatePromise;
      } catch (_) {
        var _error = _, _hasError = true;
      } finally {
        __callDispose(_stack, _error, _hasError);
      }
    }
  }
  async #cancel(flushViaSession) {
    const closing = this.#lifetime?.closing();
    this.#sendUpdatesActivated = false;
    this.#changeHandlers.close();
    if (flushViaSession !== void 0) {
      var _stack = [];
      try {
        const _flushing = __using(_stack, closing?.join("flushing"));
        await this.#flush(flushViaSession);
      } catch (_) {
        var _error = _, _hasError = true;
      } finally {
        __callDispose(_stack, _error, _hasError);
      }
    }
    this.#updateTimer.stop();
    this.#sendDelayTimer.stop();
    this.session.subscriptions.delete(this);
    logger.debug(this.session.via, "Deleted subscription", import_general.hex.fixed(this.subscriptionId, 8));
    this.cancelled.emit(this);
  }
  /**
   * Iterates over all attributes and events that have changed since the last update and sends them to
   * the controller.
   * A thrown exception will cancel the sending process immediately.
   */
  async *#iterateDataUpdate(exchange, attributeFilter, eventsMinNumber) {
    const request = {
      ...this.request,
      interactionModelRevision: import_model.Specification.INTERACTION_MODEL_REVISION
      // irrelevant here, set to our version
    };
    const session = (0, import_RemoteActorContext.RemoteActorContext)({
      activity: exchange[import_NodeActivity.NodeActivity.activityKey],
      fabricFiltered: request.isFabricFiltered,
      exchange,
      node: this.#context.node
    }).beginReadOnly();
    try {
      if (attributeFilter !== void 0 && import_protocol.Read.containsAttribute(request)) {
        const attributeReader = new import_protocol.AttributeSubscriptionResponse(
          this.#context.node.protocol,
          session,
          attributeFilter
        );
        for (const chunk of attributeReader.process(request)) {
          for await (const report of chunk) {
            yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(report);
          }
        }
      }
      if (eventsMinNumber !== void 0 && import_protocol.Read.containsEvent(request)) {
        request.eventFilters = [{ eventMin: eventsMinNumber }];
        const eventReader = new import_protocol.EventReadResponse(this.#context.node.protocol, session);
        for await (const chunk of eventReader.process(request)) {
          for await (const report of chunk) {
            if (report.kind === "event-status") {
              continue;
            }
            yield import_protocol.InteractionServerMessenger.convertServerInteractionReport(report);
          }
        }
      }
    } finally {
      session[Symbol.dispose]();
    }
  }
  async #sendUpdateMessage(lifetime, attributeFilter, eventsMinNumber, onlyWithData, session) {
    const exchange = this.#context.initiateExchange(session ?? this.#peerAddress, import_types.INTERACTION_PROTOCOL_ID);
    if (exchange === void 0) {
      return false;
    }
    this.#currentSendExchange = exchange;
    const messenger = new import_protocol.InteractionServerMessenger(exchange);
    try {
      if (attributeFilter === void 0 && eventsMinNumber === void 0) {
        var _stack = [];
        try {
          const _sending = __using(_stack, lifetime?.join("sending keepalive"));
          await messenger.sendDataReport({
            baseDataReport: {
              suppressResponse: true,
              // suppressResponse true for empty DataReports
              subscriptionId: this.subscriptionId,
              interactionModelRevision: import_model.Specification.INTERACTION_MODEL_REVISION
            },
            forFabricFilteredRead: this.request.isFabricFiltered,
            waitForAck: !this.#isClosed
            // Do not wait for ack when closed
          });
        } catch (_) {
          var _error = _, _hasError = true;
        } finally {
          __callDispose(_stack, _error, _hasError);
        }
      } else {
        var _stack2 = [];
        try {
          const _sending = __using(_stack2, lifetime?.join("sending data"));
          await messenger.sendDataReport({
            baseDataReport: {
              suppressResponse: false,
              // Non-empty data reports always need to send response
              subscriptionId: this.subscriptionId,
              interactionModelRevision: import_model.Specification.INTERACTION_MODEL_REVISION
            },
            forFabricFilteredRead: this.request.isFabricFiltered,
            payload: this.#iterateDataUpdate(exchange, attributeFilter, eventsMinNumber),
            waitForAck: !this.#isClosed,
            // Do not wait for ack when closed
            suppressEmptyReport: onlyWithData
          });
        } catch (_2) {
          var _error2 = _2, _hasError2 = true;
        } finally {
          __callDispose(_stack2, _error2, _hasError2);
        }
      }
    } catch (error) {
      var _stack3 = [];
      try {
        if (import_types.StatusResponseError.is(error, import_types.Status.InvalidSubscription, import_types.Status.Failure)) {
          logger.notice(`Subscription ${this.idStr} cancelled by peer`);
          this.#isCanceledByPeer = true;
        } else {
          import_types.StatusResponseError.accept(error);
          logger.info(`Subscription ${this.idStr} update failed:`, error);
        }
        const _canceling = __using(_stack3, lifetime?.join("canceling"));
        await this.#cancel();
      } catch (_3) {
        var _error3 = _3, _hasError3 = true;
      } finally {
        __callDispose(_stack3, _error3, _hasError3);
      }
    } finally {
      var _stack4 = [];
      try {
        this.#currentSendExchange = void 0;
        const _closing = __using(_stack4, lifetime?.join("closing messenger"));
        await messenger.close();
      } catch (_4) {
        var _error4 = _4, _hasError4 = true;
      } finally {
        __callDispose(_stack4, _error4, _hasError4);
      }
    }
    return true;
  }
}
//# sourceMappingURL=ServerSubscription.js.map
