🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
DemoInstallSign in
Socket

@crosspost/sdk

Package Overview
Dependencies
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@crosspost/sdk - npm Package Compare versions

Comparing version

to
0.1.9

9

dist/index.d.ts

@@ -27,6 +27,2 @@ import { NearAuthData } from 'near-sign-verify';

timeout: number;
/**
* Number of retries for failed requests
*/
retries: number;
}

@@ -232,7 +228,2 @@

timeout?: number;
/**
* Number of retries for failed requests (specifically for network errors or 5xx status codes)
* @default 2
*/
retries?: number;
}

@@ -239,0 +230,0 @@

2

package.json
{
"name": "@crosspost/sdk",
"version": "0.1.8",
"version": "0.1.9",
"description": "SDK for interacting with the Crosspost API",

@@ -5,0 +5,0 @@ "type": "module",

@@ -27,3 +27,2 @@ import type { NearAuthData } from 'near-sign-verify';

const timeout = config.timeout || DEFAULT_CONFIG.timeout;
const retries = config.retries ?? DEFAULT_CONFIG.retries;

@@ -35,3 +34,2 @@ const nearAuthData = config.nearAuthData;

timeout,
retries,
nearAuthData,

@@ -38,0 +36,0 @@ };

@@ -21,7 +21,2 @@ import type { NearAuthData } from 'near-sign-verify';

timeout?: number;
/**
* Number of retries for failed requests (specifically for network errors or 5xx status codes)
* @default 2
*/
retries?: number;
}

@@ -35,3 +30,2 @@

timeout: 30000,
retries: 2,
};
import { ApiErrorCode, type StatusCode } from '@crosspost/types';
import { createAuthToken, type NearAuthData } from 'near-sign-verify';
import {
apiWrapper,
createNetworkError,
CrosspostError,
enrichErrorWithContext,
handleErrorResponse,

@@ -32,10 +32,6 @@ } from '../utils/error.ts';

