Skip to content
This repository was archived by the owner on Oct 9, 2025. It is now read-only.

Commit 5da7f76

Browse files
committed
Merge branch 'master' into next
# Conflicts: # test/RealtimeChannel.test.ts
2 parents 1541f3b + 2fc5162 commit 5da7f76

File tree

5 files changed

+95
-41
lines changed

5 files changed

+95
-41
lines changed

src/RealtimeClient.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -544,36 +544,47 @@ export default class RealtimeClient {
544544
this.flushSendBuffer()
545545
this.reconnectTimer.reset()
546546
if (!this.worker) {
547-
this.heartbeatTimer && clearInterval(this.heartbeatTimer)
548-
this.heartbeatTimer = setInterval(
549-
() => this.sendHeartbeat(),
550-
this.heartbeatIntervalMs
551-
)
547+
this._startHeartbeat()
552548
} else {
553-
if (this.workerUrl) {
554-
this.log('worker', `starting worker for from ${this.workerUrl}`)
555-
} else {
556-
this.log('worker', `starting default worker`)
557-
}
558-
const objectUrl = this._workerObjectUrl(this.workerUrl!)
559-
this.workerRef = new Worker(objectUrl)
560-
this.workerRef.onerror = (error) => {
561-
this.log('worker', 'worker error', (error as ErrorEvent).message)
562-
this.workerRef!.terminate()
563-
}
564-
this.workerRef.onmessage = (event) => {
565-
if (event.data.event === 'keepAlive') {
566-
this.sendHeartbeat()
567-
}
549+
if (!this.workerRef) {
550+
this._startWorkerHeartbeat()
568551
}
569-
this.workerRef.postMessage({
570-
event: 'start',
571-
interval: this.heartbeatIntervalMs,
572-
})
573552
}
553+
574554
this.stateChangeCallbacks.open.forEach((callback) => callback())
575555
}
556+
/** @internal */
557+
private _startHeartbeat() {
558+
this.heartbeatTimer && clearInterval(this.heartbeatTimer)
559+
this.heartbeatTimer = setInterval(
560+
() => this.sendHeartbeat(),
561+
this.heartbeatIntervalMs
562+
)
563+
}
576564

565+
/** @internal */
566+
private _startWorkerHeartbeat() {
567+
if (this.workerUrl) {
568+
this.log('worker', `starting worker for from ${this.workerUrl}`)
569+
} else {
570+
this.log('worker', `starting default worker`)
571+
}
572+
const objectUrl = this._workerObjectUrl(this.workerUrl!)
573+
this.workerRef = new Worker(objectUrl)
574+
this.workerRef.onerror = (error) => {
575+
this.log('worker', 'worker error', (error as ErrorEvent).message)
576+
this.workerRef!.terminate()
577+
}
578+
this.workerRef.onmessage = (event) => {
579+
if (event.data.event === 'keepAlive') {
580+
this.sendHeartbeat()
581+
}
582+
}
583+
this.workerRef.postMessage({
584+
event: 'start',
585+
interval: this.heartbeatIntervalMs,
586+
})
587+
}
577588
/** @internal */
578589
private _onConnClose(event: any) {
579590
this.log('transport', 'close', event)
Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
import assert from 'assert'
22
import sinon from 'sinon'
33
import crypto from 'crypto'
4-
import {
5-
describe,
6-
beforeEach,
7-
afterEach,
8-
test,
9-
beforeAll,
10-
afterAll,
11-
vi,
12-
it,
13-
} from 'vitest'
4+
import { describe, beforeEach, afterEach, test, vi } from 'vitest'
145

156
import RealtimeClient from '../src/RealtimeClient'
167
import RealtimeChannel from '../src/RealtimeChannel'
178
import { Response } from '@supabase/node-fetch'
18-
import Worker from 'web-worker'
199
import { Server, WebSocket } from 'mock-socket'
2010
import { CHANNEL_STATES } from '../src/lib/constants'
2111
import Push from '../src/lib/push'
Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
import assert from 'assert'
2-
import { describe, beforeEach, afterEach, test, vi, expect } from 'vitest'
2+
import {
3+
afterAll,
4+
afterEach,
5+
beforeAll,
6+
beforeEach,
7+
describe,
8+
expect,
9+
test,
10+
vi,
11+
} from 'vitest'
312
import { Server, WebSocket as MockWebSocket } from 'mock-socket'
413
import { WebSocket } from 'isows'
514
import sinon from 'sinon'
615
import crypto from 'crypto'
7-
8-
import RealtimeClient, {
9-
HeartbeatStatus,
10-
RealtimeMessage,
11-
} from '../src/RealtimeClient'
16+
import RealtimeClient, { HeartbeatStatus } from '../src/RealtimeClient'
1217
import jwt from 'jsonwebtoken'
1318
import { CHANNEL_STATES } from '../src/lib/constants'
19+
import path from 'path'
1420

1521
function generateJWT(exp: string): string {
1622
return jwt.sign({}, 'your-256-bit-secret', {
1723
algorithm: 'HS256',
1824
expiresIn: exp || '1h',
1925
})
2026
}
27+
import Worker from 'web-worker'
2128

2229
let socket: RealtimeClient
2330
let randomProjectRef = () => crypto.randomUUID()
@@ -853,3 +860,44 @@ describe('log operations', () => {
853860
)
854861
})
855862
})
863+
864+
describe('worker', () => {
865+
let mockServer: Server
866+
let client: RealtimeClient
867+
const workerPath = path.join(__dirname, 'test_worker.js')
868+
beforeAll(() => {
869+
window.Worker = Worker
870+
projectRef = randomProjectRef()
871+
url = `wss://${projectRef}/socket`
872+
mockServer = new Server(url)
873+
})
874+
875+
afterAll(() => {
876+
// @ts-ignore - Deliberately removing Worker to clean up test environment
877+
window.Worker = undefined
878+
mockServer.close()
879+
})
880+
881+
beforeEach(() => {
882+
client = new RealtimeClient('ws://localhost:8080/socket', {
883+
worker: true,
884+
workerUrl: workerPath,
885+
heartbeatIntervalMs: 10,
886+
})
887+
})
888+
test('sets worker flag', () => {
889+
assert.ok(client.worker)
890+
})
891+
892+
test('sets worker URL', () => {
893+
assert.equal(client.workerUrl, workerPath)
894+
})
895+
896+
test('ensures single worker ref is started even with multiple connect calls', () => {
897+
client._onConnOpen()
898+
let ref = client.workerRef
899+
900+
client._onConnOpen()
901+
assert.ok(ref === client.workerRef)
902+
})
903+
})

test/test_worker.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
addEventListener('message', (e) => {
2+
if (e.data.event === 'start') {
3+
setInterval(() => postMessage({ event: 'keepAlive' }), e.data.interval)
4+
}
5+
})

0 commit comments

Comments
 (0)