@riddix/hamh 2.1.0-alpha.517 → 2.1.0-alpha.519

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.
@@ -166866,6 +166866,7 @@ function ensureCommissioningConfig(server) {
166866
166866
 
166867
166867
  // src/services/bridges/bridge.ts
166868
166868
  var AUTO_FORCE_SYNC_INTERVAL_MS = 9e4;
166869
+ var DEAD_SESSION_TIMEOUT_MS = 6e4;
166869
166870
  var Bridge = class {
166870
166871
  constructor(env, logger203, dataProvider, endpointManager) {
166871
166872
  this.dataProvider = dataProvider;
@@ -166888,6 +166889,8 @@ var Bridge = class {
166888
166889
  // (e.g. Stopped → Starting → Running).
166889
166890
  onStatusChange;
166890
166891
  autoForceSyncTimer = null;
166892
+ deadSessionTimer = null;
166893
+ staleSessionTimers = /* @__PURE__ */ new Map();
166891
166894
  // Tracks the last synced state JSON per entity to avoid pushing unchanged states.
166892
166895
  // Key: entity_id, Value: JSON.stringify of entity.state
166893
166896
  lastSyncedStates = /* @__PURE__ */ new Map();
@@ -167064,6 +167067,33 @@ ${e?.toString()}`);
167064
167067
  this.log.warn(
167065
167068
  `All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
167066
167069
  );
167070
+ if (!this.deadSessionTimer) {
167071
+ this.deadSessionTimer = setTimeout(() => {
167072
+ this.deadSessionTimer = null;
167073
+ this.closeDeadSessions();
167074
+ }, DEAD_SESSION_TIMEOUT_MS);
167075
+ this.log.info(
167076
+ `Scheduled dead session cleanup in ${DEAD_SESSION_TIMEOUT_MS / 1e3}s`
167077
+ );
167078
+ }
167079
+ } else if (totalSubs > 0 && this.deadSessionTimer) {
167080
+ clearTimeout(this.deadSessionTimer);
167081
+ this.deadSessionTimer = null;
167082
+ this.log.info(
167083
+ "Subscriptions recovered, canceled dead session cleanup"
167084
+ );
167085
+ }
167086
+ if (session.subscriptions.size === 0 && !this.staleSessionTimers.has(session.id)) {
167087
+ this.staleSessionTimers.set(
167088
+ session.id,
167089
+ setTimeout(() => {
167090
+ this.staleSessionTimers.delete(session.id);
167091
+ this.closeStaleSession(session.id);
167092
+ }, DEAD_SESSION_TIMEOUT_MS)
167093
+ );
167094
+ } else if (session.subscriptions.size > 0 && this.staleSessionTimers.has(session.id)) {
167095
+ clearTimeout(this.staleSessionTimers.get(session.id));
167096
+ this.staleSessionTimers.delete(session.id);
167067
167097
  }
167068
167098
  };
167069
167099
  sessionManager.subscriptionsChanged.on(this.sessionDiagHandler);
@@ -167092,6 +167122,38 @@ ${e?.toString()}`);
167092
167122
  } catch {
167093
167123
  }
167094
167124
  }
167125
+ closeStaleSession(sessionId) {
167126
+ try {
167127
+ const sessionManager = this.server.env.get(SessionManager);
167128
+ for (const s of [...sessionManager.sessions]) {
167129
+ if (s.id === sessionId && !s.isClosing && s.subscriptions.size === 0) {
167130
+ this.log.warn(
167131
+ `Force-closing stale session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS / 1e3}s)`
167132
+ );
167133
+ s.initiateForceClose().catch(() => {
167134
+ });
167135
+ break;
167136
+ }
167137
+ }
167138
+ } catch {
167139
+ }
167140
+ }
167141
+ closeDeadSessions() {
167142
+ try {
167143
+ const sessionManager = this.server.env.get(SessionManager);
167144
+ const sessions = [...sessionManager.sessions];
167145
+ for (const s of sessions) {
167146
+ if (!s.isClosing && s.subscriptions.size === 0) {
167147
+ this.log.warn(
167148
+ `Force-closing dead session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS / 1e3}s)`
167149
+ );
167150
+ s.initiateForceClose().catch(() => {
167151
+ });
167152
+ }
167153
+ }
167154
+ } catch {
167155
+ }
167156
+ }
167095
167157
  unwireSessionDiagnostics() {
167096
167158
  try {
167097
167159
  const sessionManager = this.server.env.get(SessionManager);
@@ -167109,6 +167171,14 @@ ${e?.toString()}`);
167109
167171
  this.sessionDiagHandler = void 0;
167110
167172
  this.sessionAddedHandler = void 0;
167111
167173
  this.sessionDeletedHandler = void 0;
167174
+ if (this.deadSessionTimer) {
167175
+ clearTimeout(this.deadSessionTimer);
167176
+ this.deadSessionTimer = null;
167177
+ }
167178
+ for (const timer of this.staleSessionTimers.values()) {
167179
+ clearTimeout(timer);
167180
+ }
167181
+ this.staleSessionTimers.clear();
167112
167182
  }
