chaingate
Version:
Multi-chain cryptocurrency SDK for TypeScript — unified API for Bitcoin, Ethereum, Litecoin, Dogecoin, Bitcoin Cash, Polygon, Arbitrum, and any EVM-compatible chain. Create wallets, query balances, send transactions, and manage tokens and NFTs across UTXO
139 lines (138 loc) • 6.49 kB
JavaScript
;
/* eslint-disable @typescript-eslint/no-explicit-any */
// This file is auto-generated by @hey-api/openapi-ts
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSseClient = void 0;
const createSseClient = ({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) => {
let lastEventId;
const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
const createStream = async function* () {
let retryDelay = sseDefaultRetryDelay ?? 3000;
let attempt = 0;
const signal = options.signal ?? new AbortController().signal;
while (true) {
if (signal.aborted)
break;
attempt++;
const headers = options.headers instanceof Headers
? options.headers
: new Headers(options.headers);
if (lastEventId !== undefined) {
headers.set('Last-Event-ID', lastEventId);
}
try {
const requestInit = {
redirect: 'follow',
...options,
body: options.serializedBody,
headers,
signal,
};
let request = new Request(url, requestInit);
if (onRequest) {
request = await onRequest(url, requestInit);
}
// fetch must be assigned here, otherwise it would throw the error:
// TypeError: Failed to execute 'fetch' on 'Window': Illegal invocation
const _fetch = options.fetch ?? globalThis.fetch;
const response = await _fetch(request);
if (!response.ok)
throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
if (!response.body)
throw new Error('No body in SSE response');
const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = '';
const abortHandler = () => {
try {
reader.cancel();
}
catch {
// noop
}
};
signal.addEventListener('abort', abortHandler);
try {
while (true) {
const { done, value } = await reader.read();
if (done)
break;
buffer += value;
// Normalize line endings: CRLF -> LF, then CR -> LF
buffer = buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
const chunks = buffer.split('\n\n');
buffer = chunks.pop() ?? '';
for (const chunk of chunks) {
const lines = chunk.split('\n');
const dataLines = [];
let eventName;
for (const line of lines) {
if (line.startsWith('data:')) {
dataLines.push(line.replace(/^data:\s*/, ''));
}
else if (line.startsWith('event:')) {
eventName = line.replace(/^event:\s*/, '');
}
else if (line.startsWith('id:')) {
lastEventId = line.replace(/^id:\s*/, '');
}
else if (line.startsWith('retry:')) {
const parsed = Number.parseInt(line.replace(/^retry:\s*/, ''), 10);
if (!Number.isNaN(parsed)) {
retryDelay = parsed;
}
}
}
let data;
let parsedJson = false;
if (dataLines.length) {
const rawData = dataLines.join('\n');
try {
data = JSON.parse(rawData);
parsedJson = true;
}
catch {
data = rawData;
}
}
if (parsedJson) {
if (responseValidator) {
await responseValidator(data);
}
if (responseTransformer) {
data = await responseTransformer(data);
}
}
onSseEvent?.({
data,
event: eventName,
id: lastEventId,
retry: retryDelay,
});
if (dataLines.length) {
yield data;
}
}
}
}
finally {
signal.removeEventListener('abort', abortHandler);
reader.releaseLock();
}
break; // exit loop on normal completion
}
catch (error) {
// connection failed or aborted; retry after delay
onSseError?.(error);
if (sseMaxRetryAttempts !== undefined && attempt >= sseMaxRetryAttempts) {
break; // stop after firing error
}
// exponential backoff: double retry each attempt, cap at 30s
const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 30000);
await sleep(backoff);
}
}
};
const stream = createStream();
return { stream };
};
exports.createSseClient = createSseClient;