1(function() { 2 try { 3 var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {}; 4 e.SENTRY_RELEASE = { id: "9bd7631" }; 5 var n = new e.Error().stack; 6 n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "f3b9cb04-9e90-46f1-97f2-488daf10ffdf", e._sentryDebugIdIdentifier = "sentry-dbid-f3b9cb04-9e90-46f1-97f2-488daf10ffdf"); 7 } catch (e) {} 8})(); 9import { n as __esmMin } from "./rolldown-runtime-C0oiEAqH.js"; 10import { i as isFunction } from "./type-guards-CYLeUmJ9.js"; 11import { t as require_react } from "./react-CRpDT2aV.js"; 12//#region node_modules/.pnpm/@[email protected]/node_modules/@rails/actioncable/app/assets/javascripts/actioncable.esm.js 13function createWebSocketURL(url) { 14 if (typeof url === "function") url = url(); 15 if (url && !/^wss?:/i.test(url)) { 16 const a = document.createElement("a"); 17 a.href = url; 18 a.href = a.href; 19 a.protocol = a.protocol.replace("http", "ws"); 20 return a.href; 21 } else return url; 22} 23function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) { 24 return new Consumer(url); 25} 26function getConfig(name) { 27 const element = document.head.querySelector(`meta[name='action-cable-${name}']`); 28 if (element) return element.getAttribute("content"); 29} 30var adapters, logger, now, secondsSince, ConnectionMonitor, INTERNAL, message_types, protocols, supportedProtocols, indexOf, Connection, extend, Subscription, SubscriptionGuarantor, Subscriptions, Consumer; 31function init_actioncable_esm() { 32 return (init_actioncable_esm = __esmMin((() => { 33 adapters = { 34 logger: typeof console !== "undefined" ? console : void 0, 35 WebSocket: typeof WebSocket !== "undefined" ? WebSocket : void 0 36 }; 37 logger = { log(...messages) { 38 if (this.enabled) { 39 messages.push(Date.now()); 40 adapters.logger.log("[ActionCable]", ...messages); 41 } 42 } }; 43 now = () => (/* @__PURE__ */ new Date()).getTime(); 44 secondsSince = (time) => (now() - time) / 1e3; 45 ConnectionMonitor = class { 46 constructor(connection) { 47 this.visibilityDidChange = this.visibilityDidChange.bind(this); 48 this.connection = connection; 49 this.reconnectAttempts = 0; 50 } 51 start() { 52 if (!this.isRunning()) { 53 this.startedAt = now(); 54 delete this.stoppedAt; 55 this.startPolling(); 56 addEventListener("visibilitychange", this.visibilityDidChange); 57 logger.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`); 58 } 59 } 60 stop() { 61 if (this.isRunning()) { 62 this.stoppedAt = now(); 63 this.stopPolling(); 64 removeEventListener("visibilitychange", this.visibilityDidChange); 65 logger.log("ConnectionMonitor stopped"); 66 } 67 } 68 isRunning() { 69 return this.startedAt && !this.stoppedAt; 70 } 71 recordMessage() { 72 this.pingedAt = now(); 73 } 74 recordConnect() { 75 this.reconnectAttempts = 0; 76 delete this.disconnectedAt; 77 logger.log("ConnectionMonitor recorded connect"); 78 } 79 recordDisconnect() { 80 this.disconnectedAt = now(); 81 logger.log("ConnectionMonitor recorded disconnect"); 82 } 83 startPolling() { 84 this.stopPolling(); 85 this.poll(); 86 } 87 stopPolling() { 88 clearTimeout(this.pollTimeout); 89 } 90 poll() { 91 this.pollTimeout = setTimeout((() => { 92 this.reconnectIfStale(); 93 this.poll(); 94 }), this.getPollInterval()); 95 } 96 getPollInterval() { 97 const { staleThreshold, reconnectionBackoffRate } = this.constructor; 98 const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10)); 99 const jitter = (this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate) * Math.random(); 100 return staleThreshold * 1e3 * backoff * (1 + jitter); 101 } 102 reconnectIfStale() { 103 if (this.connectionIsStale()) { 104 logger.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`); 105 this.reconnectAttempts++; 106 if (this.disconnectedRecently()) logger.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`); 107 else { 108 logger.log("ConnectionMonitor reopening"); 109 this.connection.reopen(); 110 } 111 } 112 } 113 get refreshedAt() { 114 return this.pingedAt ? this.pingedAt : this.startedAt; 115 } 116 connectionIsStale() { 117 return secondsSince(this.refreshedAt) > this.constructor.staleThreshold; 118 } 119 disconnectedRecently() { 120 return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; 121 } 122 visibilityDidChange() { 123 if (document.visibilityState === "visible") setTimeout((() => { 124 if (this.connectionIsStale() || !this.connection.isOpen()) { 125 logger.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`); 126 this.connection.reopen(); 127 } 128 }), 200); 129 } 130 }; 131 ConnectionMonitor.staleThreshold = 6; 132 ConnectionMonitor.reconnectionBackoffRate = .15; 133 INTERNAL = { 134 message_types: { 135 welcome: "welcome", 136 disconnect: "disconnect", 137 ping: "ping", 138 confirmation: "confirm_subscription", 139 rejection: "reject_subscription" 140 }, 141 disconnect_reasons: { 142 unauthorized: "unauthorized",
143 invalid_request: "invalid_request", 144 server_restart: "server_restart", 145 remote: "remote" 146 }, 147 default_mount_path: "/cable", 148 protocols: ["actioncable-v1-json", "actioncable-unsupported"] 149 }; 150 ({message_types: message_types, protocols: protocols} = INTERNAL); 151 supportedProtocols = protocols.slice(0, protocols.length - 1); 152 indexOf = [].indexOf; 153 Connection = class { 154 constructor(consumer) { 155 this.open = this.open.bind(this); 156 this.consumer = consumer; 157 this.subscriptions = this.consumer.subscriptions; 158 this.monitor = new ConnectionMonitor(this); 159 this.disconnected = true; 160 } 161 send(data) { 162 if (this.isOpen()) { 163 this.webSocket.send(JSON.stringify(data)); 164 return true; 165 } else return false; 166 } 167 open() { 168 if (this.isActive()) { 169 logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`); 170 return false; 171 } else { 172 const socketProtocols = [...protocols, ...this.consumer.subprotocols || []]; 173 logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`); 174 if (this.webSocket) this.uninstallEventHandlers(); 175 this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols); 176 this.installEventHandlers(); 177 this.monitor.start(); 178 return true; 179 } 180 } 181 close({ allowReconnect } = { allowReconnect: true }) { 182 if (!allowReconnect) this.monitor.stop(); 183 if (this.isOpen()) return this.webSocket.close(); 184 } 185 reopen() { 186 logger.log(`Reopening WebSocket, current state is ${this.getState()}`); 187 if (this.isActive()) try { 188 return this.close(); 189 } catch (error) { 190 logger.log("Failed to reopen WebSocket", error); 191 } finally { 192 logger.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`); 193 setTimeout(this.open, this.constructor.reopenDelay); 194 } 195 else return this.open(); 196 } 197 getProtocol() { 198 if (this.webSocket) return this.webSocket.protocol; 199 } 200 isOpen() { 201 return this.isState("open"); 202 } 203 isActive() { 204 return this.isState("open", "connecting"); 205 } 206 triedToReconnect() { 207 return this.monitor.reconnectAttempts > 0; 208 } 209 isProtocolSupported() { 210 return indexOf.call(supportedProtocols, this.getProtocol()) >= 0; 211 } 212 isState(...states) {
213 return indexOf.call(states, this.getState()) >= 0; 214 } 215 getState() { 216 if (this.webSocket) { 217 for (let state in adapters.WebSocket) if (adapters.WebSocket[state] === this.webSocket.readyState) return state.toLowerCase(); 218 } 219 return null; 220 } 221 installEventHandlers() { 222 for (let eventName in this.events) { 223 const handler = this.events[eventName].bind(this); 224 this.webSocket[`on${eventName}`] = handler; 225 } 226 } 227 uninstallEventHandlers() { 228 for (let eventName in this.events) this.webSocket[`on${eventName}`] = function() {}; 229 } 230 }; 231 Connection.reopenDelay = 500; 232 Connection.prototype.events = { 233 message(event) { 234 if (!this.isProtocolSupported()) return; 235 const { identifier, message, reason, reconnect, type } = JSON.parse(event.data); 236 this.monitor.recordMessage(); 237 switch (type) { 238 case message_types.welcome: 239 if (this.triedToReconnect()) this.reconnectAttempted = true; 240 this.monitor.recordConnect(); 241 return this.subscriptions.reload(); 242 case message_types.disconnect: 243 logger.log(`Disconnecting. Reason: ${reason}`); 244 return this.close({ allowReconnect: reconnect }); 245 case message_types.ping: return null; 246 case message_types.confirmation: 247 this.subscriptions.confirmSubscription(identifier); 248 if (this.reconnectAttempted) { 249 this.reconnectAttempted = false; 250 return this.subscriptions.notify(identifier, "connected", { reconnected: true }); 251 } else return this.subscriptions.notify(identifier, "connected", { reconnected: false }); 252 case message_types.rejection: return this.subscriptions.reject(identifier); 253 default: return this.subscriptions.notify(identifier, "received", message); 254 } 255 }, 256 open() { 257 logger.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`); 258 this.disconnected = false; 259 if (!this.isProtocolSupported()) { 260 logger.log("Protocol is unsupported. Stopping monitor and disconnecting."); 261 return this.close({ allowReconnect: false }); 262 } 263 }, 264 close(event) { 265 logger.log("WebSocket onclose event"); 266 if (this.disconnected) return; 267 this.disconnected = true; 268 this.monitor.recordDisconnect(); 269 return this.subscriptions.notifyAll("disconnected", { willAttemptReconnect: this.monitor.isRunning() }); 270 }, 271 error() { 272 logger.log("WebSocket onerror event"); 273 } 274 }; 275 extend = function(object, properties) { 276 if (properties != null) for (let key in properties) object[key] = properties[key]; 277 return object; 278 }; 279 Subscription = class { 280 constructor(consumer, params = {}, mixin) { 281 this.consumer = consumer; 282 this.identifier = JSON.stringify(params); 283 extend(this, mixin); 284 } 285 perform(action, data = {}) { 286 data.action = action; 287 return this.send(data); 288 } 289 send(data) { 290 return this.consumer.send({ 291 command: "message", 292 identifier: this.identifier, 293 data: JSON.stringify(data) 294 }); 295 } 296 unsubscribe() { 297 return this.consumer.subscriptions.remove(this); 298 } 299 }; 300 SubscriptionGuarantor = class { 301 constructor(subscriptions) { 302 this.subscriptions = subscriptions; 303 this.pendingSubscriptions = []; 304 } 305 guarantee(subscription) { 306 if (this.pendingSubscriptions.indexOf(subscription) == -1) { 307 logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`); 308 this.pendingSubscriptions.push(subscription); 309 } else logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`); 310 this.startGuaranteeing(); 311 } 312 forget(subscription) { 313 logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`); 314 this.pendingSubscriptions = this.pendingSubscriptions.filter(((s) => s !== subscription)); 315 } 316 startGuaranteeing() { 317 this.stopGuaranteeing(); 318 this.retrySubscribing(); 319 } 320 stopGuaranteeing() { 321 clearTimeout(this.retryTimeout); 322 } 323 retrySubscribing() { 324 this.retryTimeout = setTimeout((() => { 325 if (this.subscriptions && typeof this.subscriptions.subscribe === "function") this.pendingSubscriptions.map(((subscription) => { 326 logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`); 327 this.subscriptions.subscribe(subscription); 328 })); 329 }), 500); 330 } 331 }; 332 Subscriptions = class { 333 constructor(consumer) { 334 this.consumer = consumer; 335 this.guarantor = new SubscriptionGuarantor(this); 336 this.subscriptions = []; 337 } 338 create(channelName, mixin) { 339 const channel = channelName; 340 const params = typeof channel === "object" ? channel : { channel }; 341 const subscription = new Subscription(this.consumer, params, mixin); 342 return this.add(subscription); 343 } 344 add(subscription) { 345 this.subscriptions.push(subscription); 346 this.consumer.ensureActiveConnection(); 347 this.notify(subscription, "initialized"); 348 this.subscribe(subscription); 349 return subscription; 350 } 351 remove(subscription) { 352 this.forget(subscription); 353 if (!this.findAll(subscription.identifier).length) this.sendCommand(subscription, "unsubscribe"); 354 return subscription; 355 } 356 reject(identifier) { 357 return this.findAll(identifier).map(((subscription) => { 358 this.forget(subscription); 359 this.notify(subscription, "rejected"); 360 return subscription; 361 })); 362 } 363 forget(subscription) { 364 this.guarantor.forget(subscription); 365 this.subscriptions = this.subscriptions.filter(((s) => s !== subscription)); 366 return subscription; 367 } 368 findAll(identifier) { 369 return this.subscriptions.filter(((s) => s.identifier === identifier)); 370 } 371 reload() { 372 return this.subscriptions.map(((subscription) => this.subscribe(subscription))); 373 } 374 notifyAll(callbackName, ...args) { 375 return this.subscriptions.map(((subscription) => this.notify(subscription, callbackName, ...args))); 376 } 377 notify(subscription, callbackName, ...args) { 378 let subscriptions; 379 if (typeof subscription === "string") subscriptions = this.findAll(subscription); 380 else subscriptions = [subscription]; 381 return subscriptions.map(((subscription) => typeof subscription[callbackName] === "function" ? subscription[callbackName](...args) : void 0)); 382 } 383 subscribe(subscription) { 384 if (this.sendCommand(subscription, "subscribe")) this.guarantor.guarantee(subscription); 385 } 386 confirmSubscription(identifier) { 387 logger.log(`Subscription confirmed ${identifier}`); 388 this.findAll(identifier).map(((subscription) => this.guarantor.forget(subscription))); 389 } 390 sendCommand(subscription, command) { 391 const { identifier }
391 = subscription; 392 return this.consumer.send({ 393 command, 394 identifier 395 }); 396 } 397 }; 398 Consumer = class { 399 constructor(url) { 400 this._url = url; 401 this.subscriptions = new Subscriptions(this); 402 this.connection = new Connection(this); 403 this.subprotocols = []; 404 } 405 get url() { 406 return createWebSocketURL(this._url); 407 } 408 send(data) { 409 return this.connection.send(data); 410 } 411 connect() { 412 return this.connection.open(); 413 } 414 disconnect() { 415 return this.connection.close({ allowReconnect: false }); 416 } 417 ensureActiveConnection() { 418 if (!this.connection.isActive()) return this.connection.open(); 419 } 420 addSubProtocol(subprotocol) { 421 this.subprotocols = [...this.subprotocols, subprotocol]; 422 } 423 }; 424 })))(); 425} 426//#endregion 427//#region app/frontend/react/utils/actionCable.ts 428var sharedConsumer, activeUsers, disconnectTimer, disconnectConsumer, getActionCableConsumer, releaseActionCableConsumer; 429function init_actionCable() { 430 return (init_actionCable = __esmMin((() => { 431 init_actioncable_esm(); 432 sharedConsumer = null; 433 activeUsers = 0; 434 disconnectTimer = null; 435 disconnectConsumer = () => { 436 if (sharedConsumer && isFunction(sharedConsumer.disconnect)) sharedConsumer.disconnect(); 437 sharedConsumer = null; 438 disconnectTimer = null; 439 }; 440 getActionCableConsumer = () => { 441 if (disconnectTimer) { 442 window.clearTimeout(disconnectTimer); 443 disconnectTimer = null; 444 } 445 if (!sharedConsumer) sharedConsumer = createConsumer(); 446 activeUsers += 1; 447 return sharedConsumer; 448 }; 449 releaseActionCableConsumer = () => { 450 if (!sharedConsumer) return; 451 activeUsers = Math.max(activeUsers - 1, 0); 452 if (activeUsers > 0) return; 453 disconnectConsumer(); 454 }; 455 })))(); 456} 457//#endregion 458//#region app/frontend/react/hooks/useActionCable.ts 459var import_react, useActionCable; 460function init_useActionCable() { 461 return (init_useActionCable = __esmMin((() => { 462 import_react = require_react(); 463 init_actionCable(); 464 useActionCable = ({ params, callbacks, enabled = true }) => { 465 const [connected, setConnected] = (0, import_react.useState)(false); 466 (0, import_react.useRef)(null); 467 (0, import_react.useRef)(null); 468 (0, import_react.useEffect)(() => { 469 if (!enabled) return; 470 const wrappedCallbacks = { 471 ...callbacks, 472 connected: () => { 473 setConnected(true); 474 callbacks?.connected?.(); 475 }, 476 disconnected: () => { 477 setConnected(false); 478 callbacks?.disconnected?.(); 479 } 480 }; 481 const subscription = getActionCableConsumer().subscriptions.create(params, wrappedCallbacks); 482 return () => { 483 subscription.unsubscribe(); 484 releaseActionCableConsumer(); 485 setConnected(false); 486 }; 487 }, [ 488 enabled, 489 params, 490 callbacks 491 ]); 492 return { connected }; 493 }; 494 })))(); 495} 496//#endregion 497export { useActionCable as n, init_useActionCable as t };
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.