mirror of
https://github.com/DeBrosOfficial/network-ts-sdk.git
synced 2026-01-30 05:03:02 +00:00
fixes
This commit is contained in:
parent
25303e7913
commit
58097e3ff8
@ -1,11 +1,35 @@
|
|||||||
import { SDKError } from "../errors";
|
import { SDKError } from "../errors";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context provided to the onNetworkError callback
|
||||||
|
*/
|
||||||
|
export interface NetworkErrorContext {
|
||||||
|
method: "GET" | "POST" | "PUT" | "DELETE" | "WS";
|
||||||
|
path: string;
|
||||||
|
isRetry: boolean;
|
||||||
|
attempt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked when a network error occurs.
|
||||||
|
* Use this to trigger gateway failover or other error handling.
|
||||||
|
*/
|
||||||
|
export type NetworkErrorCallback = (
|
||||||
|
error: SDKError,
|
||||||
|
context: NetworkErrorContext
|
||||||
|
) => void;
|
||||||
|
|
||||||
export interface HttpClientConfig {
|
export interface HttpClientConfig {
|
||||||
baseURL: string;
|
baseURL: string;
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
maxRetries?: number;
|
maxRetries?: number;
|
||||||
retryDelayMs?: number;
|
retryDelayMs?: number;
|
||||||
fetch?: typeof fetch;
|
fetch?: typeof fetch;
|
||||||
|
/**
|
||||||
|
* Callback invoked on network errors (after all retries exhausted).
|
||||||
|
* Use this to trigger gateway failover at the application layer.
|
||||||
|
*/
|
||||||
|
onNetworkError?: NetworkErrorCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,6 +63,7 @@ export class HttpClient {
|
|||||||
private fetch: typeof fetch;
|
private fetch: typeof fetch;
|
||||||
private apiKey?: string;
|
private apiKey?: string;
|
||||||
private jwt?: string;
|
private jwt?: string;
|
||||||
|
private onNetworkError?: NetworkErrorCallback;
|
||||||
|
|
||||||
constructor(config: HttpClientConfig) {
|
constructor(config: HttpClientConfig) {
|
||||||
this.baseURL = config.baseURL.replace(/\/$/, "");
|
this.baseURL = config.baseURL.replace(/\/$/, "");
|
||||||
@ -47,6 +72,14 @@ export class HttpClient {
|
|||||||
this.retryDelayMs = config.retryDelayMs ?? 1000;
|
this.retryDelayMs = config.retryDelayMs ?? 1000;
|
||||||
// Use provided fetch or create one with proper TLS configuration for staging certificates
|
// Use provided fetch or create one with proper TLS configuration for staging certificates
|
||||||
this.fetch = config.fetch ?? createFetchWithTLSConfig();
|
this.fetch = config.fetch ?? createFetchWithTLSConfig();
|
||||||
|
this.onNetworkError = config.onNetworkError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the network error callback
|
||||||
|
*/
|
||||||
|
setOnNetworkError(callback: NetworkErrorCallback | undefined): void {
|
||||||
|
this.onNetworkError = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
setApiKey(apiKey?: string) {
|
setApiKey(apiKey?: string) {
|
||||||
@ -258,6 +291,27 @@ export class HttpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call the network error callback if configured
|
||||||
|
// This allows the app to trigger gateway failover
|
||||||
|
if (this.onNetworkError) {
|
||||||
|
// Convert native errors (TypeError, AbortError) to SDKError for the callback
|
||||||
|
const sdkError =
|
||||||
|
error instanceof SDKError
|
||||||
|
? error
|
||||||
|
: new SDKError(
|
||||||
|
error instanceof Error ? error.message : String(error),
|
||||||
|
0, // httpStatus 0 indicates network-level failure
|
||||||
|
"NETWORK_ERROR"
|
||||||
|
);
|
||||||
|
this.onNetworkError(sdkError, {
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
isRetry: false,
|
||||||
|
attempt: this.maxRetries, // All retries exhausted
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
@ -397,6 +451,25 @@ export class HttpClient {
|
|||||||
error
|
error
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Call the network error callback if configured
|
||||||
|
if (this.onNetworkError) {
|
||||||
|
const sdkError =
|
||||||
|
error instanceof SDKError
|
||||||
|
? error
|
||||||
|
: new SDKError(
|
||||||
|
error instanceof Error ? error.message : String(error),
|
||||||
|
0,
|
||||||
|
"NETWORK_ERROR"
|
||||||
|
);
|
||||||
|
this.onNetworkError(sdkError, {
|
||||||
|
method: "POST",
|
||||||
|
path,
|
||||||
|
isRetry: false,
|
||||||
|
attempt: this.maxRetries,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
@ -425,17 +498,33 @@ export class HttpClient {
|
|||||||
const response = await this.fetch(url.toString(), fetchOptions);
|
const response = await this.fetch(url.toString(), fetchOptions);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
const error = await response.json().catch(() => ({
|
const errorBody = await response.json().catch(() => ({
|
||||||
error: response.statusText,
|
error: response.statusText,
|
||||||
}));
|
}));
|
||||||
throw SDKError.fromResponse(response.status, error);
|
throw SDKError.fromResponse(response.status, errorBody);
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
if (error instanceof SDKError) {
|
|
||||||
throw error;
|
// Call the network error callback if configured
|
||||||
|
if (this.onNetworkError) {
|
||||||
|
const sdkError =
|
||||||
|
error instanceof SDKError
|
||||||
|
? error
|
||||||
|
: new SDKError(
|
||||||
|
error instanceof Error ? error.message : String(error),
|
||||||
|
0,
|
||||||
|
"NETWORK_ERROR"
|
||||||
|
);
|
||||||
|
this.onNetworkError(sdkError, {
|
||||||
|
method: "GET",
|
||||||
|
path,
|
||||||
|
isRetry: false,
|
||||||
|
attempt: 0,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
import WebSocket from "isomorphic-ws";
|
import WebSocket from "isomorphic-ws";
|
||||||
import { SDKError } from "../errors";
|
import { SDKError } from "../errors";
|
||||||
|
import { NetworkErrorCallback } from "./http";
|
||||||
|
|
||||||
export interface WSClientConfig {
|
export interface WSClientConfig {
|
||||||
wsURL: string;
|
wsURL: string;
|
||||||
timeout?: number;
|
timeout?: number;
|
||||||
authToken?: string;
|
authToken?: string;
|
||||||
WebSocket?: typeof WebSocket;
|
WebSocket?: typeof WebSocket;
|
||||||
|
/**
|
||||||
|
* Callback invoked on WebSocket errors.
|
||||||
|
* Use this to trigger gateway failover at the application layer.
|
||||||
|
*/
|
||||||
|
onNetworkError?: NetworkErrorCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WSMessageHandler = (data: string) => void;
|
export type WSMessageHandler = (data: string) => void;
|
||||||
@ -23,6 +29,7 @@ export class WSClient {
|
|||||||
private timeout: number;
|
private timeout: number;
|
||||||
private authToken?: string;
|
private authToken?: string;
|
||||||
private WebSocketClass: typeof WebSocket;
|
private WebSocketClass: typeof WebSocket;
|
||||||
|
private onNetworkError?: NetworkErrorCallback;
|
||||||
|
|
||||||
private ws?: WebSocket;
|
private ws?: WebSocket;
|
||||||
private messageHandlers: Set<WSMessageHandler> = new Set();
|
private messageHandlers: Set<WSMessageHandler> = new Set();
|
||||||
@ -36,6 +43,14 @@ export class WSClient {
|
|||||||
this.timeout = config.timeout ?? 30000;
|
this.timeout = config.timeout ?? 30000;
|
||||||
this.authToken = config.authToken;
|
this.authToken = config.authToken;
|
||||||
this.WebSocketClass = config.WebSocket ?? WebSocket;
|
this.WebSocketClass = config.WebSocket ?? WebSocket;
|
||||||
|
this.onNetworkError = config.onNetworkError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the network error callback
|
||||||
|
*/
|
||||||
|
setOnNetworkError(callback: NetworkErrorCallback | undefined): void {
|
||||||
|
this.onNetworkError = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,9 +72,19 @@ export class WSClient {
|
|||||||
|
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
this.ws?.close();
|
this.ws?.close();
|
||||||
reject(
|
const error = new SDKError("WebSocket connection timeout", 408, "WS_TIMEOUT");
|
||||||
new SDKError("WebSocket connection timeout", 408, "WS_TIMEOUT")
|
|
||||||
);
|
// Call the network error callback if configured
|
||||||
|
if (this.onNetworkError) {
|
||||||
|
this.onNetworkError(error, {
|
||||||
|
method: "WS",
|
||||||
|
path: this.wsURL,
|
||||||
|
isRetry: false,
|
||||||
|
attempt: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
reject(error);
|
||||||
}, this.timeout);
|
}, this.timeout);
|
||||||
|
|
||||||
this.ws.addEventListener("open", () => {
|
this.ws.addEventListener("open", () => {
|
||||||
@ -78,6 +103,17 @@ export class WSClient {
|
|||||||
console.error("[WSClient] WebSocket error:", event);
|
console.error("[WSClient] WebSocket error:", event);
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
const error = new SDKError("WebSocket error", 500, "WS_ERROR", event);
|
const error = new SDKError("WebSocket error", 500, "WS_ERROR", event);
|
||||||
|
|
||||||
|
// Call the network error callback if configured
|
||||||
|
if (this.onNetworkError) {
|
||||||
|
this.onNetworkError(error, {
|
||||||
|
method: "WS",
|
||||||
|
path: this.wsURL,
|
||||||
|
isRetry: false,
|
||||||
|
attempt: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.errorHandlers.forEach((handler) => handler(error));
|
this.errorHandlers.forEach((handler) => handler(error));
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
|
|||||||
10
src/index.ts
10
src/index.ts
@ -1,4 +1,4 @@
|
|||||||
import { HttpClient, HttpClientConfig } from "./core/http";
|
import { HttpClient, HttpClientConfig, NetworkErrorCallback } from "./core/http";
|
||||||
import { AuthClient } from "./auth/client";
|
import { AuthClient } from "./auth/client";
|
||||||
import { DBClient } from "./db/client";
|
import { DBClient } from "./db/client";
|
||||||
import { PubSubClient } from "./pubsub/client";
|
import { PubSubClient } from "./pubsub/client";
|
||||||
@ -20,6 +20,11 @@ export interface ClientConfig extends Omit<HttpClientConfig, "fetch"> {
|
|||||||
wsConfig?: Partial<Omit<WSClientConfig, "wsURL">>;
|
wsConfig?: Partial<Omit<WSClientConfig, "wsURL">>;
|
||||||
functionsConfig?: FunctionsClientConfig;
|
functionsConfig?: FunctionsClientConfig;
|
||||||
fetch?: typeof fetch;
|
fetch?: typeof fetch;
|
||||||
|
/**
|
||||||
|
* Callback invoked on network errors (HTTP and WebSocket).
|
||||||
|
* Use this to trigger gateway failover at the application layer.
|
||||||
|
*/
|
||||||
|
onNetworkError?: NetworkErrorCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Client {
|
export interface Client {
|
||||||
@ -39,6 +44,7 @@ export function createClient(config: ClientConfig): Client {
|
|||||||
maxRetries: config.maxRetries,
|
maxRetries: config.maxRetries,
|
||||||
retryDelayMs: config.retryDelayMs,
|
retryDelayMs: config.retryDelayMs,
|
||||||
fetch: config.fetch,
|
fetch: config.fetch,
|
||||||
|
onNetworkError: config.onNetworkError,
|
||||||
});
|
});
|
||||||
|
|
||||||
const auth = new AuthClient({
|
const auth = new AuthClient({
|
||||||
@ -55,6 +61,7 @@ export function createClient(config: ClientConfig): Client {
|
|||||||
const pubsub = new PubSubClient(httpClient, {
|
const pubsub = new PubSubClient(httpClient, {
|
||||||
...config.wsConfig,
|
...config.wsConfig,
|
||||||
wsURL,
|
wsURL,
|
||||||
|
onNetworkError: config.onNetworkError,
|
||||||
});
|
});
|
||||||
const network = new NetworkClient(httpClient);
|
const network = new NetworkClient(httpClient);
|
||||||
const cache = new CacheClient(httpClient);
|
const cache = new CacheClient(httpClient);
|
||||||
@ -73,6 +80,7 @@ export function createClient(config: ClientConfig): Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export { HttpClient } from "./core/http";
|
export { HttpClient } from "./core/http";
|
||||||
|
export type { NetworkErrorCallback, NetworkErrorContext } from "./core/http";
|
||||||
export { WSClient } from "./core/ws";
|
export { WSClient } from "./core/ws";
|
||||||
export { AuthClient } from "./auth/client";
|
export { AuthClient } from "./auth/client";
|
||||||
export { DBClient } from "./db/client";
|
export { DBClient } from "./db/client";
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user