-
-
Notifications
You must be signed in to change notification settings - Fork 516
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: use different websocket client store in browser and node
- Loading branch information
1 parent
a50bed2
commit 434e4cf
Showing
5 changed files
with
200 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import type { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/WebSocket' | ||
|
||
export type SerializedWebSocketClient = { | ||
id: string | ||
url: string | ||
} | ||
|
||
export abstract class WebSocketClientStore { | ||
public abstract add(client: WebSocketClientConnectionProtocol): Promise<void> | ||
|
||
public abstract getAll(): Promise<Array<SerializedWebSocketClient>> | ||
|
||
public abstract deleteMany(clientIds: Array<string>): Promise<void> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { DeferredPromise } from '@open-draft/deferred-promise' | ||
import { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket' | ||
import { | ||
type SerializedWebSocketClient, | ||
WebSocketClientStore, | ||
} from './WebSocketClientStore' | ||
|
||
const DB_NAME = 'msw-websocket-clients' | ||
const DB_STORE_NAME = 'clients' | ||
|
||
export class WebSocketIndexedDBClientStore implements WebSocketClientStore { | ||
private db: Promise<IDBDatabase> | ||
|
||
constructor() { | ||
this.db = this.createDatabase() | ||
} | ||
|
||
public async add(client: WebSocketClientConnectionProtocol): Promise<void> { | ||
const promise = new DeferredPromise<void>() | ||
const store = await this.getStore() | ||
const request = store.add({ | ||
id: client.id, | ||
url: client.url.href, | ||
} satisfies SerializedWebSocketClient) | ||
|
||
request.onsuccess = () => { | ||
promise.resolve() | ||
} | ||
request.onerror = () => { | ||
promise.reject(new Error(`Failed to add WebSocket client ${client.id}`)) | ||
} | ||
|
||
return promise | ||
} | ||
|
||
public async getAll(): Promise<Array<SerializedWebSocketClient>> { | ||
const promise = new DeferredPromise<Array<SerializedWebSocketClient>>() | ||
const store = await this.getStore() | ||
const request = store.getAll() as IDBRequest< | ||
Array<SerializedWebSocketClient> | ||
> | ||
|
||
request.onsuccess = () => { | ||
promise.resolve(request.result) | ||
} | ||
request.onerror = () => { | ||
promise.reject(new Error(`Failed to get all WebSocket clients`)) | ||
} | ||
|
||
return promise | ||
} | ||
|
||
public async deleteMany(clientIds: Array<string>): Promise<void> { | ||
const promise = new DeferredPromise<void>() | ||
const store = await this.getStore() | ||
|
||
for (const clientId of clientIds) { | ||
store.delete(clientId) | ||
} | ||
|
||
store.transaction.oncomplete = () => { | ||
promise.resolve() | ||
} | ||
store.transaction.onerror = () => { | ||
promise.reject( | ||
new Error( | ||
`Failed to delete WebSocket clients [${clientIds.join(', ')}]`, | ||
), | ||
) | ||
} | ||
|
||
return promise | ||
} | ||
|
||
private async createDatabase(): Promise<IDBDatabase> { | ||
const promise = new DeferredPromise<IDBDatabase>() | ||
const request = indexedDB.open(DB_NAME, 1) | ||
|
||
request.onsuccess = ({ currentTarget }) => { | ||
const db = Reflect.get(currentTarget!, 'result') as IDBDatabase | ||
|
||
if (db.objectStoreNames.contains(DB_STORE_NAME)) { | ||
return promise.resolve(db) | ||
} | ||
} | ||
|
||
request.onupgradeneeded = async ({ currentTarget }) => { | ||
const db = Reflect.get(currentTarget!, 'result') as IDBDatabase | ||
if (db.objectStoreNames.contains(DB_STORE_NAME)) { | ||
return | ||
} | ||
|
||
const store = db.createObjectStore(DB_STORE_NAME, { keyPath: 'id' }) | ||
store.transaction.oncomplete = () => { | ||
promise.resolve(db) | ||
} | ||
store.transaction.onerror = () => { | ||
promise.reject(new Error('Failed to create WebSocket client store')) | ||
} | ||
} | ||
request.onerror = () => { | ||
promise.reject(new Error('Failed to open an IndexedDB database')) | ||
} | ||
|
||
return promise | ||
} | ||
|
||
private async getStore(): Promise<IDBObjectStore> { | ||
const db = await this.db | ||
return db.transaction(DB_STORE_NAME, 'readwrite').objectStore(DB_STORE_NAME) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket' | ||
import { | ||
SerializedWebSocketClient, | ||
WebSocketClientStore, | ||
} from './WebSocketClientStore' | ||
|
||
export class WebSocketMemoryClientStore implements WebSocketClientStore { | ||
private store: Map<string, SerializedWebSocketClient> | ||
|
||
constructor() { | ||
this.store = new Map() | ||
} | ||
|
||
public async add(client: WebSocketClientConnectionProtocol): Promise<void> { | ||
this.store.set(client.id, { id: client.id, url: client.url.href }) | ||
} | ||
|
||
public getAll(): Promise<Array<SerializedWebSocketClient>> { | ||
return Promise.resolve(Array.from(this.store.values())) | ||
} | ||
|
||
public async deleteMany(clientIds: Array<string>): Promise<void> { | ||
for (const clientId of clientIds) { | ||
this.store.delete(clientId) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters