PageSourceSearch

https://voice-notes.online/assets/actioncable.esm-b66d83871f0a453b…147c2bafa655caaa5d13fa34e9bf361c1c2aedb7.js

js voice-notes.online collected 2026-09-24 14:25:32 UTC 14,813 bytes, 512 lines download raw bytes

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

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.