167113
167183
  stopAutoForceSync() {
167114
167184
  if (this.autoForceSyncTimer) {
@@ -179508,6 +179578,7 @@ function hashAreaId(areaId) {
179508
179578
  // src/services/bridges/server-mode-bridge.ts
179509
179579
  init_dist();
179510
179580
  var AUTO_FORCE_SYNC_INTERVAL_MS2 = 9e4;
179581
+ var DEAD_SESSION_TIMEOUT_MS2 = 6e4;
179511
179582
  var ServerModeBridge = class {
179512
179583
  constructor(logger203, dataProvider, endpointManager, server) {
179513
179584
  this.dataProvider = dataProvider;
@@ -179524,6 +179595,8 @@ var ServerModeBridge = class {
179524
179595
  // broadcast updates via WebSocket so the frontend sees every transition.
179525
179596
  onStatusChange;
179526
179597
  autoForceSyncTimer = null;
179598
+ deadSessionTimer = null;
179599
+ staleSessionTimers = /* @__PURE__ */ new Map();
179527
179600
  warmStartTimer = null;
179528
179601
  // Tracks the last synced state JSON per entity to avoid pushing unchanged states.
179529
179602
  lastSyncedState;
@@ -179705,6 +179778,33 @@ ${e?.toString()}`);
179705
179778
  this.log.warn(
179706
179779
  `All subscriptions lost \u2014 ${sessions.length} session(s) still active, waiting for controller to re-subscribe`
179707
179780
  );
179781
+ if (!this.deadSessionTimer) {
179782
+ this.deadSessionTimer = setTimeout(() => {
179783
+ this.deadSessionTimer = null;
179784
+ this.closeDeadSessions();
179785
+ }, DEAD_SESSION_TIMEOUT_MS2);
179786
+ this.log.info(
179787
+ `Scheduled dead session cleanup in ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s`
179788
+ );
179789
+ }
179790
+ } else if (totalSubs > 0 && this.deadSessionTimer) {
179791
+ clearTimeout(this.deadSessionTimer);
179792
+ this.deadSessionTimer = null;
179793
+ this.log.info(
179794
+ "Subscriptions recovered, canceled dead session cleanup"
179795
+ );
179796
+ }
179797
+ if (session.subscriptions.size === 0 && !this.staleSessionTimers.has(session.id)) {
179798
+ this.staleSessionTimers.set(
179799
+ session.id,
179800
+ setTimeout(() => {
179801
+ this.staleSessionTimers.delete(session.id);
179802
+ this.closeStaleSession(session.id);
179803
+ }, DEAD_SESSION_TIMEOUT_MS2)
179804
+ );
179805
+ } else if (session.subscriptions.size > 0 && this.staleSessionTimers.has(session.id)) {
179806
+ clearTimeout(this.staleSessionTimers.get(session.id));
179807
+ this.staleSessionTimers.delete(session.id);
179708
179808
  }
179709
179809
  };
179710
179810
  sessionManager.subscriptionsChanged.on(this.sessionDiagHandler);
@@ -179733,6 +179833,38 @@ ${e?.toString()}`);
179733
179833
  } catch {
179734
179834
  }
179735
179835
  }
179836
+ closeStaleSession(sessionId) {
179837
+ try {
179838
+ const sessionManager = this.server.env.get(SessionManager);
179839
+ for (const s of [...sessionManager.sessions]) {
179840
+ if (s.id === sessionId && !s.isClosing && s.subscriptions.size === 0) {
179841
+ this.log.warn(
179842
+ `Force-closing stale session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s)`
179843
+ );
179844
+ s.initiateForceClose().catch(() => {
179845
+ });
179846
+ break;
179847
+ }
179848
+ }
179849
+ } catch {
179850
+ }
179851
+ }
179852
+ closeDeadSessions() {
179853
+ try {
179854
+ const sessionManager = this.server.env.get(SessionManager);
179855
+ const sessions = [...sessionManager.sessions];
179856
+ for (const s of sessions) {
179857
+ if (!s.isClosing && s.subscriptions.size === 0) {
179858
+ this.log.warn(
179859
+ `Force-closing dead session ${s.id} (peer ${s.peerNodeId}, no subscriptions for ${DEAD_SESSION_TIMEOUT_MS2 / 1e3}s)`
179860
+ );
179861
+ s.initiateForceClose().catch(() => {
179862
+ });
179863
+ }
179864
+ }
179865
+ } catch {
179866
+ }
179867
+ }
179736
179868
  unwireSessionDiagnostics() {
179737
179869
  try {
179738
179870
  const sessionManager = this.server.env.get(SessionManager);
@@ -179750,6 +179882,14 @@ ${e?.toString()}`);
179750
179882
  this.sessionDiagHandler = void 0;
179751
179883
  this.sessionAddedHandler = void 0;
179752
179884
  this.sessionDeletedHandler = void 0;
179885
+ if (this.deadSessionTimer) {
179886
+ clearTimeout(this.deadSessionTimer);
179887
+ this.deadSessionTimer = null;
179888
+ }
179889
+ for (const timer of this.staleSessionTimers.values()) {
179890
+ clearTimeout(timer);
179891
+ }
179892
+ this.staleSessionTimers.clear();
179753
179893
  }
179754
179894
  stopAutoForceSync() {
179755
179895
  if (this.autoForceSyncTimer) {