@crosspost/sdk 0.2.0 → 0.2.2
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/README.md +97 -0
- package/dist/index.cjs +21 -24
- package/dist/index.d.cts +25 -25
- package/dist/index.d.ts +25 -25
- package/dist/index.js +21 -24
- package/package.json +1 -1
- package/src/api/activity.ts +6 -3
- package/src/api/auth.ts +33 -13
- package/src/api/post.ts +8 -7
- package/src/api/system.ts +4 -3
- package/src/core/client.ts +1 -1
- package/src/core/config.ts +2 -2
- package/src/core/request.ts +17 -24
package/README.md
CHANGED
@@ -147,6 +147,103 @@ async function createPost() {
|
|
147
147
|
|
148
148
|
## API Reference
|
149
149
|
|
150
|
+
### Pagination
|
151
|
+
|
152
|
+
The SDK supports offset-based pagination for endpoints that return large collections:
|
153
|
+
|
154
|
+
```typescript
|
155
|
+
// Get paginated results with specific limit and offset
|
156
|
+
const response = await client.activity.getLeaderboard({
|
157
|
+
limit: 10, // Number of items per page
|
158
|
+
offset: 20, // Skip the first 20 items
|
159
|
+
});
|
160
|
+
|
161
|
+
// Access pagination metadata
|
162
|
+
console.log(`Total items: ${response.meta.pagination?.total}`);
|
163
|
+
console.log(`Current page size: ${response.meta.pagination?.limit}`);
|
164
|
+
console.log(`Current offset: ${response.meta.pagination?.offset}`);
|
165
|
+
```
|
166
|
+
|
167
|
+
### Multi-Status Responses
|
168
|
+
|
169
|
+
Some operations that target multiple platforms may result in partial success. The SDK handles these
|
170
|
+
cases with multi-status responses:
|
171
|
+
|
172
|
+
```typescript
|
173
|
+
// Operation targeting multiple platforms
|
174
|
+
const response = await client.post.createPost({
|
175
|
+
targets: [
|
176
|
+
{ platform: 'twitter', userId: 'user1' },
|
177
|
+
{ platform: 'facebook', userId: 'user2' },
|
178
|
+
],
|
179
|
+
content: [{ text: 'Hello world!' }],
|
180
|
+
});
|
181
|
+
|
182
|
+
// Check multi-status summary
|
183
|
+
console.log(`Total operations: ${response.data.summary.total}`);
|
184
|
+
console.log(`Successful: ${response.data.summary.succeeded}`);
|
185
|
+
console.log(`Failed: ${response.data.summary.failed}`);
|
186
|
+
|
187
|
+
// Access successful results
|
188
|
+
response.data.results.forEach((result) => {
|
189
|
+
console.log(`Success on ${result.platform}: ${result.details.id}`);
|
190
|
+
});
|
191
|
+
|
192
|
+
// Access errors (if any)
|
193
|
+
if (response.data.errors && response.data.errors.length > 0) {
|
194
|
+
// Error structure is identical to error.details.errors when all operations fail
|
195
|
+
response.data.errors.forEach((error) => {
|
196
|
+
console.log(`Error on ${error.details.platform}: ${error.message}`);
|
197
|
+
console.log(`Error code: ${error.code}`);
|
198
|
+
console.log(`Recoverable: ${error.recoverable}`);
|
199
|
+
});
|
200
|
+
}
|
201
|
+
```
|
202
|
+
|
203
|
+
If all operations fail, the SDK throws a `CrosspostError` with the same error structure in
|
204
|
+
`details.errors`:
|
205
|
+
|
206
|
+
```typescript
|
207
|
+
try {
|
208
|
+
await client.post.createPost({...});
|
209
|
+
} catch (error) {
|
210
|
+
if (error instanceof CrosspostError && error.details?.errors) {
|
211
|
+
// Error structure is identical to response.data.errors in partial success case
|
212
|
+
error.details.errors.forEach(err => {
|
213
|
+
console.log(`Error on ${err.details.platform}: ${err.message}`);
|
214
|
+
console.log(`Error code: ${err.code}`);
|
215
|
+
console.log(`Recoverable: ${err.recoverable}`);
|
216
|
+
});
|
217
|
+
}
|
218
|
+
}
|
219
|
+
```
|
220
|
+
|
221
|
+
This consistent error structure allows you to use the same error handling logic regardless of
|
222
|
+
whether you're dealing with partial failures in a multi-status response or complete failure.
|
223
|
+
|
224
|
+
### Validation Error Handling
|
225
|
+
|
226
|
+
The SDK provides detailed validation error information:
|
227
|
+
|
228
|
+
```typescript
|
229
|
+
try {
|
230
|
+
await client.post.createPost({
|
231
|
+
// Invalid or missing required fields
|
232
|
+
});
|
233
|
+
} catch (error) {
|
234
|
+
if (isValidationError(error)) {
|
235
|
+
console.error('Validation failed:');
|
236
|
+
|
237
|
+
// Access validation error details
|
238
|
+
if (error.details?.validationErrors) {
|
239
|
+
Object.entries(error.details.validationErrors).forEach(([field, issues]) => {
|
240
|
+
console.error(`Field '${field}': ${issues.join(', ')}`);
|
241
|
+
});
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
```
|
246
|
+
|
150
247
|
### CrosspostClient
|
151
248
|
|
152
249
|
```typescript
|
package/dist/index.cjs
CHANGED
@@ -265,18 +265,13 @@ function createNetworkError(error, url, timeout) {
|
|
265
265
|
|
266
266
|
// src/core/request.ts
|
267
267
|
async function makeRequest(method, path, options, data, query) {
|
268
|
-
|
268
|
+
const url = new URL(path, options.baseUrl);
|
269
269
|
if (query && typeof query === "object" && Object.keys(query).length > 0) {
|
270
|
-
const queryParams = new URLSearchParams();
|
271
270
|
for (const [key, value] of Object.entries(query)) {
|
272
271
|
if (value !== void 0 && value !== null) {
|
273
|
-
|
272
|
+
url.searchParams.append(key, String(value));
|
274
273
|
}
|
275
274
|
}
|
276
|
-
const queryString = queryParams.toString();
|
277
|
-
if (queryString) {
|
278
|
-
url += `?${queryString}`;
|
279
|
-
}
|
280
275
|
}
|
281
276
|
const context = {
|
282
277
|
method,
|
@@ -341,24 +336,16 @@ async function makeRequest(method, path, options, data, query) {
|
|
341
336
|
if (!response.ok) {
|
342
337
|
throw handleErrorResponse(responseData, response.status);
|
343
338
|
}
|
344
|
-
if (!responseData || typeof responseData !== "object" || !("success" in responseData)) {
|
339
|
+
if (!responseData || typeof responseData !== "object" || !("success" in responseData) || !("meta" in responseData)) {
|
345
340
|
throw new CrosspostError(
|
346
|
-
"Invalid
|
341
|
+
"Invalid response format from API",
|
347
342
|
import_types2.ApiErrorCode.INVALID_RESPONSE,
|
348
343
|
response.status,
|
349
344
|
{ responseData }
|
350
345
|
);
|
351
346
|
}
|
352
347
|
if (responseData.success) {
|
353
|
-
|
354
|
-
throw new CrosspostError(
|
355
|
-
"API returned success but no data",
|
356
|
-
import_types2.ApiErrorCode.INVALID_RESPONSE,
|
357
|
-
response.status,
|
358
|
-
{ responseData }
|
359
|
-
);
|
360
|
-
}
|
361
|
-
return responseData.data;
|
348
|
+
return responseData;
|
362
349
|
}
|
363
350
|
throw handleErrorResponse(responseData, response.status);
|
364
351
|
} catch (error) {
|
@@ -367,7 +354,10 @@ async function makeRequest(method, path, options, data, query) {
|
|
367
354
|
throw enrichErrorWithContext(error, context);
|
368
355
|
}
|
369
356
|
if (error instanceof TypeError || error instanceof DOMException && error.name === "AbortError") {
|
370
|
-
throw enrichErrorWithContext(
|
357
|
+
throw enrichErrorWithContext(
|
358
|
+
createNetworkError(error, url.toString(), options.timeout),
|
359
|
+
context
|
360
|
+
);
|
371
361
|
}
|
372
362
|
throw enrichErrorWithContext(
|
373
363
|
new CrosspostError(
|
@@ -543,13 +533,20 @@ var AuthApi = class {
|
|
543
533
|
* @throws Error if popups are blocked or if running in a non-browser environment.
|
544
534
|
*/
|
545
535
|
async loginToPlatform(platform, options) {
|
546
|
-
const
|
536
|
+
const requestOptions = options || { redirect: false };
|
537
|
+
const response = await makeRequest(
|
547
538
|
"POST",
|
548
539
|
`/auth/${platform}/login`,
|
549
540
|
this.options,
|
550
|
-
|
541
|
+
requestOptions
|
551
542
|
);
|
552
|
-
|
543
|
+
if (requestOptions.redirect) {
|
544
|
+
return response;
|
545
|
+
}
|
546
|
+
if (!response.data || !("url" in response.data)) {
|
547
|
+
throw new Error("Invalid authentication URL response");
|
548
|
+
}
|
549
|
+
const result = await openAuthPopup(response.data.url);
|
553
550
|
if (!result.success || !result.userId) {
|
554
551
|
throw new Error(result.error || "Authentication failed");
|
555
552
|
}
|
@@ -790,7 +787,7 @@ var SystemApi = class {
|
|
790
787
|
|
791
788
|
// src/core/config.ts
|
792
789
|
var DEFAULT_CONFIG = {
|
793
|
-
baseUrl: "https://open-crosspost-proxy.deno.dev/",
|
790
|
+
baseUrl: new URL("https://open-crosspost-proxy.deno.dev/"),
|
794
791
|
timeout: 3e4
|
795
792
|
};
|
796
793
|
|
@@ -805,7 +802,7 @@ var CrosspostClient = class {
|
|
805
802
|
const timeout = config.timeout || DEFAULT_CONFIG.timeout;
|
806
803
|
const nearAuthData = config.nearAuthData;
|
807
804
|
this.options = {
|
808
|
-
baseUrl,
|
805
|
+
baseUrl: baseUrl instanceof URL ? baseUrl : new URL(baseUrl),
|
809
806
|
timeout,
|
810
807
|
nearAuthData
|
811
808
|
};
|
package/dist/index.d.cts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { NearAuthData } from 'near-sign-verify';
|
2
|
-
import { ActivityLeaderboardQuery, ActivityLeaderboardResponse, AccountActivityQuery, AccountActivityResponse, AccountPostsQuery, AccountPostsResponse, NearAuthorizationResponse, Platform, AuthInitRequest, AuthCallbackResponse, ConnectedAccount, AuthStatusResponse, NearUnauthorizationResponse, AuthRevokeResponse, ConnectedAccountsResponse, CreatePostRequest, CreatePostResponse, RepostRequest, RepostResponse, QuotePostRequest, QuotePostResponse, ReplyToPostRequest, ReplyToPostResponse, LikePostRequest, LikePostResponse, UnlikePostRequest, UnlikePostResponse, DeletePostRequest, DeletePostResponse, RateLimitResponse, EndpointRateLimitResponse, HealthStatus, ApiErrorCode, StatusCode, ErrorDetails } from '@crosspost/types';
|
2
|
+
import { ActivityLeaderboardQuery, ApiResponse, ActivityLeaderboardResponse, AccountActivityQuery, AccountActivityResponse, AccountPostsQuery, AccountPostsResponse, NearAuthorizationResponse, Platform, AuthInitRequest, AuthCallbackResponse, AuthUrlResponse, ConnectedAccount, AuthStatusResponse, NearUnauthorizationResponse, AuthRevokeResponse, ConnectedAccountsResponse, CreatePostRequest, CreatePostResponse, RepostRequest, RepostResponse, QuotePostRequest, QuotePostResponse, ReplyToPostRequest, ReplyToPostResponse, LikePostRequest, LikePostResponse, UnlikePostRequest, UnlikePostResponse, DeletePostRequest, DeletePostResponse, RateLimitResponse, EndpointRateLimitResponse, HealthStatus, ApiErrorCode, StatusCode, ErrorDetails } from '@crosspost/types';
|
3
3
|
export * from '@crosspost/types';
|
4
4
|
|
5
5
|
/**
|
@@ -9,7 +9,7 @@ interface RequestOptions {
|
|
9
9
|
/**
|
10
10
|
* Base URL for the API
|
11
11
|
*/
|
12
|
-
baseUrl:
|
12
|
+
baseUrl: URL;
|
13
13
|
/**
|
14
14
|
* NEAR authentication data for generating auth tokens
|
15
15
|
* Required for non-GET requests, optional for GET requests
|
@@ -41,21 +41,21 @@ declare class ActivityApi {
|
|
41
41
|
* @param query Optional query parameters
|
42
42
|
* @returns A promise resolving with the leaderboard response
|
43
43
|
*/
|
44
|
-
getLeaderboard(query?: ActivityLeaderboardQuery): Promise<ActivityLeaderboardResponse
|
44
|
+
getLeaderboard(query?: ActivityLeaderboardQuery): Promise<ApiResponse<ActivityLeaderboardResponse>>;
|
45
45
|
/**
|
46
46
|
* Gets activity for a specific account
|
47
47
|
* @param signerId The NEAR account ID
|
48
48
|
* @param query Optional query parameters
|
49
49
|
* @returns A promise resolving with the account activity response
|
50
50
|
*/
|
51
|
-
getAccountActivity(signerId: string, query?: AccountActivityQuery): Promise<AccountActivityResponse
|
51
|
+
getAccountActivity(signerId: string, query?: AccountActivityQuery): Promise<ApiResponse<AccountActivityResponse>>;
|
52
52
|
/**
|
53
53
|
* Gets posts for a specific account
|
54
54
|
* @param signerId The NEAR account ID
|
55
55
|
* @param query Optional query parameters
|
56
56
|
* @returns A promise resolving with the account posts response
|
57
57
|
*/
|
58
|
-
getAccountPosts(signerId: string, query?: AccountPostsQuery): Promise<AccountPostsResponse
|
58
|
+
getAccountPosts(signerId: string, query?: AccountPostsQuery): Promise<ApiResponse<AccountPostsResponse>>;
|
59
59
|
}
|
60
60
|
|
61
61
|
/**
|
@@ -72,12 +72,12 @@ declare class AuthApi {
|
|
72
72
|
* Authorizes the NEAR account associated with the provided nearAuthData with the Crosspost service.
|
73
73
|
* @returns A promise resolving with the authorization response.
|
74
74
|
*/
|
75
|
-
authorizeNearAccount(): Promise<NearAuthorizationResponse
|
75
|
+
authorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>>;
|
76
76
|
/**
|
77
77
|
* Checks the authorization status of the NEAR account with the Crosspost service.
|
78
78
|
* @returns A promise resolving with the authorization status response.
|
79
79
|
*/
|
80
|
-
getNearAuthorizationStatus(): Promise<NearAuthorizationResponse
|
80
|
+
getNearAuthorizationStatus(): Promise<ApiResponse<NearAuthorizationResponse>>;
|
81
81
|
/**
|
82
82
|
* Initiates the login process for a specific platform using a popup window.
|
83
83
|
* @param platform The target platform.
|
@@ -85,43 +85,43 @@ declare class AuthApi {
|
|
85
85
|
* @returns Promise that resolves with the authentication result when the popup completes.
|
86
86
|
* @throws Error if popups are blocked or if running in a non-browser environment.
|
87
87
|
*/
|
88
|
-
loginToPlatform(platform: Platform, options?: AuthInitRequest): Promise<AuthCallbackResponse
|
88
|
+
loginToPlatform(platform: Platform, options?: AuthInitRequest): Promise<AuthCallbackResponse | ApiResponse<AuthUrlResponse>>;
|
89
89
|
/**
|
90
90
|
* Refreshes the authentication token for the specified platform.
|
91
91
|
* @param platform The target platform.
|
92
92
|
* @returns A promise resolving with the refresh response containing updated auth details.
|
93
93
|
*/
|
94
|
-
refreshToken(platform: Platform, userId: string): Promise<AuthCallbackResponse
|
94
|
+
refreshToken(platform: Platform, userId: string): Promise<ApiResponse<AuthCallbackResponse>>;
|
95
95
|
/**
|
96
96
|
* Refreshes the user's profile information from the specified platform.
|
97
97
|
* @param platform The target platform.
|
98
98
|
* @param userId The user ID on the platform
|
99
99
|
* @returns A promise resolving with the updated account profile information.
|
100
100
|
*/
|
101
|
-
refreshProfile(platform: Platform, userId: string): Promise<ConnectedAccount
|
101
|
+
refreshProfile(platform: Platform, userId: string): Promise<ApiResponse<ConnectedAccount>>;
|
102
102
|
/**
|
103
103
|
* Gets the authentication status for the specified platform.
|
104
104
|
* @param platform The target platform.
|
105
105
|
* @returns A promise resolving with the authentication status response.
|
106
106
|
*/
|
107
|
-
getAuthStatus(platform: Platform, userId: string): Promise<AuthStatusResponse
|
107
|
+
getAuthStatus(platform: Platform, userId: string): Promise<ApiResponse<AuthStatusResponse>>;
|
108
108
|
/**
|
109
109
|
* Unauthorizes a NEAR account from using the service
|
110
110
|
* @returns A promise resolving with the unauthorized response
|
111
111
|
*/
|
112
|
-
unauthorizeNear(): Promise<NearUnauthorizationResponse
|
112
|
+
unauthorizeNear(): Promise<ApiResponse<NearUnauthorizationResponse>>;
|
113
113
|
/**
|
114
114
|
* Revokes the authentication token for the specified platform.
|
115
115
|
* @param platform The target platform.
|
116
116
|
* @returns A promise resolving with the revocation response.
|
117
117
|
*/
|
118
|
-
revokeAuth(platform: Platform, userId: string): Promise<AuthRevokeResponse
|
118
|
+
revokeAuth(platform: Platform, userId: string): Promise<ApiResponse<AuthRevokeResponse>>;
|
119
119
|
/**
|
120
120
|
* Lists all accounts connected to the NEAR account.
|
121
121
|
* @returns A promise resolving with the connected accounts response containing an array of accounts.
|
122
122
|
* @throws {CrosspostError} If the request fails or returns invalid data.
|
123
123
|
*/
|
124
|
-
getConnectedAccounts(): Promise<ConnectedAccountsResponse
|
124
|
+
getConnectedAccounts(): Promise<ApiResponse<ConnectedAccountsResponse>>;
|
125
125
|
}
|
126
126
|
|
127
127
|
/**
|
@@ -139,43 +139,43 @@ declare class PostApi {
|
|
139
139
|
* @param request The post creation request details.
|
140
140
|
* @returns A promise resolving with the post creation response.
|
141
141
|
*/
|
142
|
-
createPost(request: CreatePostRequest): Promise<CreatePostResponse
|
142
|
+
createPost(request: CreatePostRequest): Promise<ApiResponse<CreatePostResponse>>;
|
143
143
|
/**
|
144
144
|
* Reposts an existing post on the specified target platforms.
|
145
145
|
* @param request The repost request details.
|
146
146
|
* @returns A promise resolving with the repost response.
|
147
147
|
*/
|
148
|
-
repost(request: RepostRequest): Promise<RepostResponse
|
148
|
+
repost(request: RepostRequest): Promise<ApiResponse<RepostResponse>>;
|
149
149
|
/**
|
150
150
|
* Quotes an existing post on the specified target platforms.
|
151
151
|
* @param request The quote post request details.
|
152
152
|
* @returns A promise resolving with the quote post response.
|
153
153
|
*/
|
154
|
-
quotePost(request: QuotePostRequest): Promise<QuotePostResponse
|
154
|
+
quotePost(request: QuotePostRequest): Promise<ApiResponse<QuotePostResponse>>;
|
155
155
|
/**
|
156
156
|
* Replies to an existing post on the specified target platforms.
|
157
157
|
* @param request The reply request details.
|
158
158
|
* @returns A promise resolving with the reply response.
|
159
159
|
*/
|
160
|
-
replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse
|
160
|
+
replyToPost(request: ReplyToPostRequest): Promise<ApiResponse<ReplyToPostResponse>>;
|
161
161
|
/**
|
162
162
|
* Likes a post on the specified target platforms.
|
163
163
|
* @param request The like request details.
|
164
164
|
* @returns A promise resolving with the like response.
|
165
165
|
*/
|
166
|
-
likePost(request: LikePostRequest): Promise<LikePostResponse
|
166
|
+
likePost(request: LikePostRequest): Promise<ApiResponse<LikePostResponse>>;
|
167
167
|
/**
|
168
168
|
* Unlikes a post on the specified target platforms.
|
169
169
|
* @param request The unlike request details.
|
170
170
|
* @returns A promise resolving with the unlike response.
|
171
171
|
*/
|
172
|
-
unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse
|
172
|
+
unlikePost(request: UnlikePostRequest): Promise<ApiResponse<UnlikePostResponse>>;
|
173
173
|
/**
|
174
174
|
* Deletes one or more posts.
|
175
175
|
* @param request The delete request details.
|
176
176
|
* @returns A promise resolving with the delete response.
|
177
177
|
*/
|
178
|
-
deletePost(request: DeletePostRequest): Promise<DeletePostResponse
|
178
|
+
deletePost(request: DeletePostRequest): Promise<ApiResponse<DeletePostResponse>>;
|
179
179
|
}
|
180
180
|
|
181
181
|
/**
|
@@ -193,18 +193,18 @@ declare class SystemApi {
|
|
193
193
|
* Gets the current rate limit status
|
194
194
|
* @returns A promise resolving with the rate limit response
|
195
195
|
*/
|
196
|
-
getRateLimits(): Promise<RateLimitResponse
|
196
|
+
getRateLimits(): Promise<ApiResponse<RateLimitResponse>>;
|
197
197
|
/**
|
198
198
|
* Gets the rate limit status for a specific endpoint
|
199
199
|
* @param endpoint The endpoint to get rate limit for
|
200
200
|
* @returns A promise resolving with the endpoint rate limit response
|
201
201
|
*/
|
202
|
-
getEndpointRateLimit(endpoint: string): Promise<EndpointRateLimitResponse
|
202
|
+
getEndpointRateLimit(endpoint: string): Promise<ApiResponse<EndpointRateLimitResponse>>;
|
203
203
|
/**
|
204
204
|
* Gets the health status of the API
|
205
205
|
* @returns A promise resolving with the health status
|
206
206
|
*/
|
207
|
-
getHealthStatus(): Promise<HealthStatus
|
207
|
+
getHealthStatus(): Promise<ApiResponse<HealthStatus>>;
|
208
208
|
}
|
209
209
|
|
210
210
|
/**
|
@@ -215,7 +215,7 @@ interface CrosspostClientConfig {
|
|
215
215
|
* Base URL for the Crosspost API
|
216
216
|
* @default 'https://open-crosspost-proxy.deno.dev'
|
217
217
|
*/
|
218
|
-
baseUrl?: string;
|
218
|
+
baseUrl?: string | URL;
|
219
219
|
/**
|
220
220
|
* NEAR authentication data obtained from near-sign-verify
|
221
221
|
*/
|
package/dist/index.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { NearAuthData } from 'near-sign-verify';
|
2
|
-
import { ActivityLeaderboardQuery, ActivityLeaderboardResponse, AccountActivityQuery, AccountActivityResponse, AccountPostsQuery, AccountPostsResponse, NearAuthorizationResponse, Platform, AuthInitRequest, AuthCallbackResponse, ConnectedAccount, AuthStatusResponse, NearUnauthorizationResponse, AuthRevokeResponse, ConnectedAccountsResponse, CreatePostRequest, CreatePostResponse, RepostRequest, RepostResponse, QuotePostRequest, QuotePostResponse, ReplyToPostRequest, ReplyToPostResponse, LikePostRequest, LikePostResponse, UnlikePostRequest, UnlikePostResponse, DeletePostRequest, DeletePostResponse, RateLimitResponse, EndpointRateLimitResponse, HealthStatus, ApiErrorCode, StatusCode, ErrorDetails } from '@crosspost/types';
|
2
|
+
import { ActivityLeaderboardQuery, ApiResponse, ActivityLeaderboardResponse, AccountActivityQuery, AccountActivityResponse, AccountPostsQuery, AccountPostsResponse, NearAuthorizationResponse, Platform, AuthInitRequest, AuthCallbackResponse, AuthUrlResponse, ConnectedAccount, AuthStatusResponse, NearUnauthorizationResponse, AuthRevokeResponse, ConnectedAccountsResponse, CreatePostRequest, CreatePostResponse, RepostRequest, RepostResponse, QuotePostRequest, QuotePostResponse, ReplyToPostRequest, ReplyToPostResponse, LikePostRequest, LikePostResponse, UnlikePostRequest, UnlikePostResponse, DeletePostRequest, DeletePostResponse, RateLimitResponse, EndpointRateLimitResponse, HealthStatus, ApiErrorCode, StatusCode, ErrorDetails } from '@crosspost/types';
|
3
3
|
export * from '@crosspost/types';
|
4
4
|
|
5
5
|
/**
|
@@ -9,7 +9,7 @@ interface RequestOptions {
|
|
9
9
|
/**
|
10
10
|
* Base URL for the API
|
11
11
|
*/
|
12
|
-
baseUrl:
|
12
|
+
baseUrl: URL;
|
13
13
|
/**
|
14
14
|
* NEAR authentication data for generating auth tokens
|
15
15
|
* Required for non-GET requests, optional for GET requests
|
@@ -41,21 +41,21 @@ declare class ActivityApi {
|
|
41
41
|
* @param query Optional query parameters
|
42
42
|
* @returns A promise resolving with the leaderboard response
|
43
43
|
*/
|
44
|
-
getLeaderboard(query?: ActivityLeaderboardQuery): Promise<ActivityLeaderboardResponse
|
44
|
+
getLeaderboard(query?: ActivityLeaderboardQuery): Promise<ApiResponse<ActivityLeaderboardResponse>>;
|
45
45
|
/**
|
46
46
|
* Gets activity for a specific account
|
47
47
|
* @param signerId The NEAR account ID
|
48
48
|
* @param query Optional query parameters
|
49
49
|
* @returns A promise resolving with the account activity response
|
50
50
|
*/
|
51
|
-
getAccountActivity(signerId: string, query?: AccountActivityQuery): Promise<AccountActivityResponse
|
51
|
+
getAccountActivity(signerId: string, query?: AccountActivityQuery): Promise<ApiResponse<AccountActivityResponse>>;
|
52
52
|
/**
|
53
53
|
* Gets posts for a specific account
|
54
54
|
* @param signerId The NEAR account ID
|
55
55
|
* @param query Optional query parameters
|
56
56
|
* @returns A promise resolving with the account posts response
|
57
57
|
*/
|
58
|
-
getAccountPosts(signerId: string, query?: AccountPostsQuery): Promise<AccountPostsResponse
|
58
|
+
getAccountPosts(signerId: string, query?: AccountPostsQuery): Promise<ApiResponse<AccountPostsResponse>>;
|
59
59
|
}
|
60
60
|
|
61
61
|
/**
|
@@ -72,12 +72,12 @@ declare class AuthApi {
|
|
72
72
|
* Authorizes the NEAR account associated with the provided nearAuthData with the Crosspost service.
|
73
73
|
* @returns A promise resolving with the authorization response.
|
74
74
|
*/
|
75
|
-
authorizeNearAccount(): Promise<NearAuthorizationResponse
|
75
|
+
authorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>>;
|
76
76
|
/**
|
77
77
|
* Checks the authorization status of the NEAR account with the Crosspost service.
|
78
78
|
* @returns A promise resolving with the authorization status response.
|
79
79
|
*/
|
80
|
-
getNearAuthorizationStatus(): Promise<NearAuthorizationResponse
|
80
|
+
getNearAuthorizationStatus(): Promise<ApiResponse<NearAuthorizationResponse>>;
|
81
81
|
/**
|
82
82
|
* Initiates the login process for a specific platform using a popup window.
|
83
83
|
* @param platform The target platform.
|
@@ -85,43 +85,43 @@ declare class AuthApi {
|
|
85
85
|
* @returns Promise that resolves with the authentication result when the popup completes.
|
86
86
|
* @throws Error if popups are blocked or if running in a non-browser environment.
|
87
87
|
*/
|
88
|
-
loginToPlatform(platform: Platform, options?: AuthInitRequest): Promise<AuthCallbackResponse
|
88
|
+
loginToPlatform(platform: Platform, options?: AuthInitRequest): Promise<AuthCallbackResponse | ApiResponse<AuthUrlResponse>>;
|
89
89
|
/**
|
90
90
|
* Refreshes the authentication token for the specified platform.
|
91
91
|
* @param platform The target platform.
|
92
92
|
* @returns A promise resolving with the refresh response containing updated auth details.
|
93
93
|
*/
|
94
|
-
refreshToken(platform: Platform, userId: string): Promise<AuthCallbackResponse
|
94
|
+
refreshToken(platform: Platform, userId: string): Promise<ApiResponse<AuthCallbackResponse>>;
|
95
95
|
/**
|
96
96
|
* Refreshes the user's profile information from the specified platform.
|
97
97
|
* @param platform The target platform.
|
98
98
|
* @param userId The user ID on the platform
|
99
99
|
* @returns A promise resolving with the updated account profile information.
|
100
100
|
*/
|
101
|
-
refreshProfile(platform: Platform, userId: string): Promise<ConnectedAccount
|
101
|
+
refreshProfile(platform: Platform, userId: string): Promise<ApiResponse<ConnectedAccount>>;
|
102
102
|
/**
|
103
103
|
* Gets the authentication status for the specified platform.
|
104
104
|
* @param platform The target platform.
|
105
105
|
* @returns A promise resolving with the authentication status response.
|
106
106
|
*/
|
107
|
-
getAuthStatus(platform: Platform, userId: string): Promise<AuthStatusResponse
|
107
|
+
getAuthStatus(platform: Platform, userId: string): Promise<ApiResponse<AuthStatusResponse>>;
|
108
108
|
/**
|
109
109
|
* Unauthorizes a NEAR account from using the service
|
110
110
|
* @returns A promise resolving with the unauthorized response
|
111
111
|
*/
|
112
|
-
unauthorizeNear(): Promise<NearUnauthorizationResponse
|
112
|
+
unauthorizeNear(): Promise<ApiResponse<NearUnauthorizationResponse>>;
|
113
113
|
/**
|
114
114
|
* Revokes the authentication token for the specified platform.
|
115
115
|
* @param platform The target platform.
|
116
116
|
* @returns A promise resolving with the revocation response.
|
117
117
|
*/
|
118
|
-
revokeAuth(platform: Platform, userId: string): Promise<AuthRevokeResponse
|
118
|
+
revokeAuth(platform: Platform, userId: string): Promise<ApiResponse<AuthRevokeResponse>>;
|
119
119
|
/**
|
120
120
|
* Lists all accounts connected to the NEAR account.
|
121
121
|
* @returns A promise resolving with the connected accounts response containing an array of accounts.
|
122
122
|
* @throws {CrosspostError} If the request fails or returns invalid data.
|
123
123
|
*/
|
124
|
-
getConnectedAccounts(): Promise<ConnectedAccountsResponse
|
124
|
+
getConnectedAccounts(): Promise<ApiResponse<ConnectedAccountsResponse>>;
|
125
125
|
}
|
126
126
|
|
127
127
|
/**
|
@@ -139,43 +139,43 @@ declare class PostApi {
|
|
139
139
|
* @param request The post creation request details.
|
140
140
|
* @returns A promise resolving with the post creation response.
|
141
141
|
*/
|
142
|
-
createPost(request: CreatePostRequest): Promise<CreatePostResponse
|
142
|
+
createPost(request: CreatePostRequest): Promise<ApiResponse<CreatePostResponse>>;
|
143
143
|
/**
|
144
144
|
* Reposts an existing post on the specified target platforms.
|
145
145
|
* @param request The repost request details.
|
146
146
|
* @returns A promise resolving with the repost response.
|
147
147
|
*/
|
148
|
-
repost(request: RepostRequest): Promise<RepostResponse
|
148
|
+
repost(request: RepostRequest): Promise<ApiResponse<RepostResponse>>;
|
149
149
|
/**
|
150
150
|
* Quotes an existing post on the specified target platforms.
|
151
151
|
* @param request The quote post request details.
|
152
152
|
* @returns A promise resolving with the quote post response.
|
153
153
|
*/
|
154
|
-
quotePost(request: QuotePostRequest): Promise<QuotePostResponse
|
154
|
+
quotePost(request: QuotePostRequest): Promise<ApiResponse<QuotePostResponse>>;
|
155
155
|
/**
|
156
156
|
* Replies to an existing post on the specified target platforms.
|
157
157
|
* @param request The reply request details.
|
158
158
|
* @returns A promise resolving with the reply response.
|
159
159
|
*/
|
160
|
-
replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse
|
160
|
+
replyToPost(request: ReplyToPostRequest): Promise<ApiResponse<ReplyToPostResponse>>;
|
161
161
|
/**
|
162
162
|
* Likes a post on the specified target platforms.
|
163
163
|
* @param request The like request details.
|
164
164
|
* @returns A promise resolving with the like response.
|
165
165
|
*/
|
166
|
-
likePost(request: LikePostRequest): Promise<LikePostResponse
|
166
|
+
likePost(request: LikePostRequest): Promise<ApiResponse<LikePostResponse>>;
|
167
167
|
/**
|
168
168
|
* Unlikes a post on the specified target platforms.
|
169
169
|
* @param request The unlike request details.
|
170
170
|
* @returns A promise resolving with the unlike response.
|
171
171
|
*/
|
172
|
-
unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse
|
172
|
+
unlikePost(request: UnlikePostRequest): Promise<ApiResponse<UnlikePostResponse>>;
|
173
173
|
/**
|
174
174
|
* Deletes one or more posts.
|
175
175
|
* @param request The delete request details.
|
176
176
|
* @returns A promise resolving with the delete response.
|
177
177
|
*/
|
178
|
-
deletePost(request: DeletePostRequest): Promise<DeletePostResponse
|
178
|
+
deletePost(request: DeletePostRequest): Promise<ApiResponse<DeletePostResponse>>;
|
179
179
|
}
|
180
180
|
|
181
181
|
/**
|
@@ -193,18 +193,18 @@ declare class SystemApi {
|
|
193
193
|
* Gets the current rate limit status
|
194
194
|
* @returns A promise resolving with the rate limit response
|
195
195
|
*/
|
196
|
-
getRateLimits(): Promise<RateLimitResponse
|
196
|
+
getRateLimits(): Promise<ApiResponse<RateLimitResponse>>;
|
197
197
|
/**
|
198
198
|
* Gets the rate limit status for a specific endpoint
|
199
199
|
* @param endpoint The endpoint to get rate limit for
|
200
200
|
* @returns A promise resolving with the endpoint rate limit response
|
201
201
|
*/
|
202
|
-
getEndpointRateLimit(endpoint: string): Promise<EndpointRateLimitResponse
|
202
|
+
getEndpointRateLimit(endpoint: string): Promise<ApiResponse<EndpointRateLimitResponse>>;
|
203
203
|
/**
|
204
204
|
* Gets the health status of the API
|
205
205
|
* @returns A promise resolving with the health status
|
206
206
|
*/
|
207
|
-
getHealthStatus(): Promise<HealthStatus
|
207
|
+
getHealthStatus(): Promise<ApiResponse<HealthStatus>>;
|
208
208
|
}
|
209
209
|
|
210
210
|
/**
|
@@ -215,7 +215,7 @@ interface CrosspostClientConfig {
|
|
215
215
|
* Base URL for the Crosspost API
|
216
216
|
* @default 'https://open-crosspost-proxy.deno.dev'
|
217
217
|
*/
|
218
|
-
baseUrl?: string;
|
218
|
+
baseUrl?: string | URL;
|
219
219
|
/**
|
220
220
|
* NEAR authentication data obtained from near-sign-verify
|
221
221
|
*/
|
package/dist/index.js
CHANGED
@@ -219,18 +219,13 @@ function createNetworkError(error, url, timeout) {
|
|
219
219
|
|
220
220
|
// src/core/request.ts
|
221
221
|
async function makeRequest(method, path, options, data, query) {
|
222
|
-
|
222
|
+
const url = new URL(path, options.baseUrl);
|
223
223
|
if (query && typeof query === "object" && Object.keys(query).length > 0) {
|
224
|
-
const queryParams = new URLSearchParams();
|
225
224
|
for (const [key, value] of Object.entries(query)) {
|
226
225
|
if (value !== void 0 && value !== null) {
|
227
|
-
|
226
|
+
url.searchParams.append(key, String(value));
|
228
227
|
}
|
229
228
|
}
|
230
|
-
const queryString = queryParams.toString();
|
231
|
-
if (queryString) {
|
232
|
-
url += `?${queryString}`;
|
233
|
-
}
|
234
229
|
}
|
235
230
|
const context = {
|
236
231
|
method,
|
@@ -295,24 +290,16 @@ async function makeRequest(method, path, options, data, query) {
|
|
295
290
|
if (!response.ok) {
|
296
291
|
throw handleErrorResponse(responseData, response.status);
|
297
292
|
}
|
298
|
-
if (!responseData || typeof responseData !== "object" || !("success" in responseData)) {
|
293
|
+
if (!responseData || typeof responseData !== "object" || !("success" in responseData) || !("meta" in responseData)) {
|
299
294
|
throw new CrosspostError(
|
300
|
-
"Invalid
|
295
|
+
"Invalid response format from API",
|
301
296
|
ApiErrorCode2.INVALID_RESPONSE,
|
302
297
|
response.status,
|
303
298
|
{ responseData }
|
304
299
|
);
|
305
300
|
}
|
306
301
|
if (responseData.success) {
|
307
|
-
|
308
|
-
throw new CrosspostError(
|
309
|
-
"API returned success but no data",
|
310
|
-
ApiErrorCode2.INVALID_RESPONSE,
|
311
|
-
response.status,
|
312
|
-
{ responseData }
|
313
|
-
);
|
314
|
-
}
|
315
|
-
return responseData.data;
|
302
|
+
return responseData;
|
316
303
|
}
|
317
304
|
throw handleErrorResponse(responseData, response.status);
|
318
305
|
} catch (error) {
|
@@ -321,7 +308,10 @@ async function makeRequest(method, path, options, data, query) {
|
|
321
308
|
throw enrichErrorWithContext(error, context);
|
322
309
|
}
|
323
310
|
if (error instanceof TypeError || error instanceof DOMException && error.name === "AbortError") {
|
324
|
-
throw enrichErrorWithContext(
|
311
|
+
throw enrichErrorWithContext(
|
312
|
+
createNetworkError(error, url.toString(), options.timeout),
|
313
|
+
context
|
314
|
+
);
|
325
315
|
}
|
326
316
|
throw enrichErrorWithContext(
|
327
317
|
new CrosspostError(
|
@@ -497,13 +487,20 @@ var AuthApi = class {
|
|
497
487
|
* @throws Error if popups are blocked or if running in a non-browser environment.
|
498
488
|
*/
|
499
489
|
async loginToPlatform(platform, options) {
|
500
|
-
const
|
490
|
+
const requestOptions = options || { redirect: false };
|
491
|
+
const response = await makeRequest(
|
501
492
|
"POST",
|
502
493
|
`/auth/${platform}/login`,
|
503
494
|
this.options,
|
504
|
-
|
495
|
+
requestOptions
|
505
496
|
);
|
506
|
-
|
497
|
+
if (requestOptions.redirect) {
|
498
|
+
return response;
|
499
|
+
}
|
500
|
+
if (!response.data || !("url" in response.data)) {
|
501
|
+
throw new Error("Invalid authentication URL response");
|
502
|
+
}
|
503
|
+
const result = await openAuthPopup(response.data.url);
|
507
504
|
if (!result.success || !result.userId) {
|
508
505
|
throw new Error(result.error || "Authentication failed");
|
509
506
|
}
|
@@ -744,7 +741,7 @@ var SystemApi = class {
|
|
744
741
|
|
745
742
|
// src/core/config.ts
|
746
743
|
var DEFAULT_CONFIG = {
|
747
|
-
baseUrl: "https://open-crosspost-proxy.deno.dev/",
|
744
|
+
baseUrl: new URL("https://open-crosspost-proxy.deno.dev/"),
|
748
745
|
timeout: 3e4
|
749
746
|
};
|
750
747
|
|
@@ -759,7 +756,7 @@ var CrosspostClient = class {
|
|
759
756
|
const timeout = config.timeout || DEFAULT_CONFIG.timeout;
|
760
757
|
const nearAuthData = config.nearAuthData;
|
761
758
|
this.options = {
|
762
|
-
baseUrl,
|
759
|
+
baseUrl: baseUrl instanceof URL ? baseUrl : new URL(baseUrl),
|
763
760
|
timeout,
|
764
761
|
nearAuthData
|
765
762
|
};
|
package/package.json
CHANGED
package/src/api/activity.ts
CHANGED
@@ -5,6 +5,7 @@ import type {
|
|
5
5
|
AccountPostsResponse,
|
6
6
|
ActivityLeaderboardQuery,
|
7
7
|
ActivityLeaderboardResponse,
|
8
|
+
ApiResponse,
|
8
9
|
} from '@crosspost/types';
|
9
10
|
import { makeRequest, type RequestOptions } from '../core/request.ts';
|
10
11
|
|
@@ -27,7 +28,9 @@ export class ActivityApi {
|
|
27
28
|
* @param query Optional query parameters
|
28
29
|
* @returns A promise resolving with the leaderboard response
|
29
30
|
*/
|
30
|
-
async getLeaderboard(
|
31
|
+
async getLeaderboard(
|
32
|
+
query?: ActivityLeaderboardQuery,
|
33
|
+
): Promise<ApiResponse<ActivityLeaderboardResponse>> {
|
31
34
|
return makeRequest<ActivityLeaderboardResponse, never, ActivityLeaderboardQuery>(
|
32
35
|
'GET',
|
33
36
|
'/api/activity',
|
@@ -46,7 +49,7 @@ export class ActivityApi {
|
|
46
49
|
async getAccountActivity(
|
47
50
|
signerId: string,
|
48
51
|
query?: AccountActivityQuery,
|
49
|
-
): Promise<AccountActivityResponse
|
52
|
+
): Promise<ApiResponse<AccountActivityResponse>> {
|
50
53
|
return makeRequest<AccountActivityResponse, never, AccountActivityQuery>(
|
51
54
|
'GET',
|
52
55
|
`/api/activity/${signerId}`,
|
@@ -65,7 +68,7 @@ export class ActivityApi {
|
|
65
68
|
async getAccountPosts(
|
66
69
|
signerId: string,
|
67
70
|
query?: AccountPostsQuery,
|
68
|
-
): Promise<AccountPostsResponse
|
71
|
+
): Promise<ApiResponse<AccountPostsResponse>> {
|
69
72
|
return makeRequest<AccountPostsResponse, never, AccountPostsQuery>(
|
70
73
|
'GET',
|
71
74
|
`/api/activity/${signerId}/posts`,
|
package/src/api/auth.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import type {
|
2
|
+
ApiResponse,
|
2
3
|
AuthCallbackResponse,
|
3
4
|
AuthInitRequest,
|
4
5
|
AuthRevokeResponse,
|
@@ -34,7 +35,7 @@ export class AuthApi {
|
|
34
35
|
* Authorizes the NEAR account associated with the provided nearAuthData with the Crosspost service.
|
35
36
|
* @returns A promise resolving with the authorization response.
|
36
37
|
*/
|
37
|
-
async authorizeNearAccount(): Promise<NearAuthorizationResponse
|
38
|
+
async authorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>> {
|
38
39
|
return makeRequest<NearAuthorizationResponse, NearAuthorizationRequest>(
|
39
40
|
'POST',
|
40
41
|
'/auth/authorize/near',
|
@@ -47,7 +48,7 @@ export class AuthApi {
|
|
47
48
|
* Checks the authorization status of the NEAR account with the Crosspost service.
|
48
49
|
* @returns A promise resolving with the authorization status response.
|
49
50
|
*/
|
50
|
-
async getNearAuthorizationStatus(): Promise<NearAuthorizationResponse
|
51
|
+
async getNearAuthorizationStatus(): Promise<ApiResponse<NearAuthorizationResponse>> {
|
51
52
|
return makeRequest<NearAuthorizationResponse, never>(
|
52
53
|
'GET',
|
53
54
|
'/auth/authorize/near/status',
|
@@ -65,17 +66,30 @@ export class AuthApi {
|
|
65
66
|
async loginToPlatform(
|
66
67
|
platform: Platform,
|
67
68
|
options?: AuthInitRequest,
|
68
|
-
): Promise<AuthCallbackResponse
|
69
|
+
): Promise<AuthCallbackResponse | ApiResponse<AuthUrlResponse>> {
|
70
|
+
// Use provided options or default to redirect: false
|
71
|
+
const requestOptions = options || { redirect: false };
|
72
|
+
|
69
73
|
// Make POST request to get auth URL
|
70
|
-
const
|
74
|
+
const response = await makeRequest<AuthUrlResponse, AuthInitRequest>(
|
71
75
|
'POST',
|
72
76
|
`/auth/${platform}/login`,
|
73
77
|
this.options,
|
74
|
-
|
78
|
+
requestOptions,
|
75
79
|
);
|
76
80
|
|
77
|
-
//
|
78
|
-
|
81
|
+
// If redirect is true, return the auth URL response directly
|
82
|
+
if (requestOptions.redirect) {
|
83
|
+
return response; // Return the full ApiResponse<AuthUrlResponse>
|
84
|
+
}
|
85
|
+
|
86
|
+
// Check if response.data exists and has the url property
|
87
|
+
if (!response.data || !('url' in response.data)) {
|
88
|
+
throw new Error('Invalid authentication URL response');
|
89
|
+
}
|
90
|
+
|
91
|
+
// Otherwise, continue with popup flow
|
92
|
+
const result = await openAuthPopup(response.data.url);
|
79
93
|
|
80
94
|
if (!result.success || !result.userId) {
|
81
95
|
throw new Error(result.error || 'Authentication failed');
|
@@ -94,7 +108,10 @@ export class AuthApi {
|
|
94
108
|
* @param platform The target platform.
|
95
109
|
* @returns A promise resolving with the refresh response containing updated auth details.
|
96
110
|
*/
|
97
|
-
async refreshToken(
|
111
|
+
async refreshToken(
|
112
|
+
platform: Platform,
|
113
|
+
userId: string,
|
114
|
+
): Promise<ApiResponse<AuthCallbackResponse>> {
|
98
115
|
return makeRequest<AuthCallbackResponse, AuthTokenRequest>(
|
99
116
|
'POST',
|
100
117
|
`/auth/${platform}/refresh`,
|
@@ -109,7 +126,7 @@ export class AuthApi {
|
|
109
126
|
* @param userId The user ID on the platform
|
110
127
|
* @returns A promise resolving with the updated account profile information.
|
111
128
|
*/
|
112
|
-
async refreshProfile(platform: Platform, userId: string): Promise<ConnectedAccount
|
129
|
+
async refreshProfile(platform: Platform, userId: string): Promise<ApiResponse<ConnectedAccount>> {
|
113
130
|
return makeRequest<ConnectedAccount, AuthTokenRequest>(
|
114
131
|
'POST',
|
115
132
|
`/auth/${platform}/refresh-profile`,
|
@@ -123,7 +140,10 @@ export class AuthApi {
|
|
123
140
|
* @param platform The target platform.
|
124
141
|
* @returns A promise resolving with the authentication status response.
|
125
142
|
*/
|
126
|
-
async getAuthStatus(
|
143
|
+
async getAuthStatus(
|
144
|
+
platform: Platform,
|
145
|
+
userId: string,
|
146
|
+
): Promise<ApiResponse<AuthStatusResponse>> {
|
127
147
|
return makeRequest<AuthStatusResponse, never, AuthStatusParams>(
|
128
148
|
'GET',
|
129
149
|
`/auth/${platform}/status/${userId}`,
|
@@ -137,7 +157,7 @@ export class AuthApi {
|
|
137
157
|
* Unauthorizes a NEAR account from using the service
|
138
158
|
* @returns A promise resolving with the unauthorized response
|
139
159
|
*/
|
140
|
-
async unauthorizeNear(): Promise<NearUnauthorizationResponse
|
160
|
+
async unauthorizeNear(): Promise<ApiResponse<NearUnauthorizationResponse>> {
|
141
161
|
return makeRequest<NearUnauthorizationResponse, NearAuthorizationRequest>(
|
142
162
|
'DELETE',
|
143
163
|
'/auth/unauthorize/near',
|
@@ -151,7 +171,7 @@ export class AuthApi {
|
|
151
171
|
* @param platform The target platform.
|
152
172
|
* @returns A promise resolving with the revocation response.
|
153
173
|
*/
|
154
|
-
async revokeAuth(platform: Platform, userId: string): Promise<AuthRevokeResponse
|
174
|
+
async revokeAuth(platform: Platform, userId: string): Promise<ApiResponse<AuthRevokeResponse>> {
|
155
175
|
return makeRequest<AuthRevokeResponse, AuthTokenRequest>(
|
156
176
|
'DELETE',
|
157
177
|
`/auth/${platform}/revoke`,
|
@@ -165,7 +185,7 @@ export class AuthApi {
|
|
165
185
|
* @returns A promise resolving with the connected accounts response containing an array of accounts.
|
166
186
|
* @throws {CrosspostError} If the request fails or returns invalid data.
|
167
187
|
*/
|
168
|
-
async getConnectedAccounts(): Promise<ConnectedAccountsResponse
|
188
|
+
async getConnectedAccounts(): Promise<ApiResponse<ConnectedAccountsResponse>> {
|
169
189
|
return makeRequest<ConnectedAccountsResponse, never>(
|
170
190
|
'GET',
|
171
191
|
'/auth/accounts',
|
package/src/api/post.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import type {
|
2
|
+
ApiResponse,
|
2
3
|
CreatePostRequest,
|
3
4
|
CreatePostResponse,
|
4
5
|
DeletePostRequest,
|
@@ -35,7 +36,7 @@ export class PostApi {
|
|
35
36
|
* @param request The post creation request details.
|
36
37
|
* @returns A promise resolving with the post creation response.
|
37
38
|
*/
|
38
|
-
async createPost(request: CreatePostRequest): Promise<CreatePostResponse
|
39
|
+
async createPost(request: CreatePostRequest): Promise<ApiResponse<CreatePostResponse>> {
|
39
40
|
return makeRequest<CreatePostResponse, CreatePostRequest>(
|
40
41
|
'POST',
|
41
42
|
'/api/post',
|
@@ -49,7 +50,7 @@ export class PostApi {
|
|
49
50
|
* @param request The repost request details.
|
50
51
|
* @returns A promise resolving with the repost response.
|
51
52
|
*/
|
52
|
-
async repost(request: RepostRequest): Promise<RepostResponse
|
53
|
+
async repost(request: RepostRequest): Promise<ApiResponse<RepostResponse>> {
|
53
54
|
return makeRequest<RepostResponse, RepostRequest>(
|
54
55
|
'POST',
|
55
56
|
'/api/post/repost',
|
@@ -63,7 +64,7 @@ export class PostApi {
|
|
63
64
|
* @param request The quote post request details.
|
64
65
|
* @returns A promise resolving with the quote post response.
|
65
66
|
*/
|
66
|
-
async quotePost(request: QuotePostRequest): Promise<QuotePostResponse
|
67
|
+
async quotePost(request: QuotePostRequest): Promise<ApiResponse<QuotePostResponse>> {
|
67
68
|
return makeRequest<QuotePostResponse, QuotePostRequest>(
|
68
69
|
'POST',
|
69
70
|
'/api/post/quote',
|
@@ -77,7 +78,7 @@ export class PostApi {
|
|
77
78
|
* @param request The reply request details.
|
78
79
|
* @returns A promise resolving with the reply response.
|
79
80
|
*/
|
80
|
-
async replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse
|
81
|
+
async replyToPost(request: ReplyToPostRequest): Promise<ApiResponse<ReplyToPostResponse>> {
|
81
82
|
return makeRequest<ReplyToPostResponse, ReplyToPostRequest>(
|
82
83
|
'POST',
|
83
84
|
'/api/post/reply',
|
@@ -91,7 +92,7 @@ export class PostApi {
|
|
91
92
|
* @param request The like request details.
|
92
93
|
* @returns A promise resolving with the like response.
|
93
94
|
*/
|
94
|
-
async likePost(request: LikePostRequest): Promise<LikePostResponse
|
95
|
+
async likePost(request: LikePostRequest): Promise<ApiResponse<LikePostResponse>> {
|
95
96
|
return makeRequest<LikePostResponse, LikePostRequest>(
|
96
97
|
'POST',
|
97
98
|
`/api/post/like`,
|
@@ -105,7 +106,7 @@ export class PostApi {
|
|
105
106
|
* @param request The unlike request details.
|
106
107
|
* @returns A promise resolving with the unlike response.
|
107
108
|
*/
|
108
|
-
async unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse
|
109
|
+
async unlikePost(request: UnlikePostRequest): Promise<ApiResponse<UnlikePostResponse>> {
|
109
110
|
return makeRequest<UnlikePostResponse, UnlikePostRequest>(
|
110
111
|
'DELETE',
|
111
112
|
`/api/post/like`,
|
@@ -119,7 +120,7 @@ export class PostApi {
|
|
119
120
|
* @param request The delete request details.
|
120
121
|
* @returns A promise resolving with the delete response.
|
121
122
|
*/
|
122
|
-
async deletePost(request: DeletePostRequest): Promise<DeletePostResponse
|
123
|
+
async deletePost(request: DeletePostRequest): Promise<ApiResponse<DeletePostResponse>> {
|
123
124
|
return makeRequest<DeletePostResponse, DeletePostRequest>(
|
124
125
|
'DELETE',
|
125
126
|
`/api/post`,
|
package/src/api/system.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import type {
|
2
|
+
ApiResponse,
|
2
3
|
EndpointRateLimitResponse,
|
3
4
|
HealthStatus,
|
4
5
|
RateLimitEndpointParam,
|
@@ -25,7 +26,7 @@ export class SystemApi {
|
|
25
26
|
* Gets the current rate limit status
|
26
27
|
* @returns A promise resolving with the rate limit response
|
27
28
|
*/
|
28
|
-
async getRateLimits(): Promise<RateLimitResponse
|
29
|
+
async getRateLimits(): Promise<ApiResponse<RateLimitResponse>> {
|
29
30
|
return makeRequest<RateLimitResponse, never>(
|
30
31
|
'GET',
|
31
32
|
'/api/rate-limit',
|
@@ -38,7 +39,7 @@ export class SystemApi {
|
|
38
39
|
* @param endpoint The endpoint to get rate limit for
|
39
40
|
* @returns A promise resolving with the endpoint rate limit response
|
40
41
|
*/
|
41
|
-
async getEndpointRateLimit(endpoint: string): Promise<EndpointRateLimitResponse
|
42
|
+
async getEndpointRateLimit(endpoint: string): Promise<ApiResponse<EndpointRateLimitResponse>> {
|
42
43
|
return makeRequest<EndpointRateLimitResponse, never, RateLimitEndpointParam>(
|
43
44
|
'GET',
|
44
45
|
`/api/rate-limit/${endpoint}`,
|
@@ -52,7 +53,7 @@ export class SystemApi {
|
|
52
53
|
* Gets the health status of the API
|
53
54
|
* @returns A promise resolving with the health status
|
54
55
|
*/
|
55
|
-
async getHealthStatus(): Promise<HealthStatus
|
56
|
+
async getHealthStatus(): Promise<ApiResponse<HealthStatus>> {
|
56
57
|
return makeRequest<HealthStatus, never>(
|
57
58
|
'GET',
|
58
59
|
'/health',
|
package/src/core/client.ts
CHANGED
package/src/core/config.ts
CHANGED
@@ -8,7 +8,7 @@ export interface CrosspostClientConfig {
|
|
8
8
|
* Base URL for the Crosspost API
|
9
9
|
* @default 'https://open-crosspost-proxy.deno.dev'
|
10
10
|
*/
|
11
|
-
baseUrl?: string;
|
11
|
+
baseUrl?: string | URL;
|
12
12
|
/**
|
13
13
|
* NEAR authentication data obtained from near-sign-verify
|
14
14
|
*/
|
@@ -24,6 +24,6 @@ export interface CrosspostClientConfig {
|
|
24
24
|
* Default configuration values for the CrosspostClient
|
25
25
|
*/
|
26
26
|
export const DEFAULT_CONFIG: Required<Omit<CrosspostClientConfig, 'nearAuthData'>> = {
|
27
|
-
baseUrl: 'https://open-crosspost-proxy.deno.dev/',
|
27
|
+
baseUrl: new URL('https://open-crosspost-proxy.deno.dev/'),
|
28
28
|
timeout: 30000,
|
29
29
|
};
|
package/src/core/request.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import { ApiErrorCode, type StatusCode } from '@crosspost/types';
|
1
|
+
import { ApiErrorCode, type ApiResponse, type StatusCode } from '@crosspost/types';
|
2
2
|
import { createAuthToken, type NearAuthData } from 'near-sign-verify';
|
3
3
|
import {
|
4
4
|
createNetworkError,
|
@@ -14,7 +14,7 @@ export interface RequestOptions {
|
|
14
14
|
/**
|
15
15
|
* Base URL for the API
|
16
16
|
*/
|
17
|
-
baseUrl:
|
17
|
+
baseUrl: URL;
|
18
18
|
/**
|
19
19
|
* NEAR authentication data for generating auth tokens
|
20
20
|
* Required for non-GET requests, optional for GET requests
|
@@ -39,7 +39,7 @@ export interface RequestOptions {
|
|
39
39
|
* @param options The request options
|
40
40
|
* @param data Optional request data
|
41
41
|
* @param query Optional query parameters
|
42
|
-
* @returns A promise resolving with the
|
42
|
+
* @returns A promise resolving with the API response object
|
43
43
|
* @throws {CrosspostError}
|
44
44
|
* - If the request fails (network error, timeout)
|
45
45
|
* - If the response is not valid JSON
|
@@ -57,21 +57,16 @@ export async function makeRequest<
|
|
57
57
|
options: RequestOptions,
|
58
58
|
data?: TRequest,
|
59
59
|
query?: TQuery,
|
60
|
-
): Promise<TResponse
|
61
|
-
|
60
|
+
): Promise<ApiResponse<TResponse>> {
|
61
|
+
const url = new URL(path, options.baseUrl);
|
62
62
|
|
63
63
|
// Add query parameters if provided
|
64
64
|
if (query && typeof query === 'object' && Object.keys(query).length > 0) {
|
65
|
-
const queryParams = new URLSearchParams();
|
66
65
|
for (const [key, value] of Object.entries(query)) {
|
67
66
|
if (value !== undefined && value !== null) {
|
68
|
-
|
67
|
+
url.searchParams.append(key, String(value));
|
69
68
|
}
|
70
69
|
}
|
71
|
-
const queryString = queryParams.toString();
|
72
|
-
if (queryString) {
|
73
|
-
url += `?${queryString}`;
|
74
|
-
}
|
75
70
|
}
|
76
71
|
|
77
72
|
// Create a context object for error enrichment
|
@@ -123,7 +118,7 @@ export async function makeRequest<
|
|
123
118
|
const response = await fetch(url, requestOptions);
|
124
119
|
clearTimeout(timeoutId);
|
125
120
|
|
126
|
-
let responseData:
|
121
|
+
let responseData: ApiResponse<TResponse>;
|
127
122
|
try {
|
128
123
|
responseData = await response.json();
|
129
124
|
} catch (jsonError) {
|
@@ -151,9 +146,12 @@ export async function makeRequest<
|
|
151
146
|
}
|
152
147
|
|
153
148
|
// Validate success response structure
|
154
|
-
if (
|
149
|
+
if (
|
150
|
+
!responseData || typeof responseData !== 'object' || !('success' in responseData) ||
|
151
|
+
!('meta' in responseData)
|
152
|
+
) {
|
155
153
|
throw new CrosspostError(
|
156
|
-
'Invalid
|
154
|
+
'Invalid response format from API',
|
157
155
|
ApiErrorCode.INVALID_RESPONSE,
|
158
156
|
response.status as StatusCode,
|
159
157
|
{ responseData },
|
@@ -161,15 +159,7 @@ export async function makeRequest<
|
|
161
159
|
}
|
162
160
|
|
163
161
|
if (responseData.success) {
|
164
|
-
|
165
|
-
throw new CrosspostError(
|
166
|
-
'API returned success but no data',
|
167
|
-
ApiErrorCode.INVALID_RESPONSE,
|
168
|
-
response.status as StatusCode,
|
169
|
-
{ responseData },
|
170
|
-
);
|
171
|
-
}
|
172
|
-
return responseData.data as TResponse;
|
162
|
+
return responseData as ApiResponse<TResponse>;
|
173
163
|
}
|
174
164
|
|
175
165
|
// If we get here, we have response.ok but success: false
|
@@ -187,7 +177,10 @@ export async function makeRequest<
|
|
187
177
|
if (
|
188
178
|
error instanceof TypeError || (error instanceof DOMException && error.name === 'AbortError')
|
189
179
|
) {
|
190
|
-
throw enrichErrorWithContext(
|
180
|
+
throw enrichErrorWithContext(
|
181
|
+
createNetworkError(error, url.toString(), options.timeout),
|
182
|
+
context,
|
183
|
+
);
|
191
184
|
}
|
192
185
|
|
193
186
|
// For any other errors, wrap them with context
|