infra: add linting and formatting for js projects (#230)
* wip * wip * wip * format * wip(mobile): lint and format * cleanup * nits * nits * idiomatic react * nit * format all root files
This commit was merged in pull request #230.
This commit is contained in:
@@ -4,13 +4,13 @@
|
||||
* channel subscriptions, and event dispatching.
|
||||
*/
|
||||
|
||||
import { logError, reportError } from "@/lib/errors";
|
||||
import { logError, reportError } from '@/lib/errors';
|
||||
|
||||
export type ConnectionState =
|
||||
| "disconnected"
|
||||
| "connecting"
|
||||
| "connected"
|
||||
| "reconnecting";
|
||||
| 'disconnected'
|
||||
| 'connecting'
|
||||
| 'connected'
|
||||
| 'reconnecting';
|
||||
|
||||
export interface ChannelMessage {
|
||||
humanId: string;
|
||||
@@ -19,7 +19,7 @@ export interface ChannelMessage {
|
||||
|
||||
// Server → Client message shape
|
||||
interface ServerMessage {
|
||||
type: "subscribed" | "join" | "leave" | "message" | "error";
|
||||
type: 'subscribed' | 'join' | 'leave' | 'message' | 'error';
|
||||
channel?: string;
|
||||
humanId?: string;
|
||||
presence?: string[];
|
||||
@@ -27,7 +27,7 @@ interface ServerMessage {
|
||||
message?: string;
|
||||
}
|
||||
|
||||
type ChannelEventType = "subscribed" | "join" | "leave" | "message";
|
||||
type ChannelEventType = 'subscribed' | 'join' | 'leave' | 'message';
|
||||
type ChannelEventCallback = (msg: ServerMessage) => void;
|
||||
|
||||
interface PusherClientConfig {
|
||||
@@ -42,7 +42,7 @@ const PING_INTERVAL = 20000; // 20s — keeps alive through GKE gateway timeout
|
||||
export class PusherClient {
|
||||
private config: PusherClientConfig;
|
||||
private ws: WebSocket | null = null;
|
||||
private state: ConnectionState = "disconnected";
|
||||
private state: ConnectionState = 'disconnected';
|
||||
private stateListeners = new Set<(state: ConnectionState) => void>();
|
||||
|
||||
// Channel event listeners: channelId → eventType → callbacks
|
||||
@@ -75,20 +75,20 @@ export class PusherClient {
|
||||
|
||||
const token = this.config.getToken();
|
||||
if (!token) {
|
||||
console.warn("[pusher] no token available, cannot connect");
|
||||
console.warn('[pusher] no token available, cannot connect');
|
||||
return;
|
||||
}
|
||||
|
||||
this.shouldReconnect = true;
|
||||
this.setState(
|
||||
this.state === "reconnecting" ? "reconnecting" : "connecting",
|
||||
this.state === 'reconnecting' ? 'reconnecting' : 'connecting',
|
||||
);
|
||||
|
||||
const url = `${this.config.url}?token=${encodeURIComponent(token)}`;
|
||||
this.ws = new WebSocket(url);
|
||||
|
||||
this.ws.onopen = () => {
|
||||
this.setState("connected");
|
||||
this.setState('connected');
|
||||
this.reconnectDelay = INITIAL_RECONNECT_DELAY;
|
||||
this.startPing();
|
||||
this.resubscribeAll();
|
||||
@@ -103,7 +103,7 @@ export class PusherClient {
|
||||
|
||||
this.ws.onerror = (event) => {
|
||||
// onclose fires after onerror — reconnection is handled there.
|
||||
logError(event, { scope: "pusher.ws" });
|
||||
logError(event, { scope: 'pusher.ws' });
|
||||
};
|
||||
|
||||
this.ws.onmessage = (event) => {
|
||||
@@ -116,21 +116,21 @@ export class PusherClient {
|
||||
this.clearReconnectTimer();
|
||||
this.cleanup();
|
||||
this.activeSubscriptions.clear();
|
||||
this.setState("disconnected");
|
||||
this.setState('disconnected');
|
||||
}
|
||||
|
||||
subscribe(channelId: string): void {
|
||||
this.activeSubscriptions.add(channelId);
|
||||
this.send({ type: "subscribe", channel: channelId });
|
||||
this.send({ type: 'subscribe', channel: channelId });
|
||||
}
|
||||
|
||||
unsubscribe(channelId: string): void {
|
||||
this.activeSubscriptions.delete(channelId);
|
||||
this.send({ type: "unsubscribe", channel: channelId });
|
||||
this.send({ type: 'unsubscribe', channel: channelId });
|
||||
}
|
||||
|
||||
sendMessage(channelId: string, payload: unknown): void {
|
||||
this.send({ type: "message", channel: channelId, payload });
|
||||
this.send({ type: 'message', channel: channelId, payload });
|
||||
}
|
||||
|
||||
on(
|
||||
@@ -138,14 +138,17 @@ export class PusherClient {
|
||||
event: ChannelEventType,
|
||||
callback: ChannelEventCallback,
|
||||
): void {
|
||||
if (!this.listeners.has(channelId)) {
|
||||
this.listeners.set(channelId, new Map());
|
||||
let channelListeners = this.listeners.get(channelId);
|
||||
if (!channelListeners) {
|
||||
channelListeners = new Map();
|
||||
this.listeners.set(channelId, channelListeners);
|
||||
}
|
||||
const channelListeners = this.listeners.get(channelId)!;
|
||||
if (!channelListeners.has(event)) {
|
||||
channelListeners.set(event, new Set());
|
||||
let eventListeners = channelListeners.get(event);
|
||||
if (!eventListeners) {
|
||||
eventListeners = new Set();
|
||||
channelListeners.set(event, eventListeners);
|
||||
}
|
||||
channelListeners.get(event)!.add(callback);
|
||||
eventListeners.add(callback);
|
||||
}
|
||||
|
||||
off(
|
||||
@@ -171,7 +174,11 @@ export class PusherClient {
|
||||
|
||||
// --- Private ---
|
||||
|
||||
private send(msg: { type: string; channel?: string; payload?: unknown }): void {
|
||||
private send(msg: {
|
||||
type: string;
|
||||
channel?: string;
|
||||
payload?: unknown;
|
||||
}): void {
|
||||
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(JSON.stringify(msg));
|
||||
}
|
||||
@@ -179,19 +186,19 @@ export class PusherClient {
|
||||
|
||||
private handleMessage(data: string): void {
|
||||
// Ignore keep-alive pong responses
|
||||
if (data === "pong") return;
|
||||
if (data === 'pong') return;
|
||||
|
||||
let msg: ServerMessage;
|
||||
try {
|
||||
msg = JSON.parse(data);
|
||||
} catch (err) {
|
||||
logError(err, { scope: "pusher.parse", data });
|
||||
logError(err, { scope: 'pusher.parse', data });
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.type === "error") {
|
||||
logError(new Error(msg.message ?? "pusher server error"), {
|
||||
scope: "pusher.server",
|
||||
if (msg.type === 'error') {
|
||||
logError(new Error(msg.message ?? 'pusher server error'), {
|
||||
scope: 'pusher.server',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -209,26 +216,23 @@ export class PusherClient {
|
||||
cb(msg);
|
||||
} catch (err) {
|
||||
// Listener bugs silently break user flows — escalate to reportError.
|
||||
reportError(err, { scope: "pusher.listener", channel: msg.channel });
|
||||
reportError(err, { scope: 'pusher.listener', channel: msg.channel });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private resubscribeAll(): void {
|
||||
for (const channelId of this.activeSubscriptions) {
|
||||
this.send({ type: "subscribe", channel: channelId });
|
||||
this.send({ type: 'subscribe', channel: channelId });
|
||||
}
|
||||
}
|
||||
|
||||
private scheduleReconnect(): void {
|
||||
this.setState("reconnecting");
|
||||
this.setState('reconnecting');
|
||||
|
||||
// Exponential backoff with jitter
|
||||
const jitter = Math.random() * 0.5 + 0.75; // 0.75 - 1.25x
|
||||
const delay = Math.min(
|
||||
this.reconnectDelay * jitter,
|
||||
MAX_RECONNECT_DELAY,
|
||||
);
|
||||
const delay = Math.min(this.reconnectDelay * jitter, MAX_RECONNECT_DELAY);
|
||||
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.reconnectDelay = Math.min(
|
||||
@@ -268,7 +272,7 @@ export class PusherClient {
|
||||
this.pingTimer = setInterval(() => {
|
||||
// Send an empty message as a keep-alive
|
||||
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||
this.ws.send("ping");
|
||||
this.ws.send('ping');
|
||||
}
|
||||
}, PING_INTERVAL);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user