@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 CHANGED
@@ -1,6 +1,10 @@
1
1
  # @crosspost/sdk
2
2
 
3
- SDK for interacting with the Crosspost API.
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
- ## Quick Start
15
+ ## Usage
12
16
 
13
17
  ```typescript
14
- import { CrosspostClient, CrosspostError, isAuthError } from '@crosspost/sdk';
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 (authentication can be provided later)
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
- // Set authentication with fresh signature for the request
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
- // Check if client has authentication data set
30
- if (client.isAuthenticated()) {
31
- console.log('Client has authentication data');
32
- }
41
+ client.setAuthentication(authToken);
42
+ client.setAccountHeader("signer.near")
33
43
 
34
- // NEAR Account Authorization
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
- // Unauthorize NEAR Account
57
- async function unauthorizeNearAccount() {
58
- try {
59
- // Unauthorize NEAR account (removes all platform connections)
60
- const response = await client.auth.unauthorizeNearAccount();
61
- console.log('NEAR account unauthorized');
62
- console.log('Status:', response.status);
63
- console.log('Message:', response.message);
64
- return true;
65
- } catch (error) {
66
- console.error('Failed to unauthorize NEAR account');
67
- if (error instanceof CrosspostError) {
68
- console.error('Error code:', error.code);
69
- console.error('Status:', error.status);
70
- console.error('Details:', error.details);
71
- }
72
- return false;
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
- // Revoke Platform Authorization
77
- async function revokePlatformAuth(platform) {
78
- try {
79
- // Revoke specific platform authorization
80
- const response = await client.auth.revokeAuth(platform);
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
- // Example usage
98
- async function createPost() {
99
- try {
100
- const response = await client.post.createPost({
101
- targets: [{ platform: 'twitter', userId: 'your-twitter-id' }],
102
- content: {
103
- text: 'Hello from Crosspost SDK!',
104
- },
105
- });
106
- console.log('Post created successfully');
107
- console.log('Post ID:', response.id);
108
- console.log('Platform:', response.platform);
109
- console.log('URL:', response.url);
110
- console.log('Created at:', response.createdAt);
111
- } catch (error) {
112
- // Check if it's an authentication error
113
- if (isAuthError(error)) {
114
- console.error('Authentication required. Attempting to authorize...');
115
- const authorized = await authorizeNearAccount();
116
- if (authorized) {
117
- // Retry the operation
118
- return createPost();
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
- } else {
121
- // Handle other error types
122
- console.error('Error creating post:', error);
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
- Some operations that target multiple platforms may result in partial success. The SDK handles these
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: 'Hello world!' }],
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 && error.details?.errors) {
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
- ```