@crosspost/sdk 0.1.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 ADDED
@@ -0,0 +1,274 @@
1
+ # @crosspost/sdk
2
+
3
+ SDK for interacting with the Crosspost API.
4
+
5
+ ## Overview
6
+
7
+ This package provides a client for interacting with the Crosspost API, allowing you to easily
8
+ integrate social media posting capabilities into your applications. The SDK is designed to be
9
+ flexible and easy to use, with support for multiple authentication methods and platforms.
10
+
11
+ ## Features
12
+
13
+ - Unified client for all supported platforms
14
+ - Flexible authentication:
15
+ - Direct `nearAuthData` injection
16
+ - Automatic cookie-based authentication (`__crosspost_auth`)
17
+ - Explicit authentication via `setAuthentication` method
18
+ - Platform-specific clients (Twitter, with more to come)
19
+ - Type-safe request/response handling using `@crosspost/types`
20
+ - Comprehensive error handling with specific `ApiError` and `PlatformError` types
21
+ - CSRF protection via Double Submit Cookie pattern
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ bun install @crosspost/sdk
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Initializing the SDK
32
+
33
+ The SDK can be initialized in several ways depending on how you manage authentication:
34
+
35
+ **1. Cookie-Based Authentication (Recommended for Browsers)**
36
+
37
+ If the user has previously authenticated via the API, the SDK can automatically use the
38
+ authentication data stored in the `__crosspost_auth` cookie.
39
+
40
+ ```typescript
41
+ import { CrosspostClient } from '@crosspost/sdk';
42
+
43
+ // Client will automatically try to load auth from the cookie
44
+ const client = new CrosspostClient({
45
+ baseUrl: 'https://your-crosspost-api.com', // Optional: Defaults to official API
46
+ });
47
+
48
+ // If the cookie exists and is valid, requests will be authenticated.
49
+ // If not, authenticated requests will throw an ApiError.
50
+ ```
51
+
52
+ The cookie is stored with secure attributes:
53
+
54
+ - `secure: true` - Only sent over HTTPS
55
+ - `sameSite: 'lax'` - Provides CSRF protection while allowing top-level navigation
56
+ - `path: '/'` - Available across the entire domain
57
+ - `expires: 30 days` - Persists for 30 days
58
+
59
+ **2. Direct Authentication**
60
+
61
+ Provide the `nearAuthData` object directly if you have obtained it through other means (e.g.,
62
+ server-side flow, manual signing).
63
+
64
+ ```typescript
65
+ import { CrosspostClient } from '@crosspost/sdk';
66
+ import type { NearAuthData } from 'near-sign-verify'; // Assuming this type exists
67
+
68
+ const nearAuthData: NearAuthData = {
69
+ account_id: 'example.near',
70
+ public_key: 'ed25519:...',
71
+ signature: '...',
72
+ message: '...',
73
+ nonce: '...',
74
+ recipient: 'crosspost-api.near',
75
+ // callback_url and state are optional
76
+ };
77
+
78
+ const client = new CrosspostClient({
79
+ baseUrl: 'https://your-crosspost-api.com',
80
+ nearAuthData: nearAuthData,
81
+ });
82
+ ```
83
+
84
+ **3. Explicit Authentication**
85
+
86
+ Initialize the client without authentication and set it later, for example, after a user logs in via
87
+ a NEAR wallet connection. This method also stores the authentication data in the `__crosspost_auth`
88
+ cookie for future use.
89
+
90
+ ```typescript
91
+ import { CrosspostClient } from '@crosspost/sdk';
92
+ import type { NearAuthData } from 'near-sign-verify';
93
+
94
+ const client = new CrosspostClient({
95
+ baseUrl: 'https://your-crosspost-api.com',
96
+ });
97
+
98
+ // Later, after obtaining the signature...
99
+ async function handleAuthentication(nearAuthData: NearAuthData) {
100
+ try {
101
+ // This sets the auth data in the client and stores it in the cookie
102
+ await client.setAuthentication(nearAuthData);
103
+ console.log('Authentication successful and stored.');
104
+ // Client is now ready for authenticated requests
105
+ } catch (error) {
106
+ console.error('Authentication failed:', error);
107
+ }
108
+ }
109
+ ```
110
+
111
+ ### Making Authenticated Requests (Example: Twitter Client)
112
+
113
+ ```typescript
114
+ // Create a post
115
+ const createPostResponse = await client.twitter.createPost({
116
+ content: {
117
+ text: 'Hello from Crosspost SDK!',
118
+ },
119
+ });
120
+
121
+ console.log(`Post created with ID: ${createPostResponse.id}`);
122
+
123
+ // Create a post with media
124
+ const createPostWithMediaResponse = await client.twitter.createPost({
125
+ content: {
126
+ text: 'Check out this image!',
127
+ media: [
128
+ {
129
+ type: 'image',
130
+ url: 'https://example.com/image.jpg',
131
+ },
132
+ ],
133
+ },
134
+ });
135
+
136
+ // Like a post
137
+ await client.twitter.likePost({
138
+ postId: '1234567890',
139
+ });
140
+
141
+ // Repost a post
142
+ await client.twitter.repost({
143
+ postId: '1234567890',
144
+ });
145
+
146
+ // Reply to a post
147
+ await client.twitter.reply({
148
+ postId: '1234567890',
149
+ content: {
150
+ text: 'This is a reply!',
151
+ },
152
+ });
153
+
154
+ // Delete a post
155
+ await client.twitter.deletePost({
156
+ postId: '1234567890',
157
+ });
158
+ ```
159
+
160
+ ### Error Handling
161
+
162
+ ```typescript
163
+ import { ApiError, ApiErrorCode, CrosspostClient, PlatformError } from '@crosspost/sdk';
164
+
165
+ try {
166
+ // Ensure client is authenticated (either via cookie or direct data)
167
+ const response = await client.post.createPost({ // Assuming a generic post API exists
168
+ targets: [{ platform: 'twitter', userId: 'twitter_user_id' }], // Example target
169
+ content: {
170
+ text: 'Hello from Crosspost SDK!',
171
+ },
172
+ });
173
+
174
+ console.log(`Post created with ID: ${response.id}`);
175
+ } catch (error) {
176
+ if (error instanceof ApiError) {
177
+ // Handle authentication errors
178
+ if (error.code === ApiErrorCode.UNAUTHORIZED) {
179
+ console.error('Authentication required. Please sign in with your NEAR wallet.');
180
+ // Redirect to authentication flow or show login UI
181
+ } else {
182
+ console.error(`API Error: ${error.message}`);
183
+ console.error(`Error Code: ${error.code}`); // e.g., RATE_LIMITED
184
+ console.error(`Status: ${error.status}`); // HTTP status code
185
+ console.error(`Details:`, error.details); // Additional context
186
+ console.error(`Recoverable: ${error.recoverable}`);
187
+ }
188
+ } else if (error instanceof PlatformError) {
189
+ // Handle errors specific to a platform (e.g., Twitter API error)
190
+ console.error(`Platform Error (${error.platform}): ${error.message}`);
191
+ console.error(`Original Error:`, error.originalError);
192
+ } else {
193
+ console.error(`Unexpected error:`, error);
194
+ }
195
+ }
196
+ ```
197
+
198
+ ## API Reference
199
+
200
+ ### `CrosspostClient`
201
+
202
+ The main client for interacting with the Crosspost API.
203
+
204
+ #### Constructor
205
+
206
+ ```typescript
207
+ constructor(config?: CrosspostClientConfig)
208
+ ```
209
+
210
+ `CrosspostClientConfig` Options:
211
+
212
+ - `baseUrl?: string`: Base URL of the Crosspost API. Defaults to the official endpoint.
213
+ - `nearAuthData?: NearAuthData`: NEAR authentication data object. If not provided, the client
214
+ attempts to load from the `__crosspost_auth` cookie.
215
+ - `timeout?: number`: Request timeout in milliseconds (default: 30000).
216
+ - `retries?: number`: Number of retries for failed requests (network/5xx errors) (default: 2).
217
+
218
+ #### Methods
219
+
220
+ - `setAuthentication(nearAuthData: NearAuthData): Promise<void>`: Sets the provided `NearAuthData`
221
+ in the client and stores it in the `__crosspost_auth` cookie for future use.
222
+
223
+ #### Properties
224
+
225
+ - `auth`: Instance of `AuthApi` for authentication-related operations.
226
+ - `post`: Instance of `PostApi` for post-related operations.
227
+
228
+ ### API Modules
229
+
230
+ #### `AuthApi` (`client.auth`)
231
+
232
+ - `authorizeNearAccount(): Promise<NearAuthorizationResponse>`: Authorizes the current NEAR account
233
+ (requires `nearAuthData` to be set).
234
+ - `getNearAuthorizationStatus(): Promise<NearAuthorizationResponse>`: Checks if the current NEAR
235
+ account is authorized.
236
+ - `loginToPlatform(platform, options?): Promise<EnhancedApiResponse<any>>`: Initiates the OAuth
237
+ login flow for a platform.
238
+ - `refreshToken(platform): Promise<EnhancedApiResponse<any>>`: Refreshes the platform token.
239
+ - `refreshProfile(platform): Promise<EnhancedApiResponse<any>>`: Refreshes the user's profile from
240
+ the platform.
241
+ - `getAuthStatus(platform): Promise<AuthStatusResponse>`: Gets the authentication status for a
242
+ specific platform.
243
+ - `revokeAuth(platform): Promise<AuthRevokeResponse>`: Revokes access for a specific platform.
244
+ - `getConnectedAccounts(): Promise<ConnectedAccountsResponse>`: Lists all platform accounts
245
+ connected to the NEAR account.
246
+
247
+ #### `PostApi` (`client.post`)
248
+
249
+ - `createPost(request: CreatePostRequest): Promise<CreatePostResponse>`: Creates a new post.
250
+ - `repost(request: RepostRequest): Promise<RepostResponse>`: Reposts an existing post.
251
+ - `quotePost(request: QuotePostRequest): Promise<QuotePostResponse>`: Quotes an existing post.
252
+ - `replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse>`: Replies to an existing
253
+ post.
254
+ - `likePost(request: LikePostRequest): Promise<LikePostResponse>`: Likes a post.
255
+ - `unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse>`: Unlikes a post.
256
+ - `deletePost(request: DeletePostRequest): Promise<DeletePostResponse>`: Deletes one or more posts.
257
+
258
+ ### CSRF Protection
259
+
260
+ The SDK supports the Double Submit Cookie pattern for CSRF protection:
261
+
262
+ 1. The backend API sets a CSRF token in a non-HttpOnly cookie named `XSRF-TOKEN`
263
+ 2. The SDK automatically reads this token and includes it in the `X-CSRF-Token` header for all
264
+ state-changing requests (non-GET)
265
+ 3. The backend API validates that the token in the header matches the token in the cookie
266
+
267
+ This protection is automatically enabled when the backend API is configured to use CSRF tokens.
268
+
269
+ _(Note: Specific platform clients like `client.twitter` might be deprecated in favor of using the
270
+ generic `client.post` API with platform targets specified in the request body.)_
271
+
272
+ ## License
273
+
274
+ MIT