timeout: number;
/**
* Number of retries for failed requests
*/
retries: number;
}
/**
* Makes a request to the API with retry and error handling
* Makes a request to the API with error handling
*

@@ -80,129 +76,116 @@ * @param method The HTTP method

url,
retries: options.retries,
};
return apiWrapper(async () => {
let lastError: Error | null = null;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
for (let attempt = 0; attempt <= options.retries; attempt++) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
try {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
// For GET requests, use X-Near-Account header if available
if (method === 'GET') {
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
if (!nearAccount) {
throw new CrosspostError(
'No NEAR account provided for GET request',
ApiErrorCode.UNAUTHORIZED,
401,
);
}
headers['X-Near-Account'] = nearAccount;
} else {
// For non-GET requests, require nearAuthData
if (!options.nearAuthData) {
throw new CrosspostError(
'NEAR authentication data required for non-GET request',
ApiErrorCode.UNAUTHORIZED,
401,
);
}
headers['Authorization'] = `Bearer ${createAuthToken(options.nearAuthData)}`;
}
// For GET requests, use X-Near-Account header if available
if (method === 'GET') {
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
if (!nearAccount) {
throw new CrosspostError(
'No NEAR account provided for GET request',
ApiErrorCode.UNAUTHORIZED,
401,
);
}
headers['X-Near-Account'] = nearAccount;
} else {
// For non-GET requests, require nearAuthData
if (!options.nearAuthData) {
throw new CrosspostError(
'NEAR authentication data required for non-GET request',
ApiErrorCode.UNAUTHORIZED,
401,
);
}
headers['Authorization'] = `Bearer ${createAuthToken(options.nearAuthData)}`;
}
const requestOptions: RequestInit = {
method,
headers,
body: method !== 'GET' && data ? JSON.stringify(data) : undefined,
signal: controller.signal,
};
const requestOptions: RequestInit = {
method,
headers,
body: method !== 'GET' && data ? JSON.stringify(data) : undefined,
signal: controller.signal,
};
const response = await fetch(url, requestOptions);
clearTimeout(timeoutId);
const response = await fetch(url, requestOptions);
clearTimeout(timeoutId); // Clear timeout if fetch completes
let responseData: any;
try {
responseData = await response.json();
} catch (jsonError) {
// JSON parsing failed - try to get response text for context
let responseText: string | undefined;
try {
responseText = await response.text();
} catch (_) { /* ignore */ }
let responseData: any;
try {
responseData = await response.json();
} catch (jsonError) {
// If JSON parsing fails, did API throw an error?
if (!response.ok) {
throw new CrosspostError(
`API request failed with status ${response.status} and non-JSON response`,
ApiErrorCode.NETWORK_ERROR,
response.status as StatusCode,
{ originalStatusText: response.statusText },
);
}
// Otherwise, throw a custom error
throw new CrosspostError(
`Failed to parse JSON response: ${
jsonError instanceof Error ? jsonError.message : String(jsonError)
}`,
ApiErrorCode.INTERNAL_ERROR,
response.status as StatusCode,
);
}
throw new CrosspostError(
`API request failed with status ${response.status} and non-JSON response`,
ApiErrorCode.INVALID_RESPONSE,
response.status as StatusCode,
{
originalStatusText: response.statusText,
originalError: jsonError instanceof Error ? jsonError.message : String(jsonError),
responseText,
},
);
}
if (!response.ok) {
lastError = handleErrorResponse(responseData, response.status);
// Only retry rate limit errors
const shouldRetry = lastError instanceof CrosspostError &&
lastError.code === ApiErrorCode.RATE_LIMITED;
if (shouldRetry && attempt < options.retries) {
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
continue; // Retry
}
throw lastError; // Throw error if not retrying or retries exhausted
}
// Handle non-ok responses (4xx/5xx)
if (!response.ok) {
throw handleErrorResponse(responseData, response.status);
}
// Handle response based on success flag
if (responseData && typeof responseData === 'object' && 'success' in responseData) {
if (responseData.success) {
// Success response - return the data
return responseData.data as TResponse;
} else {
// Error response - handle with our error utilities
lastError = handleErrorResponse(responseData, response.status);
// Only retry rate limit errors
const shouldRetry = lastError instanceof CrosspostError &&
lastError.code === ApiErrorCode.RATE_LIMITED;
if (shouldRetry && attempt < options.retries) {
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
continue; // Retry
}
throw lastError;
}
}
} catch (error) {
clearTimeout(timeoutId); // Clear timeout on error
lastError = error instanceof Error ? error : new Error(String(error)); // Store the error
// Validate success response structure
if (!responseData || typeof responseData !== 'object' || !('success' in responseData)) {
throw new CrosspostError(
'Invalid success response format from API',
ApiErrorCode.INVALID_RESPONSE,
response.status as StatusCode,
{ responseData },
);
}
// Handle fetch/network errors specifically for retries
const isNetworkError = error instanceof TypeError ||
(error instanceof DOMException && error.name === 'AbortError');
if (isNetworkError && attempt < options.retries) {
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
continue; // Retry network error
}
if (responseData.success) {
return responseData.data as TResponse;
}
// If it's not a known ApiError/PlatformError, wrap it
if (!(error instanceof CrosspostError)) {
throw createNetworkError(error, url, options.timeout);
}
// If we get here, we have response.ok but success: false
// This is unexpected - treat as an error
throw handleErrorResponse(responseData, response.status);
} catch (error) {
clearTimeout(timeoutId);
throw error; // Re-throw known ApiError or final network error
}
if (error instanceof CrosspostError) {
// Enrich CrosspostError with request context
throw enrichErrorWithContext(error, context);
}
// Should not be reachable if retries >= 0, but needed for type safety
throw lastError ||
new CrosspostError('Request failed after multiple retries', ApiErrorCode.INTERNAL_ERROR, 500);
}, context);
// Handle network errors (including timeouts)
if (
error instanceof TypeError || (error instanceof DOMException && error.name === 'AbortError')
) {
throw enrichErrorWithContext(createNetworkError(error, url, options.timeout), context);
}
// For any other errors, wrap them with context
throw enrichErrorWithContext(
new CrosspostError(
error instanceof Error ? error.message : String(error),
ApiErrorCode.INTERNAL_ERROR,
500,
{ originalError: String(error) },
),
context,
);
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display