@crosspost/sdk 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +484 -681
- package/dist/index.d.cts +70 -89
- package/dist/index.d.ts +70 -89
- package/dist/index.js +476 -655
- package/package.json +1 -1
- package/src/api/activity.ts +3 -3
- package/src/api/auth.ts +44 -18
- package/src/api/post.ts +10 -22
- package/src/api/system.ts +12 -5
- package/src/core/client.ts +40 -1
- package/src/core/request.ts +71 -39
- package/src/index.ts +0 -10
- package/src/utils/error.ts +150 -247
package/package.json
CHANGED
package/src/api/activity.ts
CHANGED
@@ -28,7 +28,7 @@ export class ActivityApi {
|
|
28
28
|
* @returns A promise resolving with the leaderboard response
|
29
29
|
*/
|
30
30
|
async getLeaderboard(query?: ActivityLeaderboardQuery): Promise<ActivityLeaderboardResponse> {
|
31
|
-
return makeRequest<ActivityLeaderboardResponse>(
|
31
|
+
return makeRequest<ActivityLeaderboardResponse, never, ActivityLeaderboardQuery>(
|
32
32
|
'GET',
|
33
33
|
'/api/activity',
|
34
34
|
this.options,
|
@@ -47,7 +47,7 @@ export class ActivityApi {
|
|
47
47
|
signerId: string,
|
48
48
|
query?: AccountActivityQuery,
|
49
49
|
): Promise<AccountActivityResponse> {
|
50
|
-
return makeRequest<AccountActivityResponse>(
|
50
|
+
return makeRequest<AccountActivityResponse, never, AccountActivityQuery>(
|
51
51
|
'GET',
|
52
52
|
`/api/activity/${signerId}`,
|
53
53
|
this.options,
|
@@ -66,7 +66,7 @@ export class ActivityApi {
|
|
66
66
|
signerId: string,
|
67
67
|
query?: AccountPostsQuery,
|
68
68
|
): Promise<AccountPostsResponse> {
|
69
|
-
return makeRequest<AccountPostsResponse>(
|
69
|
+
return makeRequest<AccountPostsResponse, never, AccountPostsQuery>(
|
70
70
|
'GET',
|
71
71
|
`/api/activity/${signerId}/posts`,
|
72
72
|
this.options,
|
package/src/api/auth.ts
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
import type {
|
2
|
+
AuthCallbackResponse,
|
3
|
+
AuthInitRequest,
|
2
4
|
AuthRevokeResponse,
|
5
|
+
AuthStatusParams,
|
3
6
|
AuthStatusResponse,
|
7
|
+
AuthTokenRequest,
|
8
|
+
AuthUrlResponse,
|
9
|
+
ConnectedAccount,
|
4
10
|
ConnectedAccountsResponse,
|
5
|
-
|
11
|
+
NearAuthorizationRequest,
|
6
12
|
NearAuthorizationResponse,
|
13
|
+
NearUnauthorizationResponse,
|
7
14
|
Platform,
|
8
15
|
} from '@crosspost/types';
|
9
16
|
import { makeRequest, type RequestOptions } from '../core/request.ts';
|
@@ -27,7 +34,7 @@ export class AuthApi {
|
|
27
34
|
* @returns A promise resolving with the authorization response.
|
28
35
|
*/
|
29
36
|
async authorizeNearAccount(): Promise<NearAuthorizationResponse> {
|
30
|
-
return makeRequest<NearAuthorizationResponse>(
|
37
|
+
return makeRequest<NearAuthorizationResponse, NearAuthorizationRequest>(
|
31
38
|
'POST',
|
32
39
|
'/auth/authorize/near',
|
33
40
|
this.options,
|
@@ -40,7 +47,7 @@ export class AuthApi {
|
|
40
47
|
* @returns A promise resolving with the authorization status response.
|
41
48
|
*/
|
42
49
|
async getNearAuthorizationStatus(): Promise<NearAuthorizationResponse> {
|
43
|
-
return makeRequest<NearAuthorizationResponse>(
|
50
|
+
return makeRequest<NearAuthorizationResponse, never>(
|
44
51
|
'GET',
|
45
52
|
'/auth/authorize/near/status',
|
46
53
|
this.options,
|
@@ -56,9 +63,9 @@ export class AuthApi {
|
|
56
63
|
*/
|
57
64
|
async loginToPlatform(
|
58
65
|
platform: Platform,
|
59
|
-
options?:
|
60
|
-
): Promise<
|
61
|
-
return makeRequest<
|
66
|
+
options?: AuthInitRequest,
|
67
|
+
): Promise<AuthUrlResponse> {
|
68
|
+
return makeRequest<AuthUrlResponse, AuthInitRequest>(
|
62
69
|
'POST',
|
63
70
|
`/auth/${platform}/login`,
|
64
71
|
this.options,
|
@@ -69,26 +76,29 @@ export class AuthApi {
|
|
69
76
|
/**
|
70
77
|
* Refreshes the authentication token for the specified platform.
|
71
78
|
* @param platform The target platform.
|
72
|
-
* @returns A promise resolving with the refresh response.
|
79
|
+
* @returns A promise resolving with the refresh response containing updated auth details.
|
73
80
|
*/
|
74
|
-
async refreshToken(platform: Platform): Promise<
|
75
|
-
return makeRequest<
|
81
|
+
async refreshToken(platform: Platform, userId: string): Promise<AuthCallbackResponse> {
|
82
|
+
return makeRequest<AuthCallbackResponse, AuthTokenRequest>(
|
76
83
|
'POST',
|
77
84
|
`/auth/${platform}/refresh`,
|
78
85
|
this.options,
|
86
|
+
{ userId },
|
79
87
|
);
|
80
88
|
}
|
81
89
|
|
82
90
|
/**
|
83
91
|
* Refreshes the user's profile information from the specified platform.
|
84
92
|
* @param platform The target platform.
|
85
|
-
* @
|
93
|
+
* @param userId The user ID on the platform
|
94
|
+
* @returns A promise resolving with the updated account profile information.
|
86
95
|
*/
|
87
|
-
async refreshProfile(platform: Platform): Promise<
|
88
|
-
return makeRequest<
|
96
|
+
async refreshProfile(platform: Platform, userId: string): Promise<ConnectedAccount> {
|
97
|
+
return makeRequest<ConnectedAccount, AuthTokenRequest>(
|
89
98
|
'POST',
|
90
99
|
`/auth/${platform}/refresh-profile`,
|
91
100
|
this.options,
|
101
|
+
{ userId },
|
92
102
|
);
|
93
103
|
}
|
94
104
|
|
@@ -97,11 +107,26 @@ export class AuthApi {
|
|
97
107
|
* @param platform The target platform.
|
98
108
|
* @returns A promise resolving with the authentication status response.
|
99
109
|
*/
|
100
|
-
async getAuthStatus(platform: Platform): Promise<AuthStatusResponse> {
|
101
|
-
return makeRequest<AuthStatusResponse>(
|
110
|
+
async getAuthStatus(platform: Platform, userId: string): Promise<AuthStatusResponse> {
|
111
|
+
return makeRequest<AuthStatusResponse, never, AuthStatusParams>(
|
102
112
|
'GET',
|
103
|
-
`/auth/${platform}/status`,
|
113
|
+
`/auth/${platform}/status/${userId}`,
|
104
114
|
this.options,
|
115
|
+
undefined,
|
116
|
+
{ platform, userId },
|
117
|
+
);
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Unauthorizes a NEAR account from using the service
|
122
|
+
* @returns A promise resolving with the unauthorized response
|
123
|
+
*/
|
124
|
+
async unauthorizeNear(): Promise<NearUnauthorizationResponse> {
|
125
|
+
return makeRequest<NearUnauthorizationResponse, NearAuthorizationRequest>(
|
126
|
+
'DELETE',
|
127
|
+
'/auth/unauthorize/near',
|
128
|
+
this.options,
|
129
|
+
{},
|
105
130
|
);
|
106
131
|
}
|
107
132
|
|
@@ -110,11 +135,12 @@ export class AuthApi {
|
|
110
135
|
* @param platform The target platform.
|
111
136
|
* @returns A promise resolving with the revocation response.
|
112
137
|
*/
|
113
|
-
async revokeAuth(platform: Platform): Promise<AuthRevokeResponse> {
|
114
|
-
return makeRequest<AuthRevokeResponse>(
|
138
|
+
async revokeAuth(platform: Platform, userId: string): Promise<AuthRevokeResponse> {
|
139
|
+
return makeRequest<AuthRevokeResponse, AuthTokenRequest>(
|
115
140
|
'DELETE',
|
116
141
|
`/auth/${platform}/revoke`,
|
117
142
|
this.options,
|
143
|
+
{ userId },
|
118
144
|
);
|
119
145
|
}
|
120
146
|
|
@@ -123,7 +149,7 @@ export class AuthApi {
|
|
123
149
|
* @returns A promise resolving with the list of connected accounts.
|
124
150
|
*/
|
125
151
|
async getConnectedAccounts(): Promise<ConnectedAccountsResponse> {
|
126
|
-
return makeRequest<ConnectedAccountsResponse>(
|
152
|
+
return makeRequest<ConnectedAccountsResponse, never>(
|
127
153
|
'GET',
|
128
154
|
'/auth/accounts',
|
129
155
|
this.options,
|
package/src/api/post.ts
CHANGED
@@ -14,7 +14,6 @@ import type {
|
|
14
14
|
UnlikePostRequest,
|
15
15
|
UnlikePostResponse,
|
16
16
|
} from '@crosspost/types';
|
17
|
-
import { ApiError, ApiErrorCode } from '@crosspost/types';
|
18
17
|
import { makeRequest, type RequestOptions } from '../core/request.ts';
|
19
18
|
|
20
19
|
/**
|
@@ -37,7 +36,7 @@ export class PostApi {
|
|
37
36
|
* @returns A promise resolving with the post creation response.
|
38
37
|
*/
|
39
38
|
async createPost(request: CreatePostRequest): Promise<CreatePostResponse> {
|
40
|
-
return makeRequest<CreatePostResponse>(
|
39
|
+
return makeRequest<CreatePostResponse, CreatePostRequest>(
|
41
40
|
'POST',
|
42
41
|
'/api/post',
|
43
42
|
this.options,
|
@@ -51,7 +50,7 @@ export class PostApi {
|
|
51
50
|
* @returns A promise resolving with the repost response.
|
52
51
|
*/
|
53
52
|
async repost(request: RepostRequest): Promise<RepostResponse> {
|
54
|
-
return makeRequest<RepostResponse>(
|
53
|
+
return makeRequest<RepostResponse, RepostRequest>(
|
55
54
|
'POST',
|
56
55
|
'/api/post/repost',
|
57
56
|
this.options,
|
@@ -65,7 +64,7 @@ export class PostApi {
|
|
65
64
|
* @returns A promise resolving with the quote post response.
|
66
65
|
*/
|
67
66
|
async quotePost(request: QuotePostRequest): Promise<QuotePostResponse> {
|
68
|
-
return makeRequest<QuotePostResponse>(
|
67
|
+
return makeRequest<QuotePostResponse, QuotePostRequest>(
|
69
68
|
'POST',
|
70
69
|
'/api/post/quote',
|
71
70
|
this.options,
|
@@ -79,7 +78,7 @@ export class PostApi {
|
|
79
78
|
* @returns A promise resolving with the reply response.
|
80
79
|
*/
|
81
80
|
async replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse> {
|
82
|
-
return makeRequest<ReplyToPostResponse>(
|
81
|
+
return makeRequest<ReplyToPostResponse, ReplyToPostRequest>(
|
83
82
|
'POST',
|
84
83
|
'/api/post/reply',
|
85
84
|
this.options,
|
@@ -93,10 +92,9 @@ export class PostApi {
|
|
93
92
|
* @returns A promise resolving with the like response.
|
94
93
|
*/
|
95
94
|
async likePost(request: LikePostRequest): Promise<LikePostResponse> {
|
96
|
-
|
97
|
-
return makeRequest<LikePostResponse>(
|
95
|
+
return makeRequest<LikePostResponse, LikePostRequest>(
|
98
96
|
'POST',
|
99
|
-
`/api/post/like
|
97
|
+
`/api/post/like`,
|
100
98
|
this.options,
|
101
99
|
request,
|
102
100
|
);
|
@@ -108,10 +106,9 @@ export class PostApi {
|
|
108
106
|
* @returns A promise resolving with the unlike response.
|
109
107
|
*/
|
110
108
|
async unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse> {
|
111
|
-
|
112
|
-
return makeRequest<UnlikePostResponse>(
|
109
|
+
return makeRequest<UnlikePostResponse, UnlikePostRequest>(
|
113
110
|
'DELETE',
|
114
|
-
`/api/post/like
|
111
|
+
`/api/post/like`,
|
115
112
|
this.options,
|
116
113
|
request,
|
117
114
|
);
|
@@ -123,18 +120,9 @@ export class PostApi {
|
|
123
120
|
* @returns A promise resolving with the delete response.
|
124
121
|
*/
|
125
122
|
async deletePost(request: DeletePostRequest): Promise<DeletePostResponse> {
|
126
|
-
|
127
|
-
const postId = request.posts[0]?.postId || '';
|
128
|
-
if (!postId) {
|
129
|
-
throw new ApiError(
|
130
|
-
'Post ID is required for deletion path',
|
131
|
-
ApiErrorCode.VALIDATION_ERROR,
|
132
|
-
400,
|
133
|
-
);
|
134
|
-
}
|
135
|
-
return makeRequest<DeletePostResponse>(
|
123
|
+
return makeRequest<DeletePostResponse, DeletePostRequest>(
|
136
124
|
'DELETE',
|
137
|
-
`/api/post
|
125
|
+
`/api/post`,
|
138
126
|
this.options,
|
139
127
|
request,
|
140
128
|
);
|
package/src/api/system.ts
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
import type {
|
1
|
+
import type {
|
2
|
+
EndpointRateLimitResponse,
|
3
|
+
HealthStatus,
|
4
|
+
RateLimitEndpointParam,
|
5
|
+
RateLimitResponse,
|
6
|
+
} from '@crosspost/types';
|
2
7
|
import { makeRequest, type RequestOptions } from '../core/request.ts';
|
3
8
|
|
4
9
|
/**
|
@@ -21,7 +26,7 @@ export class SystemApi {
|
|
21
26
|
* @returns A promise resolving with the rate limit response
|
22
27
|
*/
|
23
28
|
async getRateLimits(): Promise<RateLimitResponse> {
|
24
|
-
return makeRequest<RateLimitResponse>(
|
29
|
+
return makeRequest<RateLimitResponse, never>(
|
25
30
|
'GET',
|
26
31
|
'/api/rate-limit',
|
27
32
|
this.options,
|
@@ -34,10 +39,12 @@ export class SystemApi {
|
|
34
39
|
* @returns A promise resolving with the endpoint rate limit response
|
35
40
|
*/
|
36
41
|
async getEndpointRateLimit(endpoint: string): Promise<EndpointRateLimitResponse> {
|
37
|
-
return makeRequest<EndpointRateLimitResponse>(
|
42
|
+
return makeRequest<EndpointRateLimitResponse, never, RateLimitEndpointParam>(
|
38
43
|
'GET',
|
39
44
|
`/api/rate-limit/${endpoint}`,
|
40
45
|
this.options,
|
46
|
+
undefined,
|
47
|
+
{ endpoint },
|
41
48
|
);
|
42
49
|
}
|
43
50
|
|
@@ -45,8 +52,8 @@ export class SystemApi {
|
|
45
52
|
* Gets the health status of the API
|
46
53
|
* @returns A promise resolving with the health status
|
47
54
|
*/
|
48
|
-
async getHealthStatus(): Promise<
|
49
|
-
return makeRequest<
|
55
|
+
async getHealthStatus(): Promise<HealthStatus> {
|
56
|
+
return makeRequest<HealthStatus, never>(
|
50
57
|
'GET',
|
51
58
|
'/health',
|
52
59
|
this.options,
|
package/src/core/client.ts
CHANGED
@@ -43,17 +43,56 @@ export class CrosspostClient {
|
|
43
43
|
|
44
44
|
/**
|
45
45
|
* Sets the authentication data (signature) for the client
|
46
|
+
* Required for non-GET requests
|
46
47
|
* @param nearAuthData The NEAR authentication data
|
47
48
|
*/
|
48
49
|
public setAuthentication(nearAuthData: NearAuthData): void {
|
49
50
|
this.options.nearAuthData = nearAuthData;
|
51
|
+
// Also set nearAccount from nearAuthData if not already set
|
52
|
+
if (!this.options.nearAccount) {
|
53
|
+
this.options.nearAccount = nearAuthData.account_id;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
/**
|
58
|
+
* Sets the NEAR account ID for simplified GET request authentication
|
59
|
+
* If not set, will use account_id from nearAuthData
|
60
|
+
* @param nearAccount The NEAR account ID
|
61
|
+
*/
|
62
|
+
public setNearAccount(nearAccount: string): void {
|
63
|
+
this.options.nearAccount = nearAccount;
|
64
|
+
}
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Gets the current NEAR account ID being used for authentication
|
68
|
+
* @returns The NEAR account ID from nearAccount or nearAuthData
|
69
|
+
*/
|
70
|
+
public getNearAccount(): string | undefined {
|
71
|
+
return this.options.nearAccount || this.options.nearAuthData?.account_id;
|
50
72
|
}
|
51
73
|
|
52
74
|
/**
|
53
75
|
* Checks if authentication data (signature) exists on client
|
54
|
-
* @
|
76
|
+
* @returns true if nearAuthData is set (required for non-GET requests)
|
55
77
|
*/
|
56
78
|
public isAuthenticated(): boolean {
|
57
79
|
return !!this.options.nearAuthData;
|
58
80
|
}
|
81
|
+
|
82
|
+
/**
|
83
|
+
* Checks if a NEAR account is set for GET request authentication
|
84
|
+
* @returns true if either nearAccount or nearAuthData.account_id is set
|
85
|
+
*/
|
86
|
+
public hasNearAccount(): boolean {
|
87
|
+
return !!(this.options.nearAccount || this.options.nearAuthData?.account_id);
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Clears all authentication data from the client
|
92
|
+
* This will prevent all requests from working until new authentication is set
|
93
|
+
*/
|
94
|
+
public clear(): void {
|
95
|
+
this.options.nearAuthData = undefined;
|
96
|
+
this.options.nearAccount = undefined;
|
97
|
+
}
|
59
98
|
}
|
package/src/core/request.ts
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
-
import {
|
1
|
+
import { ApiErrorCode, type StatusCode } from '@crosspost/types';
|
2
2
|
import { createAuthToken, type NearAuthData } from 'near-sign-verify';
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
apiWrapper,
|
5
|
+
createNetworkError,
|
6
|
+
CrosspostError,
|
7
|
+
handleErrorResponse,
|
8
|
+
} from '../utils/error.ts';
|
4
9
|
|
5
10
|
/**
|
6
11
|
* Options for making a request to the API
|
@@ -12,9 +17,14 @@ export interface RequestOptions {
|
|
12
17
|
baseUrl: string;
|
13
18
|
/**
|
14
19
|
* NEAR authentication data for generating auth tokens
|
15
|
-
*
|
20
|
+
* Required for non-GET requests, optional for GET requests
|
16
21
|
*/
|
17
22
|
nearAuthData?: NearAuthData;
|
23
|
+
/**
|
24
|
+
* NEAR account ID for simplified GET request authentication
|
25
|
+
* If not provided, will use account_id from nearAuthData
|
26
|
+
*/
|
27
|
+
nearAccount?: string;
|
18
28
|
/**
|
19
29
|
* Request timeout in milliseconds
|
20
30
|
*/
|
@@ -34,17 +44,21 @@ export interface RequestOptions {
|
|
34
44
|
* @param data Optional request data
|
35
45
|
* @returns A promise resolving with the response data
|
36
46
|
*/
|
37
|
-
export async function makeRequest<
|
47
|
+
export async function makeRequest<
|
48
|
+
TResponse,
|
49
|
+
TRequest = unknown,
|
50
|
+
TQuery = unknown,
|
51
|
+
>(
|
38
52
|
method: string,
|
39
53
|
path: string,
|
40
54
|
options: RequestOptions,
|
41
|
-
data?:
|
42
|
-
query?:
|
43
|
-
): Promise<
|
55
|
+
data?: TRequest,
|
56
|
+
query?: TQuery,
|
57
|
+
): Promise<TResponse> {
|
44
58
|
let url = `${options.baseUrl}${path.startsWith('/') ? path : `/${path}`}`;
|
45
59
|
|
46
60
|
// Add query parameters if provided
|
47
|
-
if (query && Object.keys(query).length > 0) {
|
61
|
+
if (query && typeof query === 'object' && Object.keys(query).length > 0) {
|
48
62
|
const queryParams = new URLSearchParams();
|
49
63
|
for (const [key, value] of Object.entries(query)) {
|
50
64
|
if (value !== undefined && value !== null) {
|
@@ -56,10 +70,6 @@ export async function makeRequest<T>(
|
|
56
70
|
url += `?${queryString}`;
|
57
71
|
}
|
58
72
|
}
|
59
|
-
// Check if authentication data is available
|
60
|
-
if (!options.nearAuthData) {
|
61
|
-
throw ApiError.unauthorized('Authentication required. Please provide NEAR signature.');
|
62
|
-
}
|
63
73
|
|
64
74
|
// Create a context object for error enrichment
|
65
75
|
const context = {
|
@@ -80,9 +90,31 @@ export async function makeRequest<T>(
|
|
80
90
|
const headers: Record<string, string> = {
|
81
91
|
'Content-Type': 'application/json',
|
82
92
|
'Accept': 'application/json',
|
83
|
-
'Authorization': `Bearer ${createAuthToken(options.nearAuthData!)}`,
|
84
93
|
};
|
85
94
|
|
95
|
+
// For GET requests, use X-Near-Account header if available
|
96
|
+
if (method === 'GET') {
|
97
|
+
const nearAccount = options.nearAccount || options.nearAuthData?.account_id;
|
98
|
+
if (!nearAccount) {
|
99
|
+
throw new CrosspostError(
|
100
|
+
'No NEAR account provided for GET request',
|
101
|
+
ApiErrorCode.UNAUTHORIZED,
|
102
|
+
401,
|
103
|
+
);
|
104
|
+
}
|
105
|
+
headers['X-Near-Account'] = nearAccount;
|
106
|
+
} else {
|
107
|
+
// For non-GET requests, require nearAuthData
|
108
|
+
if (!options.nearAuthData) {
|
109
|
+
throw new CrosspostError(
|
110
|
+
'NEAR authentication data required for non-GET request',
|
111
|
+
ApiErrorCode.UNAUTHORIZED,
|
112
|
+
401,
|
113
|
+
);
|
114
|
+
}
|
115
|
+
headers['Authorization'] = `Bearer ${createAuthToken(options.nearAuthData)}`;
|
116
|
+
}
|
117
|
+
|
86
118
|
const requestOptions: RequestInit = {
|
87
119
|
method,
|
88
120
|
headers,
|
@@ -97,32 +129,30 @@ export async function makeRequest<T>(
|
|
97
129
|
try {
|
98
130
|
responseData = await response.json();
|
99
131
|
} catch (jsonError) {
|
100
|
-
// If JSON parsing fails, throw
|
132
|
+
// If JSON parsing fails, did API throw an error?
|
101
133
|
if (!response.ok) {
|
102
|
-
throw new
|
134
|
+
throw new CrosspostError(
|
103
135
|
`API request failed with status ${response.status} and non-JSON response`,
|
104
136
|
ApiErrorCode.NETWORK_ERROR,
|
105
|
-
response.status as
|
137
|
+
response.status as StatusCode,
|
106
138
|
{ originalStatusText: response.statusText },
|
107
139
|
);
|
108
140
|
}
|
109
|
-
// If response was ok but JSON failed, maybe it was an empty 204 response?
|
110
|
-
if (response.status === 204) return {} as T; // Handle No Content
|
111
141
|
// Otherwise, throw a custom error
|
112
|
-
throw new
|
142
|
+
throw new CrosspostError(
|
113
143
|
`Failed to parse JSON response: ${
|
114
144
|
jsonError instanceof Error ? jsonError.message : String(jsonError)
|
115
145
|
}`,
|
116
146
|
ApiErrorCode.INTERNAL_ERROR,
|
117
|
-
response.status as
|
147
|
+
response.status as StatusCode,
|
118
148
|
);
|
119
149
|
}
|
120
150
|
|
121
151
|
if (!response.ok) {
|
122
152
|
lastError = handleErrorResponse(responseData, response.status);
|
123
|
-
//
|
124
|
-
const shouldRetry =
|
125
|
-
|
153
|
+
// Only retry rate limit errors
|
154
|
+
const shouldRetry = lastError instanceof CrosspostError &&
|
155
|
+
lastError.code === ApiErrorCode.RATE_LIMITED;
|
126
156
|
if (shouldRetry && attempt < options.retries) {
|
127
157
|
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
|
128
158
|
continue; // Retry
|
@@ -130,22 +160,24 @@ export async function makeRequest<T>(
|
|
130
160
|
throw lastError; // Throw error if not retrying or retries exhausted
|
131
161
|
}
|
132
162
|
|
133
|
-
// Handle
|
134
|
-
if (
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
163
|
+
// Handle response based on success flag
|
164
|
+
if (responseData && typeof responseData === 'object' && 'success' in responseData) {
|
165
|
+
if (responseData.success) {
|
166
|
+
// Success response - return the data
|
167
|
+
return responseData.data as TResponse;
|
168
|
+
} else {
|
169
|
+
// Error response - handle with our error utilities
|
170
|
+
lastError = handleErrorResponse(responseData, response.status);
|
171
|
+
// Only retry rate limit errors
|
172
|
+
const shouldRetry = lastError instanceof CrosspostError &&
|
173
|
+
lastError.code === ApiErrorCode.RATE_LIMITED;
|
174
|
+
if (shouldRetry && attempt < options.retries) {
|
175
|
+
await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
|
176
|
+
continue; // Retry
|
177
|
+
}
|
178
|
+
throw lastError;
|
144
179
|
}
|
145
|
-
throw lastError;
|
146
180
|
}
|
147
|
-
|
148
|
-
return responseData as T;
|
149
181
|
} catch (error) {
|
150
182
|
clearTimeout(timeoutId); // Clear timeout on error
|
151
183
|
lastError = error instanceof Error ? error : new Error(String(error)); // Store the error
|
@@ -159,7 +191,7 @@ export async function makeRequest<T>(
|
|
159
191
|
}
|
160
192
|
|
161
193
|
// If it's not a known ApiError/PlatformError, wrap it
|
162
|
-
if (!(error instanceof
|
194
|
+
if (!(error instanceof CrosspostError)) {
|
163
195
|
throw createNetworkError(error, url, options.timeout);
|
164
196
|
}
|
165
197
|
|
@@ -169,6 +201,6 @@ export async function makeRequest<T>(
|
|
169
201
|
|
170
202
|
// Should not be reachable if retries >= 0, but needed for type safety
|
171
203
|
throw lastError ||
|
172
|
-
new
|
204
|
+
new CrosspostError('Request failed after multiple retries', ApiErrorCode.INTERNAL_ERROR, 500);
|
173
205
|
}, context);
|
174
206
|
}
|
package/src/index.ts
CHANGED
@@ -1,30 +1,20 @@
|
|
1
|
-
/**
|
2
|
-
* @crosspost/sdk
|
3
|
-
* SDK for interacting with the Crosspost API
|
4
|
-
*/
|
5
|
-
|
6
|
-
// Export main client
|
7
1
|
export { CrosspostClient } from './core/client.ts';
|
8
2
|
export type { CrosspostClientConfig } from './core/config.ts';
|
9
3
|
|
10
|
-
// Export API modules for advanced usage
|
11
4
|
export { ActivityApi } from './api/activity.ts';
|
12
5
|
export { AuthApi } from './api/auth.ts';
|
13
6
|
export { PostApi } from './api/post.ts';
|
14
7
|
export { SystemApi } from './api/system.ts';
|
15
8
|
|
16
|
-
// Export utility functions
|
17
9
|
export {
|
18
10
|
apiWrapper,
|
19
11
|
createNetworkError,
|
20
12
|
enrichErrorWithContext,
|
21
|
-
ERROR_CATEGORIES,
|
22
13
|
getErrorDetails,
|
23
14
|
getErrorMessage,
|
24
15
|
handleErrorResponse,
|
25
16
|
isAuthError,
|
26
17
|
isContentError,
|
27
|
-
isErrorOfCategory,
|
28
18
|
isMediaError,
|
29
19
|
isNetworkError,
|
30
20
|
isPlatformError,
|