Mid-rewrite
This commit is contained in:
91
src/utils/sync-server.ts
Normal file
91
src/utils/sync-server.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import type { XOInvitation } from "@xo-cash/types";
|
||||
import { EventEmitter } from "./event-emitter.js";
|
||||
import { SSESession, type SSEvent } from "./sse-client.js";
|
||||
import { decodeExtendedJsonObject, encodeExtendedJson } from "./ext-json.js";
|
||||
|
||||
export type SyncServerEventMap = {
|
||||
'connected': void;
|
||||
'disconnected': void;
|
||||
'error': Error;
|
||||
'message': SSEvent;
|
||||
}
|
||||
|
||||
export class SyncServer extends EventEmitter<SyncServerEventMap> {
|
||||
static async from(baseUrl: string, invitationIdentifier: string): Promise<SyncServer> {
|
||||
const server = new SyncServer(baseUrl, invitationIdentifier);
|
||||
await server.connect();
|
||||
return server;
|
||||
}
|
||||
|
||||
private sse: SSESession;
|
||||
|
||||
constructor(private readonly baseUrl: string, private readonly invitationIdentifier: string) {
|
||||
super();
|
||||
|
||||
// Create an SSE Session
|
||||
this.sse = new SSESession(`${baseUrl}/invitations?invitationIdentifier=${invitationIdentifier}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'text/event-stream',
|
||||
},
|
||||
|
||||
// Create our event bubblers
|
||||
onMessage: (event: SSEvent) => this.emit('message', event),
|
||||
onError: (error: unknown) => this.emit('error', error instanceof Error ? error : new Error(String(error))),
|
||||
onDisconnected: () => this.emit('disconnected', undefined),
|
||||
onConnected: () => this.emit('connected', undefined),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the sync server.
|
||||
*/
|
||||
async connect(): Promise<void> {
|
||||
// Connect to the SSE Session
|
||||
await this.sse.connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the sync server.
|
||||
*/
|
||||
async disconnect(): Promise<void> {
|
||||
// Disconnect from the SSE Session
|
||||
this.sse.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invitation by identifier.
|
||||
* @param identifier - The invitation identifier.
|
||||
* @returns The invitation.
|
||||
*/
|
||||
async getInvitation(identifier: string): Promise<XOInvitation> {
|
||||
// Send a GET request to the sync server
|
||||
const response = await fetch(`${this.baseUrl}/invitations/${identifier}`);
|
||||
const invitation = await response.json() as XOInvitation;
|
||||
return invitation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish an invitation.
|
||||
* @param invitation - The invitation to create.
|
||||
* @returns The invitation.
|
||||
*/
|
||||
async publishInvitation(invitation: XOInvitation): Promise<XOInvitation> {
|
||||
// Send a POST request to the sync server
|
||||
const response = await fetch(`${this.baseUrl}/invitations`, {
|
||||
method: 'POST',
|
||||
body: encodeExtendedJson(invitation),
|
||||
});
|
||||
|
||||
// Throw is there was an issue with the request
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to publish invitation: ${response.statusText}`);
|
||||
}
|
||||
|
||||
// Read the returned JSON
|
||||
// TODO: This should use zod to verify the response
|
||||
const data = decodeExtendedJsonObject(await response.text()) as XOInvitation;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user