@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/mod.ts ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @crosspost/sdk
3
+ * SDK for interacting with the Crosspost API
4
+ *
5
+ * This is the Deno entry point for the package.
6
+ */
7
+
8
+ // Export everything from the source directly
9
+ export * from './src/index.ts';
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@crosspost/sdk",
3
+ "version": "0.1.2",
4
+ "description": "SDK for interacting with the Crosspost API",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "src",
19
+ "mod.ts"
20
+ ],
21
+ "scripts": {
22
+ "build": "npm run build:node",
23
+ "build:node": "tsup src/index.ts --format cjs,esm --dts",
24
+ "clean": "rimraf dist",
25
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
26
+ "lint": "eslint src --ext .ts",
27
+ "typecheck": "tsc --noEmit",
28
+ "prepublishOnly": "npm run clean && npm run build"
29
+ },
30
+ "keywords": [
31
+ "crosspost",
32
+ "sdk",
33
+ "api",
34
+ "social-media"
35
+ ],
36
+ "author": "crosspost.near",
37
+ "license": "MIT",
38
+ "dependencies": {
39
+ "@types/js-cookie": "^3.0.6",
40
+ "js-cookie": "^3.0.5",
41
+ "near-sign-verify": "^0.1.1"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^20.10.5",
45
+ "eslint": "^8.56.0",
46
+ "rimraf": "^5.0.5",
47
+ "tsup": "^8.0.1",
48
+ "typescript": "^5.3.3"
49
+ },
50
+ "publishConfig": {
51
+ "access": "public"
52
+ }
53
+ }
@@ -0,0 +1,132 @@
1
+ import type {
2
+ AuthRevokeResponse,
3
+ AuthStatusResponse,
4
+ ConnectedAccountsResponse,
5
+ EnhancedApiResponse,
6
+ NearAuthorizationResponse,
7
+ Platform,
8
+ } from '@crosspost/types';
9
+ import { makeRequest, type RequestOptions } from '../core/request.ts';
10
+
11
+ /**
12
+ * Authentication-related API operations
13
+ */
14
+ export class AuthApi {
15
+ private options: RequestOptions;
16
+
17
+ /**
18
+ * Creates an instance of AuthApi
19
+ * @param options Request options
20
+ */
21
+ constructor(options: RequestOptions) {
22
+ this.options = options;
23
+ }
24
+
25
+ /**
26
+ * Authorizes the NEAR account associated with the provided nearAuthData with the Crosspost service.
27
+ * @returns A promise resolving with the authorization response.
28
+ */
29
+ async authorizeNearAccount(): Promise<NearAuthorizationResponse> {
30
+ return makeRequest<NearAuthorizationResponse>(
31
+ 'POST',
32
+ '/auth/authorize/near',
33
+ this.options,
34
+ {},
35
+ );
36
+ }
37
+
38
+ /**
39
+ * Checks the authorization status of the NEAR account with the Crosspost service.
40
+ * @returns A promise resolving with the authorization status response.
41
+ */
42
+ async getNearAuthorizationStatus(): Promise<NearAuthorizationResponse> {
43
+ return makeRequest<NearAuthorizationResponse>(
44
+ 'GET',
45
+ '/auth/authorize/near/status',
46
+ this.options,
47
+ );
48
+ }
49
+
50
+ /**
51
+ * Initiates the login process for a specific platform.
52
+ * The service handles the OAuth flow; this method triggers it.
53
+ * @param platform The target platform.
54
+ * @param options Optional success and error redirect URLs.
55
+ * @returns A promise resolving with the response from the service (might indicate success/failure or redirect info).
56
+ */
57
+ async loginToPlatform(
58
+ platform: Platform,
59
+ options?: { successUrl?: string; errorUrl?: string },
60
+ ): Promise<EnhancedApiResponse<any>> { // TODO: Refine response type based on actual API
61
+ return makeRequest<EnhancedApiResponse<any>>(
62
+ 'POST',
63
+ `/auth/${platform}/login`,
64
+ this.options,
65
+ options || {},
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Refreshes the authentication token for the specified platform.
71
+ * @param platform The target platform.
72
+ * @returns A promise resolving with the refresh response.
73
+ */
74
+ async refreshToken(platform: Platform): Promise<EnhancedApiResponse<any>> { // TODO: Refine response type
75
+ return makeRequest<EnhancedApiResponse<any>>(
76
+ 'POST',
77
+ `/auth/${platform}/refresh`,
78
+ this.options,
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Refreshes the user's profile information from the specified platform.
84
+ * @param platform The target platform.
85
+ * @returns A promise resolving with the profile refresh response.
86
+ */
87
+ async refreshProfile(platform: Platform): Promise<EnhancedApiResponse<any>> { // TODO: Refine response type
88
+ return makeRequest<EnhancedApiResponse<any>>(
89
+ 'POST',
90
+ `/auth/${platform}/refresh-profile`,
91
+ this.options,
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Gets the authentication status for the specified platform.
97
+ * @param platform The target platform.
98
+ * @returns A promise resolving with the authentication status response.
99
+ */
100
+ async getAuthStatus(platform: Platform): Promise<AuthStatusResponse> {
101
+ return makeRequest<AuthStatusResponse>(
102
+ 'GET',
103
+ `/auth/${platform}/status`,
104
+ this.options,
105
+ );
106
+ }
107
+
108
+ /**
109
+ * Revokes the authentication token for the specified platform.
110
+ * @param platform The target platform.
111
+ * @returns A promise resolving with the revocation response.
112
+ */
113
+ async revokeAuth(platform: Platform): Promise<AuthRevokeResponse> {
114
+ return makeRequest<AuthRevokeResponse>(
115
+ 'DELETE',
116
+ `/auth/${platform}/revoke`,
117
+ this.options,
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Lists all accounts connected to the NEAR account.
123
+ * @returns A promise resolving with the list of connected accounts.
124
+ */
125
+ async getConnectedAccounts(): Promise<ConnectedAccountsResponse> {
126
+ return makeRequest<ConnectedAccountsResponse>(
127
+ 'GET',
128
+ '/auth/accounts',
129
+ this.options,
130
+ );
131
+ }
132
+ }
@@ -0,0 +1,142 @@
1
+ import type {
2
+ CreatePostRequest,
3
+ CreatePostResponse,
4
+ DeletePostRequest,
5
+ DeletePostResponse,
6
+ LikePostRequest,
7
+ LikePostResponse,
8
+ QuotePostRequest,
9
+ QuotePostResponse,
10
+ ReplyToPostRequest,
11
+ ReplyToPostResponse,
12
+ RepostRequest,
13
+ RepostResponse,
14
+ UnlikePostRequest,
15
+ UnlikePostResponse,
16
+ } from '@crosspost/types';
17
+ import { ApiError, ApiErrorCode } from '@crosspost/types';
18
+ import { makeRequest, type RequestOptions } from '../core/request.ts';
19
+
20
+ /**
21
+ * Post-related API operations
22
+ */
23
+ export class PostApi {
24
+ private options: RequestOptions;
25
+
26
+ /**
27
+ * Creates an instance of PostApi
28
+ * @param options Request options
29
+ */
30
+ constructor(options: RequestOptions) {
31
+ this.options = options;
32
+ }
33
+
34
+ /**
35
+ * Creates a new post on the specified target platforms.
36
+ * @param request The post creation request details.
37
+ * @returns A promise resolving with the post creation response.
38
+ */
39
+ async createPost(request: CreatePostRequest): Promise<CreatePostResponse> {
40
+ return makeRequest<CreatePostResponse>(
41
+ 'POST',
42
+ '/api/post',
43
+ this.options,
44
+ request,
45
+ );
46
+ }
47
+
48
+ /**
49
+ * Reposts an existing post on the specified target platforms.
50
+ * @param request The repost request details.
51
+ * @returns A promise resolving with the repost response.
52
+ */
53
+ async repost(request: RepostRequest): Promise<RepostResponse> {
54
+ return makeRequest<RepostResponse>(
55
+ 'POST',
56
+ '/api/post/repost',
57
+ this.options,
58
+ request,
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Quotes an existing post on the specified target platforms.
64
+ * @param request The quote post request details.
65
+ * @returns A promise resolving with the quote post response.
66
+ */
67
+ async quotePost(request: QuotePostRequest): Promise<QuotePostResponse> {
68
+ return makeRequest<QuotePostResponse>(
69
+ 'POST',
70
+ '/api/post/quote',
71
+ this.options,
72
+ request,
73
+ );
74
+ }
75
+
76
+ /**
77
+ * Replies to an existing post on the specified target platforms.
78
+ * @param request The reply request details.
79
+ * @returns A promise resolving with the reply response.
80
+ */
81
+ async replyToPost(request: ReplyToPostRequest): Promise<ReplyToPostResponse> {
82
+ return makeRequest<ReplyToPostResponse>(
83
+ 'POST',
84
+ '/api/post/reply',
85
+ this.options,
86
+ request,
87
+ );
88
+ }
89
+
90
+ /**
91
+ * Likes a post on the specified target platforms.
92
+ * @param request The like request details.
93
+ * @returns A promise resolving with the like response.
94
+ */
95
+ async likePost(request: LikePostRequest): Promise<LikePostResponse> {
96
+ // API endpoint uses postId in the path
97
+ return makeRequest<LikePostResponse>(
98
+ 'POST',
99
+ `/api/post/like/${request.postId}`,
100
+ this.options,
101
+ request,
102
+ );
103
+ }
104
+
105
+ /**
106
+ * Unlikes a post on the specified target platforms.
107
+ * @param request The unlike request details.
108
+ * @returns A promise resolving with the unlike response.
109
+ */
110
+ async unlikePost(request: UnlikePostRequest): Promise<UnlikePostResponse> {
111
+ // API endpoint uses postId in the path
112
+ return makeRequest<UnlikePostResponse>(
113
+ 'DELETE',
114
+ `/api/post/like/${request.postId}`,
115
+ this.options,
116
+ request,
117
+ );
118
+ }
119
+
120
+ /**
121
+ * Deletes one or more posts.
122
+ * @param request The delete request details.
123
+ * @returns A promise resolving with the delete response.
124
+ */
125
+ async deletePost(request: DeletePostRequest): Promise<DeletePostResponse> {
126
+ // API endpoint uses postId in the path, assuming the first post ID for the URL
127
+ const postId = request.posts[0]?.postId || '';
128
+ if (!postId) {
129
+ throw new ApiError(
130
+ 'Post ID is required for deletion path',
131
+ ApiErrorCode.VALIDATION_ERROR,
132
+ 400,
133
+ );
134
+ }
135
+ return makeRequest<DeletePostResponse>(
136
+ 'DELETE',
137
+ `/api/post/${postId}`,
138
+ this.options,
139
+ request,
140
+ );
141
+ }
142
+ }
@@ -0,0 +1,58 @@
1
+ import type { NearAuthData as NearSignatureData } from 'near-sign-verify';
2
+ import { AuthApi } from '../api/auth.ts';
3
+ import { PostApi } from '../api/post.ts';
4
+ import { type CrosspostClientConfig, DEFAULT_CONFIG } from './config.ts';
5
+ import type { RequestOptions } from './request.ts';
6
+ import { getAuthFromCookie, storeAuthInCookie } from '../utils/cookie.ts';
7
+
8
+ /**
9
+ * Main client for interacting with the Crosspost API service.
10
+ */
11
+ export class CrosspostClient {
12
+ /**
13
+ * Authentication-related API operations
14
+ */
15
+ public readonly auth: AuthApi;
16
+
17
+ /**
18
+ * Post-related API operations
19
+ */
20
+ public readonly post: PostApi;
21
+
22
+ private readonly options: RequestOptions;
23
+
24
+ /**
25
+ * Creates an instance of CrosspostClient.
26
+ * @param config Configuration options for the client.
27
+ */
28
+ constructor(config: CrosspostClientConfig = {}) {
29
+ const baseUrl = config.baseUrl || DEFAULT_CONFIG.baseUrl; // you can deploy your own
30
+ const timeout = config.timeout || DEFAULT_CONFIG.timeout;
31
+ const retries = config.retries ?? DEFAULT_CONFIG.retries;
32
+
33
+ // Try to get auth data from config or cookie
34
+ const signature = config.signature || getAuthFromCookie();
35
+
36
+ this.options = {
37
+ baseUrl,
38
+ timeout,
39
+ retries,
40
+ signature,
41
+ };
42
+
43
+ this.auth = new AuthApi(this.options);
44
+ this.post = new PostApi(this.options);
45
+ }
46
+
47
+ /**
48
+ * Sets the authentication data (signature) for the client and stores it in a cookie
49
+ * @param signature The NEAR authentication data
50
+ */
51
+ public async setAuthentication(signature: NearSignatureData): Promise<void> {
52
+ // Update the client's auth data
53
+ this.options.signature = signature;
54
+
55
+ // Store in cookie for persistence
56
+ storeAuthInCookie(signature);
57
+ }
58
+ }
@@ -0,0 +1,35 @@
1
+ import type { NearAuthData as NearSignatureData } from 'near-sign-verify';
2
+
3
+ /**
4
+ * Configuration options for the CrosspostClient
5
+ */
6
+ export interface CrosspostClientConfig {
7
+ /**
8
+ * Base URL for the Crosspost API
9
+ * @default 'https://api.opencrosspost.com'
10
+ */
11
+ baseUrl?: string;
12
+ /**
13
+ * NEAR authentication data obtained from near-sign-verify
14
+ */
15
+ signature?: NearSignatureData;
16
+ /**
17
+ * Request timeout in milliseconds
18
+ * @default 30000
19
+ */
20
+ timeout?: number;
21
+ /**
22
+ * Number of retries for failed requests (specifically for network errors or 5xx status codes)
23
+ * @default 2
24
+ */
25
+ retries?: number;
26
+ }
27
+
28
+ /**
29
+ * Default configuration values for the CrosspostClient
30
+ */
31
+ export const DEFAULT_CONFIG: Required<Omit<CrosspostClientConfig, 'signature'>> = {
32
+ baseUrl: 'https://open-crosspost-proxy.deno.dev/',
33
+ timeout: 30000,
34
+ retries: 2,
35
+ };
@@ -0,0 +1,158 @@
1
+ import { ApiError, ApiErrorCode } from '@crosspost/types';
2
+ import { createAuthToken, type NearAuthData as NearSignatureData } from 'near-sign-verify';
3
+ import { createNetworkError, handleErrorResponse } from '../utils/error.ts';
4
+ import { CSRF_HEADER_NAME, getCsrfToken } from '../utils/cookie.ts';
5
+
6
+ /**
7
+ * Options for making a request to the API
8
+ */
9
+ export interface RequestOptions {
10
+ /**
11
+ * Base URL for the API
12
+ */
13
+ baseUrl: string;
14
+ /**
15
+ * NEAR authentication data for generating auth tokens
16
+ * Can be undefined if not authorize yet
17
+ */
18
+ signature?: NearSignatureData;
19
+ /**
20
+ * Request timeout in milliseconds
21
+ */
22
+ timeout: number;
23
+ /**
24
+ * Number of retries for failed requests
25
+ */
26
+ retries: number;
27
+ }
28
+
29
+ /**
30
+ * Makes a request to the API with retry and error handling
31
+ *
32
+ * @param method The HTTP method
33
+ * @param path The API path
34
+ * @param options The request options
35
+ * @param data Optional request data
36
+ * @returns A promise resolving with the response data
37
+ */
38
+ export async function makeRequest<T>(
39
+ method: string,
40
+ path: string,
41
+ options: RequestOptions,
42
+ data?: any,
43
+ ): Promise<T> {
44
+ const url = `${options.baseUrl}${path.startsWith('/') ? path : `/${path}`}`;
45
+ let lastError: Error | null = null;
46
+
47
+ // Check if authentication data is available
48
+ if (!options.signature) {
49
+ throw ApiError.unauthorized('Authentication required. Please provide NEAR signature.');
50
+ }
51
+
52
+ for (let attempt = 0; attempt <= options.retries; attempt++) {
53
+ const controller = new AbortController();
54
+ const timeoutId = setTimeout(() => controller.abort(), options.timeout);
55
+
56
+ try {
57
+ const headers: Record<string, string> = {
58
+ 'Content-Type': 'application/json',
59
+ 'Accept': 'application/json',
60
+ 'Authorization': `Bearer ${createAuthToken(options.signature)}`,
61
+ };
62
+
63
+ // Add CSRF token for state-changing requests (non-GET)
64
+ if (method !== 'GET') {
65
+ const csrfToken = getCsrfToken();
66
+ if (csrfToken) {
67
+ headers[CSRF_HEADER_NAME] = csrfToken;
68
+ }
69
+ }
70
+
71
+ const requestOptions: RequestInit = {
72
+ method,
73
+ headers,
74
+ body: method !== 'GET' && data ? JSON.stringify(data) : undefined,
75
+ signal: controller.signal,
76
+ };
77
+
78
+ const response = await fetch(url, requestOptions);
79
+ clearTimeout(timeoutId); // Clear timeout if fetch completes
80
+
81
+ let responseData: any;
82
+ try {
83
+ responseData = await response.json();
84
+ } catch (jsonError) {
85
+ // If JSON parsing fails, throw a specific error or handle based on status
86
+ if (!response.ok) {
87
+ throw new ApiError(
88
+ `API request failed with status ${response.status} and non-JSON response`,
89
+ ApiErrorCode.NETWORK_ERROR, // Or a more specific code
90
+ response.status as any,
91
+ { originalStatusText: response.statusText },
92
+ );
93
+ }
94
+ // If response was ok but JSON failed, maybe it was an empty 204 response?
95
+ if (response.status === 204) return {} as T; // Handle No Content
96
+ // Otherwise, rethrow JSON parse error or a custom error
97
+ throw new ApiError(
98
+ `Failed to parse JSON response: ${
99
+ jsonError instanceof Error ? jsonError.message : String(jsonError)
100
+ }`,
101
+ ApiErrorCode.INTERNAL_ERROR, // Or NETWORK_ERROR?
102
+ response.status as any,
103
+ );
104
+ }
105
+
106
+ if (!response.ok) {
107
+ lastError = handleErrorResponse(responseData, response.status);
108
+ // Retry only on 5xx errors or potentially recoverable errors if defined
109
+ const shouldRetry = response.status >= 500 ||
110
+ (lastError instanceof ApiError && lastError.recoverable);
111
+ if (shouldRetry && attempt < options.retries) {
112
+ await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
113
+ continue; // Retry
114
+ }
115
+ throw lastError; // Throw error if not retrying or retries exhausted
116
+ }
117
+
118
+ // Handle cases where API indicates failure within a 2xx response
119
+ if (
120
+ responseData && typeof responseData === 'object' && 'success' in responseData &&
121
+ !responseData.success && responseData.error
122
+ ) {
123
+ lastError = handleErrorResponse(responseData, response.status);
124
+ // Decide if this specific type of "successful" response with an error payload should be retried
125
+ const shouldRetry = lastError instanceof ApiError && lastError.recoverable;
126
+ if (shouldRetry && attempt < options.retries) {
127
+ await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
128
+ continue; // Retry
129
+ }
130
+ throw lastError;
131
+ }
132
+
133
+ return responseData as T; // Success
134
+ } catch (error) {
135
+ clearTimeout(timeoutId); // Clear timeout on error
136
+ lastError = error as Error; // Store the error
137
+
138
+ // Handle fetch/network errors specifically for retries
139
+ const isNetworkError = error instanceof TypeError ||
140
+ (error instanceof DOMException && error.name === 'AbortError');
141
+ if (isNetworkError && attempt < options.retries) {
142
+ await new Promise((resolve) => setTimeout(resolve, 1000 * Math.pow(2, attempt))); // Exponential backoff
143
+ continue; // Retry network error
144
+ }
145
+
146
+ // If it's not a known ApiError/PlatformError, wrap it
147
+ if (!(error instanceof ApiError)) {
148
+ throw createNetworkError(error, url, options.timeout);
149
+ }
150
+
151
+ throw error; // Re-throw known ApiError or final network error
152
+ }
153
+ }
154
+
155
+ // Should not be reachable if retries >= 0, but needed for type safety
156
+ throw lastError ||
157
+ new ApiError('Request failed after multiple retries', ApiErrorCode.INTERNAL_ERROR, 500);
158
+ }
package/src/index.ts ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @crosspost/sdk
3
+ * SDK for interacting with the Crosspost API
4
+ */
5
+
6
+ // Export main client
7
+ export { CrosspostClient } from './core/client.js';
8
+ export { CrosspostClientConfig } from './core/config.js';
9
+
10
+ // Export API modules for advanced usage
11
+ export { AuthApi } from './api/auth.js';
12
+ export { PostApi } from './api/post.js';
13
+
14
+ // Export utility functions
15
+ export { createNetworkError, handleErrorResponse } from './utils/error.js';
16
+ export {
17
+ AUTH_COOKIE_NAME,
18
+ AUTH_COOKIE_OPTIONS,
19
+ clearAuthCookie,
20
+ CSRF_COOKIE_NAME,
21
+ CSRF_HEADER_NAME,
22
+ getAuthFromCookie,
23
+ getCsrfToken,
24
+ storeAuthInCookie,
25
+ } from './utils/cookie.js';
26
+
27
+ // Re-export types from @crosspost/types for convenience
28
+ export * from '@crosspost/types';
@@ -0,0 +1,75 @@
1
+ import Cookies from 'js-cookie';
2
+ import type { NearAuthData } from 'near-sign-verify';
3
+
4
+ export const AUTH_COOKIE_NAME = '__crosspost_auth';
5
+ export const CSRF_COOKIE_NAME = 'XSRF-TOKEN';
6
+ export const CSRF_HEADER_NAME = 'X-CSRF-Token';
7
+
8
+ export const AUTH_COOKIE_OPTIONS: Cookies.CookieAttributes = {
9
+ secure: true,
10
+ sameSite: 'lax', // how could we make this none?
11
+ path: '/',
12
+ expires: 30, // 30 days
13
+ };
14
+
15
+ /**
16
+ * Gets authentication data from the cookie
17
+ * @returns The NearAuthData object or undefined if not found
18
+ */
19
+ export function getAuthFromCookie(): NearAuthData | undefined {
20
+ try {
21
+ if (typeof document === 'undefined') {
22
+ return undefined;
23
+ }
24
+
25
+ const cookieValue = Cookies.get(AUTH_COOKIE_NAME);
26
+ if (!cookieValue) {
27
+ return undefined;
28
+ }
29
+
30
+ return JSON.parse(cookieValue) as NearAuthData;
31
+ } catch (error) {
32
+ console.error('Failed to parse auth cookie:', error);
33
+ return undefined;
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Stores authentication data in a secure cookie
39
+ * @param authData The NearAuthData object to store
40
+ */
41
+ export function storeAuthInCookie(authData: NearAuthData): void {
42
+ try {
43
+ if (typeof document === 'undefined') {
44
+ return;
45
+ }
46
+
47
+ const cookieValue = JSON.stringify(authData);
48
+ Cookies.set(AUTH_COOKIE_NAME, cookieValue, AUTH_COOKIE_OPTIONS);
49
+ } catch (error) {
50
+ console.error('Failed to store auth cookie:', error);
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Clears the authentication cookie
56
+ */
57
+ export function clearAuthCookie(): void {
58
+ if (typeof document === 'undefined') {
59
+ return;
60
+ }
61
+
62
+ Cookies.remove(AUTH_COOKIE_NAME, { path: AUTH_COOKIE_OPTIONS.path });
63
+ }
64
+
65
+ /**
66
+ * Gets the CSRF token from the cookie
67
+ * @returns The CSRF token or undefined if not found
68
+ */
69
+ export function getCsrfToken(): string | undefined {
70
+ if (typeof document === 'undefined') {
71
+ return undefined;
72
+ }
73
+
74
+ return Cookies.get(CSRF_COOKIE_NAME);
75
+ }