@crosspost/sdk 0.2.12 → 0.3.1
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 +149 -222
- package/dist/index.cjs +130 -155
- package/dist/index.d.cts +13 -31
- package/dist/index.d.ts +13 -31
- package/dist/index.js +120 -154
- package/package.json +3 -2
- package/src/api/auth.ts +1 -1
- package/src/core/client.ts +12 -35
- package/src/core/config.ts +3 -5
- package/src/core/request.ts +151 -122
- package/src/index.ts +0 -1
- package/src/utils/error.ts +0 -48
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# @crosspost/sdk
|
|
2
2
|
|
|
3
|
-
SDK for interacting with the Crosspost
|
|
3
|
+
SDK for interacting with the [Crosspost Proxy Service](./../../README.md).
|
|
4
|
+
|
|
5
|
+
This package is designed to be used with
|
|
6
|
+
[near-sign-verify](https://github.com/elliotBraem/near-sign-verify) for authenticating requests via
|
|
7
|
+
a wallet or keypair.
|
|
4
8
|
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
@@ -8,143 +12,163 @@ SDK for interacting with the Crosspost API.
|
|
|
8
12
|
bun install @crosspost/sdk
|
|
9
13
|
```
|
|
10
14
|
|
|
11
|
-
##
|
|
15
|
+
## Usage
|
|
12
16
|
|
|
13
17
|
```typescript
|
|
14
|
-
import
|
|
18
|
+
import * as near from "fastintear"; // or near-api-js for creating key pairs
|
|
19
|
+
import { sign } from "near-sign-verify";
|
|
20
|
+
import {
|
|
21
|
+
CrosspostClient,
|
|
22
|
+
// error handling helpers
|
|
23
|
+
CrosspostError,
|
|
24
|
+
isAuthError,
|
|
25
|
+
isPlatformError,
|
|
26
|
+
isRateLimitError,
|
|
27
|
+
isValidationError
|
|
28
|
+
} from '@crosspost/sdk';
|
|
29
|
+
import type {
|
|
30
|
+
ConnectedAccount,
|
|
31
|
+
CreatePostRequest,
|
|
32
|
+
} from "@crosspost/sdk";
|
|
15
33
|
|
|
16
|
-
// Initialize the client
|
|
34
|
+
// Initialize the client
|
|
17
35
|
const client = new CrosspostClient({
|
|
18
|
-
baseUrl: 'https://your-crosspost-api.com', // Optional: Defaults to official API
|
|
36
|
+
baseUrl: 'https://your-self-hosted-crosspost-api.com', // Optional: Defaults to official API
|
|
19
37
|
});
|
|
20
38
|
|
|
21
|
-
|
|
22
|
-
client.setAuthentication({
|
|
23
|
-
accountId: 'your-account.near',
|
|
24
|
-
publicKey: 'ed25519:...',
|
|
25
|
-
signature: '...',
|
|
26
|
-
message: '...',
|
|
27
|
-
});
|
|
39
|
+
const authToken = await sign({ signer: near, recipient: "crosspost.near", message: "createPost" });
|
|
28
40
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
console.log('Client has authentication data');
|
|
32
|
-
}
|
|
41
|
+
client.setAuthentication(authToken);
|
|
42
|
+
client.setAccountHeader("signer.near")
|
|
33
43
|
|
|
34
|
-
|
|
35
|
-
async function authorizeNearAccount() {
|
|
36
|
-
try {
|
|
37
|
-
// Authorize with NEAR account
|
|
38
|
-
const authResponse = await client.auth.authorizeNearAccount();
|
|
39
|
-
console.log('NEAR authorization successful');
|
|
40
|
-
console.log('Account ID:', authResponse.accountId);
|
|
41
|
-
console.log('Status:', authResponse.status);
|
|
42
|
-
console.log('Connected platforms:', authResponse.connectedPlatforms);
|
|
43
|
-
return true;
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error('NEAR authorization failed');
|
|
46
|
-
if (error instanceof CrosspostError) {
|
|
47
|
-
console.error('Error code:', error.code);
|
|
48
|
-
console.error('Status:', error.status);
|
|
49
|
-
console.error('Details:', error.details);
|
|
50
|
-
console.error('Recoverable:', error.recoverable);
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
44
|
+
const connectedAccounts: ApiResponse<ConnectedAccountsResponse> = await client.auth.getConnectedAccounts():
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
}
|
|
46
|
+
try {
|
|
47
|
+
const response = await await client.post.createPost({
|
|
48
|
+
targets: [
|
|
49
|
+
{
|
|
50
|
+
userId: connectedAccounts[0].userId,
|
|
51
|
+
platform: connectedAccounts[0].platform
|
|
52
|
+
}
|
|
53
|
+
],
|
|
54
|
+
content: [{
|
|
55
|
+
text: "hello world",
|
|
56
|
+
media: {
|
|
57
|
+
data: imageBlob,
|
|
58
|
+
mimeType: 'image/jpeg',
|
|
59
|
+
altText: 'a beautiful sunset',
|
|
60
|
+
}
|
|
61
|
+
}]
|
|
62
|
+
} as CreatePostRequest);
|
|
75
63
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
console.log(`${platform} authorization revoked`);
|
|
82
|
-
console.log('Status:', response.status);
|
|
83
|
-
console.log('Platform:', response.platform);
|
|
84
|
-
console.log('Message:', response.message);
|
|
85
|
-
return true;
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.error(`Failed to revoke ${platform} authorization`);
|
|
88
|
-
if (error instanceof CrosspostError) {
|
|
89
|
-
console.error('Error code:', error.code);
|
|
90
|
-
console.error('Status:', error.status);
|
|
91
|
-
console.error('Details:', error.details);
|
|
92
|
-
}
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
64
|
+
console.log('Post created successfully');
|
|
65
|
+
console.log('Post ID:', response.id);
|
|
66
|
+
console.log('Platform:', response.platform);
|
|
67
|
+
console.log('URL:', response.url);
|
|
68
|
+
console.log('Created at:', response.createdAt);
|
|
96
69
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
console.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// Check if it's an authentication error
|
|
72
|
+
if (isAuthError(error)) {
|
|
73
|
+
console.error('Authentication required. Attempting to authorize...');
|
|
74
|
+
// The account must be authorized with the backend
|
|
75
|
+
const authorized = await client.auth.authorizeNearAccount();
|
|
76
|
+
if (authorized) {
|
|
77
|
+
// Retry the operation
|
|
78
|
+
return createPost();
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
// Handle other error types
|
|
82
|
+
console.error('Error creating post:', error);
|
|
83
|
+
if (error instanceof CrosspostError) {
|
|
84
|
+
// Use error utility functions to handle specific cases
|
|
85
|
+
if (isPlatformError(error)) {
|
|
86
|
+
console.error('Platform:', error.platform);
|
|
87
|
+
console.error('Error code:', error.code);
|
|
88
|
+
console.error('Details:', error.details);
|
|
89
|
+
} else if (isRateLimitError(error)) {
|
|
90
|
+
console.error('Rate limited until:', error.details?.rateLimit?.reset);
|
|
91
|
+
} else if (isValidationError(error)) {
|
|
92
|
+
console.error('Validation errors:', error.details?.validationErrors);
|
|
119
93
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if (error instanceof CrosspostError) {
|
|
124
|
-
// Use error utility functions to handle specific cases
|
|
125
|
-
if (isPlatformError(error)) {
|
|
126
|
-
console.error('Platform:', error.platform);
|
|
127
|
-
console.error('Error code:', error.code);
|
|
128
|
-
console.error('Details:', error.details);
|
|
129
|
-
} else if (isRateLimitError(error)) {
|
|
130
|
-
console.error('Rate limited until:', error.details?.rateLimit?.reset);
|
|
131
|
-
} else if (isValidationError(error)) {
|
|
132
|
-
console.error('Validation errors:', error.details?.validationErrors);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Check if error is recoverable
|
|
136
|
-
if (error.recoverable) {
|
|
137
|
-
console.log('This error is recoverable - retry may succeed');
|
|
138
|
-
}
|
|
139
|
-
} else if (error instanceof Error) {
|
|
140
|
-
// Handle non-API errors (network issues, etc)
|
|
141
|
-
console.error('Unexpected error:', error.message);
|
|
94
|
+
// Check if error is recoverable
|
|
95
|
+
if (error.recoverable) {
|
|
96
|
+
console.log('This error is recoverable - retry may succeed');
|
|
142
97
|
}
|
|
98
|
+
} else if (error instanceof Error) {
|
|
99
|
+
// Handle non-API errors (network issues, etc)
|
|
100
|
+
console.error('Unexpected error:', error.message);
|
|
143
101
|
}
|
|
144
|
-
}
|
|
102
|
+
}
|
|
145
103
|
}
|
|
146
104
|
```
|
|
147
105
|
|
|
106
|
+
## Methods
|
|
107
|
+
|
|
108
|
+
- `client.setAuthentication(authToken: string): Promise<void>` - Sets authentication data, necessary
|
|
109
|
+
for non-GET requests
|
|
110
|
+
- `client.isAuthenticated(): boolean` - Checks if client is authenticated
|
|
111
|
+
- `client.setAccountHeader(accountId: string): Promise<void>` - Sets X-Near-Account Header,
|
|
112
|
+
necessary for GET requests
|
|
113
|
+
- `client.clear(): boolean` - Clears authentication and account header
|
|
114
|
+
|
|
115
|
+
### Auth API (client.auth)
|
|
116
|
+
|
|
117
|
+
- `client.auth.authorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>>` - Authorizes
|
|
118
|
+
NEAR account
|
|
119
|
+
- `client.auth.unauthorizeNearAccount(): Promise<ApiResponse<NearAuthorizationResponse>>` -
|
|
120
|
+
Unauthorizes NEAR account
|
|
121
|
+
- `client.auth.getNearAuthorizationStatus(): Promise<ApiResponse<NearAuthorizationResponse>>` -
|
|
122
|
+
Checks authorization status for authenticated account
|
|
123
|
+
- `client.auth.loginToPlatform(platform, options?): Promise<AuthCallbackResponse | ApiResponse<AuthUrlResponse>>` -
|
|
124
|
+
Opens popup to initiate OAuth flow with platform
|
|
125
|
+
- `client.auth.refreshToken(platform): Promise<ApiResponse<AuthCallbackResponse>>` - Refreshes
|
|
126
|
+
platform token
|
|
127
|
+
- `client.auth.refreshProfile(platform): Promise<ApiResponse<ConnectedAccount>>` - Refreshes user
|
|
128
|
+
profile
|
|
129
|
+
- `client.auth.getAuthStatus(platform): Promise<ApiResponse<AuthStatusResponse>>` - Gets
|
|
130
|
+
authentication status
|
|
131
|
+
- `client.auth.revokeAuth(platform): Promise<ApiResponse<AuthRevokeResponse>>` - Revokes platform
|
|
132
|
+
access
|
|
133
|
+
- `client.auth.getConnectedAccounts(): Promise<ApiResponse<ConnectedAccountsResponse>>` - Lists
|
|
134
|
+
connected accounts
|
|
135
|
+
|
|
136
|
+
### Post API (client.post)
|
|
137
|
+
|
|
138
|
+
Each post operation accepts a request object that includes:
|
|
139
|
+
|
|
140
|
+
- `targets`: Array of `{ platform: string, userId: string }` specifying where to perform the action
|
|
141
|
+
- Additional parameters specific to each operation
|
|
142
|
+
|
|
143
|
+
Available methods:
|
|
144
|
+
|
|
145
|
+
- `client.post.createPost(request: CreatePostRequest): Promise<CreatePostResponse>` - Creates posts
|
|
146
|
+
on specified platforms
|
|
147
|
+
- `client.post.repost(request: RepostRequest): Promise<RepostResponse>` - Reposts an existing post
|
|
148
|
+
- `client.post.quotePost(request: QuotePostRequest): Promise<QuotePostResponse>` - Quotes an
|
|
149
|
+
existing post
|
|
150
|
+
- `client.post.replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse>` - Replies to
|
|
151
|
+
a post
|
|
152
|
+
- `client.post.likePost(request: LikePostRequest): Promise<LikePostResponse>` - Likes a post
|
|
153
|
+
- `client.post.unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse>` - Unlikes a post
|
|
154
|
+
- `client.post.deletePost(request: DeletePostRequest): Promise<DeletePostResponse>` - Deletes posts
|
|
155
|
+
|
|
156
|
+
### Activity API (client.activity)
|
|
157
|
+
|
|
158
|
+
- `client.activity.getLeaderboard(options): Promise<LeaderboardResponse>` - Gets activity
|
|
159
|
+
leaderboard
|
|
160
|
+
- `client.activity.getAccountActivity(signerId, options): Promise<AccountActivityResponse>` - Gets
|
|
161
|
+
account activity
|
|
162
|
+
- `client.activity.getAccountPosts(signerId, options): Promise<AccountPostsResponse>` - Gets account
|
|
163
|
+
posts
|
|
164
|
+
|
|
165
|
+
### System API (client.system)
|
|
166
|
+
|
|
167
|
+
- `client.system.getRateLimits(): Promise<RateLimitsResponse>` - Gets all rate limits
|
|
168
|
+
- `client.system.getEndpointRateLimit(endpoint): Promise<EndpointRateLimitResponse>` - Gets endpoint
|
|
169
|
+
rate limit
|
|
170
|
+
- `client.system.getHealthStatus(): Promise<HealthStatusResponse>` - Gets API health status
|
|
171
|
+
|
|
148
172
|
## API Reference
|
|
149
173
|
|
|
150
174
|
### Pagination
|
|
@@ -166,8 +190,7 @@ console.log(`Current offset: ${response.meta.pagination?.offset}`);
|
|
|
166
190
|
|
|
167
191
|
### Multi-Status Responses
|
|
168
192
|
|
|
169
|
-
|
|
170
|
-
cases with multi-status responses:
|
|
193
|
+
Post operations always return multi-status responses:
|
|
171
194
|
|
|
172
195
|
```typescript
|
|
173
196
|
// Operation targeting multiple platforms
|
|
@@ -176,7 +199,7 @@ const response = await client.post.createPost({
|
|
|
176
199
|
{ platform: 'twitter', userId: 'user1' },
|
|
177
200
|
{ platform: 'facebook', userId: 'user2' },
|
|
178
201
|
],
|
|
179
|
-
content: [{ text: '
|
|
202
|
+
content: [{ text: 'hello world' }],
|
|
180
203
|
});
|
|
181
204
|
|
|
182
205
|
// Check multi-status summary
|
|
@@ -207,7 +230,7 @@ If all operations fail, the SDK throws a `CrosspostError` with the same error st
|
|
|
207
230
|
try {
|
|
208
231
|
await client.post.createPost({...});
|
|
209
232
|
} catch (error) {
|
|
210
|
-
if (error instanceof CrosspostError
|
|
233
|
+
if (error instanceof CrosspostError) {
|
|
211
234
|
// Error structure is identical to response.data.errors in partial success case
|
|
212
235
|
error.details.errors.forEach(err => {
|
|
213
236
|
console.log(`Error on ${err.details.platform}: ${err.message}`);
|
|
@@ -244,70 +267,10 @@ try {
|
|
|
244
267
|
}
|
|
245
268
|
```
|
|
246
269
|
|
|
247
|
-
### CrosspostClient
|
|
248
|
-
|
|
249
|
-
```typescript
|
|
250
|
-
constructor(config?: {
|
|
251
|
-
baseUrl?: string;
|
|
252
|
-
nearAuthData?: NearAuthData;
|
|
253
|
-
timeout?: number;
|
|
254
|
-
retries?: number;
|
|
255
|
-
})
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
#### Methods
|
|
259
|
-
|
|
260
|
-
- `setAuthentication(nearAuthData: NearAuthData): Promise<void>` - Sets authentication data
|
|
261
|
-
- `isAuthenticated(): boolean` - Checks if client is authenticated
|
|
262
|
-
|
|
263
|
-
### Auth API (client.auth)
|
|
264
|
-
|
|
265
|
-
- `authorizeNearAccount(): Promise<NearAuthorizationResponse>` - Authorizes NEAR account
|
|
266
|
-
- `unauthorizeNearAccount(): Promise<NearAuthorizationResponse>` - Unauthorizes NEAR account
|
|
267
|
-
- `getNearAuthorizationStatus(): Promise<NearAuthorizationResponse>` - Checks authorization status
|
|
268
|
-
- `loginToPlatform(platform, options?): Promise<EnhancedApiResponse<any>>` - Initiates OAuth flow
|
|
269
|
-
- `refreshToken(platform): Promise<EnhancedApiResponse<any>>` - Refreshes platform token
|
|
270
|
-
- `refreshProfile(platform): Promise<EnhancedApiResponse<any>>` - Refreshes user profile
|
|
271
|
-
- `getAuthStatus(platform): Promise<AuthStatusResponse>` - Gets authentication status
|
|
272
|
-
- `revokeAuth(platform): Promise<AuthRevokeResponse>` - Revokes platform access
|
|
273
|
-
- `getConnectedAccounts(): Promise<ConnectedAccountsResponse>` - Lists connected accounts
|
|
274
|
-
|
|
275
|
-
### Post API (client.post)
|
|
276
|
-
|
|
277
|
-
Each post operation accepts a request object that includes:
|
|
278
|
-
|
|
279
|
-
- `targets`: Array of `{ platform: string, userId: string }` specifying where to perform the action
|
|
280
|
-
- Additional parameters specific to each operation
|
|
281
|
-
|
|
282
|
-
Available methods:
|
|
283
|
-
|
|
284
|
-
- `createPost(request: CreatePostRequest): Promise<CreatePostResponse>` - Creates posts on specified
|
|
285
|
-
platforms
|
|
286
|
-
- `repost(request: RepostRequest): Promise<RepostResponse>` - Reposts an existing post
|
|
287
|
-
- `quotePost(request: QuotePostRequest): Promise<QuotePostResponse>` - Quotes an existing post
|
|
288
|
-
- `replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse>` - Replies to a post
|
|
289
|
-
- `likePost(request: LikePostRequest): Promise<LikePostResponse>` - Likes a post
|
|
290
|
-
- `unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse>` - Unlikes a post
|
|
291
|
-
- `deletePost(request: DeletePostRequest): Promise<DeletePostResponse>` - Deletes posts
|
|
292
|
-
|
|
293
|
-
### Activity API (client.activity)
|
|
294
|
-
|
|
295
|
-
- `getLeaderboard(options): Promise<LeaderboardResponse>` - Gets activity leaderboard
|
|
296
|
-
- `getAccountActivity(signerId, options): Promise<AccountActivityResponse>` - Gets account activity
|
|
297
|
-
- `getAccountPosts(signerId, options): Promise<AccountPostsResponse>` - Gets account posts
|
|
298
|
-
|
|
299
|
-
### System API (client.system)
|
|
300
|
-
|
|
301
|
-
- `getRateLimits(): Promise<RateLimitsResponse>` - Gets all rate limits
|
|
302
|
-
- `getEndpointRateLimit(endpoint): Promise<EndpointRateLimitResponse>` - Gets endpoint rate limit
|
|
303
|
-
- `getHealthStatus(): Promise<HealthStatusResponse>` - Gets API health status
|
|
304
|
-
|
|
305
270
|
### Error Handling Utilities
|
|
306
271
|
|
|
307
272
|
```typescript
|
|
308
273
|
import {
|
|
309
|
-
apiWrapper,
|
|
310
|
-
enrichErrorWithContext,
|
|
311
274
|
getErrorDetails,
|
|
312
275
|
getErrorMessage,
|
|
313
276
|
isAuthError,
|
|
@@ -331,21 +294,6 @@ const message = getErrorMessage(error, 'Default message');
|
|
|
331
294
|
|
|
332
295
|
// Get error details
|
|
333
296
|
const details = getErrorDetails(error);
|
|
334
|
-
|
|
335
|
-
// Add context to errors
|
|
336
|
-
const enrichedError = enrichErrorWithContext(error, {
|
|
337
|
-
operation: 'createPost',
|
|
338
|
-
timestamp: Date.now(),
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
// Wrap API calls with error handling
|
|
342
|
-
const result = await apiWrapper(
|
|
343
|
-
async () => {
|
|
344
|
-
// API call implementation
|
|
345
|
-
return await fetch('/api/endpoint');
|
|
346
|
-
},
|
|
347
|
-
{ operation: 'fetchData' }, // Optional context
|
|
348
|
-
);
|
|
349
297
|
```
|
|
350
298
|
|
|
351
299
|
## Usage Examples
|
|
@@ -413,7 +361,7 @@ await client.post.replyToPost({
|
|
|
413
361
|
platform: 'twitter',
|
|
414
362
|
postId: '1234567890',
|
|
415
363
|
content: [{
|
|
416
|
-
text: 'This is a reply
|
|
364
|
+
text: 'This is a reply',
|
|
417
365
|
}],
|
|
418
366
|
});
|
|
419
367
|
|
|
@@ -461,24 +409,3 @@ const rateLimits = await client.system.getRateLimits();
|
|
|
461
409
|
// Get rate limit for a specific endpoint
|
|
462
410
|
const postRateLimit = await client.system.getEndpointRateLimit('post');
|
|
463
411
|
```
|
|
464
|
-
|
|
465
|
-
## Authentication and Security
|
|
466
|
-
|
|
467
|
-
### Authentication Strategy
|
|
468
|
-
|
|
469
|
-
The SDK uses direct authentication with per-request signatures:
|
|
470
|
-
|
|
471
|
-
```typescript
|
|
472
|
-
// Initialize the client
|
|
473
|
-
const client = new CrosspostClient({
|
|
474
|
-
baseUrl: 'https://your-crosspost-api.com',
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
// Before making authenticated requests, set fresh signature
|
|
478
|
-
client.setAuthentication({
|
|
479
|
-
accountId: 'your-account.near',
|
|
480
|
-
publicKey: 'ed25519:...',
|
|
481
|
-
signature: '...',
|
|
482
|
-
message: '...',
|
|
483
|
-
});
|
|
484
|
-
```
|