@hasna/connectors 1.3.36 → 1.3.37
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/bin/index.js +167 -241
- package/bin/mcp.js +190 -267
- package/bin/serve.js +264 -341
- package/connectors/bluesky/README.md +34 -0
- package/connectors/bluesky/package.json +41 -0
- package/connectors/bluesky/src/api/client.test.ts +122 -0
- package/connectors/bluesky/src/api/client.ts +194 -0
- package/connectors/bluesky/src/api/index.ts +108 -0
- package/connectors/bluesky/src/index.ts +17 -0
- package/connectors/bluesky/src/types/index.ts +46 -0
- package/connectors/bluesky/tsconfig.json +16 -0
- package/connectors/x/src/api/media.ts +4 -3
- package/dashboard/dist/assets/index-ClBXkNbL.css +1 -0
- package/dashboard/dist/assets/index-DvfmyAO4.js +284 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/.types/connectors/bluesky/src/api/client.d.ts +73 -0
- package/dist/.types/connectors/bluesky/src/api/index.d.ts +76 -0
- package/dist/.types/connectors/bluesky/src/index.d.ts +11 -0
- package/dist/.types/connectors/bluesky/src/types/index.d.ts +33 -0
- package/dist/.types/connectors/x/src/api/client.d.ts +96 -0
- package/dist/.types/connectors/x/src/api/index.d.ts +80 -0
- package/dist/.types/connectors/x/src/api/media.d.ts +54 -0
- package/dist/.types/connectors/x/src/api/oauth.d.ts +82 -0
- package/dist/.types/connectors/x/src/api/oauth1.d.ts +68 -0
- package/dist/.types/connectors/x/src/api/tweets.d.ts +175 -0
- package/dist/.types/connectors/x/src/api/users.d.ts +127 -0
- package/dist/.types/connectors/x/src/cli/index.d.ts +2 -0
- package/dist/.types/connectors/x/src/index.d.ts +6 -0
- package/dist/.types/connectors/x/src/types/index.d.ts +156 -0
- package/dist/.types/connectors/x/src/utils/config.d.ts +99 -0
- package/dist/.types/connectors/x/src/utils/output.d.ts +8 -0
- package/dist/.types/src/social/bluesky.d.ts +65 -0
- package/dist/.types/src/social/errors.d.ts +9 -0
- package/dist/.types/src/social/index.d.ts +16 -0
- package/dist/.types/src/social/mastodon.d.ts +32 -0
- package/dist/.types/src/social/types.d.ts +73 -0
- package/dist/.types/src/social/util.d.ts +5 -0
- package/dist/.types/src/social/x.d.ts +82 -0
- package/dist/cli/components/App.d.ts +1 -2
- package/dist/cli/components/CategorySelect.d.ts +1 -2
- package/dist/cli/components/ConnectorSelect.d.ts +1 -2
- package/dist/cli/components/Header.d.ts +1 -2
- package/dist/cli/components/InstallProgress.d.ts +1 -2
- package/dist/cli/components/SearchView.d.ts +1 -2
- package/dist/index.js +122 -109
- package/dist/social/index.js +1531 -0
- package/package.json +7 -3
- package/dashboard/dist/assets/index-DJjxFlTl.css +0 -1
- package/dashboard/dist/assets/index-DNPZ58_i.js +0 -284
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>Hasna Connectors</title>
|
|
7
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-DvfmyAO4.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-ClBXkNbL.css">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="root"></div>
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type AtUriRef, type BlueskyConfig, type BlueskySession, type CreateRecordResult } from "../types/index";
|
|
2
|
+
/**
|
|
3
|
+
* Minimal AT Protocol (Bluesky) transport — raw fetch, zero dependencies, no fs.
|
|
4
|
+
*
|
|
5
|
+
* Credentials are passed in per construction; the session is created lazily on the
|
|
6
|
+
* first authenticated call (com.atproto.server.createSession). Nothing is persisted.
|
|
7
|
+
*/
|
|
8
|
+
export declare class BlueskyClient {
|
|
9
|
+
private readonly identifier;
|
|
10
|
+
private readonly appPassword;
|
|
11
|
+
private readonly pds;
|
|
12
|
+
private session?;
|
|
13
|
+
constructor(config: BlueskyConfig);
|
|
14
|
+
private xrpc;
|
|
15
|
+
/** Create (or return cached) a session via com.atproto.server.createSession. */
|
|
16
|
+
ensureSession(): Promise<BlueskySession>;
|
|
17
|
+
/** Create a record in the authenticated user's repo. */
|
|
18
|
+
createRecord(collection: string, record: Record<string, unknown>): Promise<CreateRecordResult>;
|
|
19
|
+
/** Delete a record by its at:// URI (parses repo/collection/rkey). */
|
|
20
|
+
deleteRecord(uri: string): Promise<void>;
|
|
21
|
+
/** Upload a blob (image/video) — returns the blob ref for embedding. */
|
|
22
|
+
uploadBlob(data: Buffer | Uint8Array, mimeType: string): Promise<{
|
|
23
|
+
blob: unknown;
|
|
24
|
+
}>;
|
|
25
|
+
/** List notifications (used for mentions). */
|
|
26
|
+
listNotifications(options?: {
|
|
27
|
+
limit?: number;
|
|
28
|
+
cursor?: string;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
notifications: Array<{
|
|
31
|
+
uri: string;
|
|
32
|
+
cid: string;
|
|
33
|
+
reason: string;
|
|
34
|
+
indexedAt?: string;
|
|
35
|
+
author?: {
|
|
36
|
+
did: string;
|
|
37
|
+
handle: string;
|
|
38
|
+
};
|
|
39
|
+
record?: {
|
|
40
|
+
text?: string;
|
|
41
|
+
createdAt?: string;
|
|
42
|
+
};
|
|
43
|
+
}>;
|
|
44
|
+
cursor?: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** Fetch hydrated posts by URI (used for analytics/metrics + reply refs). */
|
|
47
|
+
getPosts(uris: string[]): Promise<{
|
|
48
|
+
posts: Array<{
|
|
49
|
+
uri: string;
|
|
50
|
+
cid?: string;
|
|
51
|
+
likeCount?: number;
|
|
52
|
+
repostCount?: number;
|
|
53
|
+
replyCount?: number;
|
|
54
|
+
quoteCount?: number;
|
|
55
|
+
record?: {
|
|
56
|
+
reply?: {
|
|
57
|
+
root?: {
|
|
58
|
+
uri: string;
|
|
59
|
+
cid: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}>;
|
|
64
|
+
}>;
|
|
65
|
+
getSession(): BlueskySession | undefined;
|
|
66
|
+
}
|
|
67
|
+
/** Parse an at:// URI into its components. */
|
|
68
|
+
export declare function parseAtUri(uri: string): {
|
|
69
|
+
repo: string;
|
|
70
|
+
collection: string;
|
|
71
|
+
rkey: string;
|
|
72
|
+
};
|
|
73
|
+
export type { AtUriRef };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { BlueskyClient } from "./client";
|
|
2
|
+
import type { BlueskyConfig, BlueskySession, CreateRecordResult } from "../types/index";
|
|
3
|
+
export interface CreatePostOptions {
|
|
4
|
+
text: string;
|
|
5
|
+
/** at:// URI of the post being replied to (the social SDK passes the parent uri). */
|
|
6
|
+
replyToUri?: string;
|
|
7
|
+
/** Optional embed (e.g. images) built by the caller. */
|
|
8
|
+
embed?: Record<string, unknown>;
|
|
9
|
+
createdAt?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Main Bluesky (AT Protocol) connector class.
|
|
13
|
+
*/
|
|
14
|
+
export declare class Bluesky {
|
|
15
|
+
private readonly client;
|
|
16
|
+
constructor(config: BlueskyConfig);
|
|
17
|
+
static fromEnv(): Bluesky;
|
|
18
|
+
/** Resolve the authenticated account (did + handle). */
|
|
19
|
+
me(): Promise<BlueskySession>;
|
|
20
|
+
/**
|
|
21
|
+
* Create a feed post. For replies, we resolve the root of the thread so the
|
|
22
|
+
* reply ref carries both parent and root strong-refs (AT Protocol requirement).
|
|
23
|
+
*/
|
|
24
|
+
createPost(options: CreatePostOptions): Promise<CreateRecordResult>;
|
|
25
|
+
deletePost(uri: string): Promise<void>;
|
|
26
|
+
/** Upload an image/video blob and return a strong blob ref. */
|
|
27
|
+
uploadBlob(data: Buffer | Uint8Array, mimeType: string): Promise<unknown>;
|
|
28
|
+
listNotifications(options?: {
|
|
29
|
+
limit?: number;
|
|
30
|
+
cursor?: string;
|
|
31
|
+
}): Promise<{
|
|
32
|
+
notifications: Array<{
|
|
33
|
+
uri: string;
|
|
34
|
+
cid: string;
|
|
35
|
+
reason: string;
|
|
36
|
+
indexedAt?: string;
|
|
37
|
+
author?: {
|
|
38
|
+
did: string;
|
|
39
|
+
handle: string;
|
|
40
|
+
};
|
|
41
|
+
record?: {
|
|
42
|
+
text?: string;
|
|
43
|
+
createdAt?: string;
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
46
|
+
cursor?: string;
|
|
47
|
+
}>;
|
|
48
|
+
getPosts(uris: string[]): Promise<{
|
|
49
|
+
posts: Array<{
|
|
50
|
+
uri: string;
|
|
51
|
+
cid?: string;
|
|
52
|
+
likeCount?: number;
|
|
53
|
+
repostCount?: number;
|
|
54
|
+
replyCount?: number;
|
|
55
|
+
quoteCount?: number;
|
|
56
|
+
record?: {
|
|
57
|
+
reply?: {
|
|
58
|
+
root?: {
|
|
59
|
+
uri: string;
|
|
60
|
+
cid: string;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}>;
|
|
65
|
+
}>;
|
|
66
|
+
getClient(): BlueskyClient;
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the strong-refs needed for a reply: the parent ref ({uri,cid}) and the
|
|
69
|
+
* thread root. If the parent is itself a reply, its record carries the thread
|
|
70
|
+
* root; otherwise the parent IS the root. This keeps deep threads correctly
|
|
71
|
+
* rooted per the AT Protocol app.bsky.feed.post reply schema.
|
|
72
|
+
*/
|
|
73
|
+
private resolveReplyRefs;
|
|
74
|
+
}
|
|
75
|
+
export { BlueskyClient, parseAtUri } from "./client";
|
|
76
|
+
export type { BlueskyConfig, BlueskySession, CreateRecordResult } from "../types/index";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hasna/connect-bluesky
|
|
3
|
+
*
|
|
4
|
+
* Bluesky / AT Protocol connector. Stateless, raw-fetch transport with zero
|
|
5
|
+
* runtime dependencies — login via com.atproto.server.createSession, post via
|
|
6
|
+
* com.atproto.repo.createRecord (app.bsky.feed.post), delete via
|
|
7
|
+
* com.atproto.repo.deleteRecord.
|
|
8
|
+
*/
|
|
9
|
+
export { Bluesky, BlueskyClient, parseAtUri } from "./api/index";
|
|
10
|
+
export { BlueskyApiError, type BlueskyConfig, type BlueskySession, type CreateRecordResult, type AtUriRef, } from "./types/index";
|
|
11
|
+
export type { CreatePostOptions } from "./api/index";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export interface BlueskyConfig {
|
|
2
|
+
/** Handle or DID, e.g. "alice.bsky.social" */
|
|
3
|
+
identifier: string;
|
|
4
|
+
/** App password (NOT the account password) */
|
|
5
|
+
appPassword: string;
|
|
6
|
+
/** Personal Data Server base URL. Defaults to https://bsky.social */
|
|
7
|
+
pds?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BlueskySession {
|
|
10
|
+
accessJwt: string;
|
|
11
|
+
refreshJwt: string;
|
|
12
|
+
handle: string;
|
|
13
|
+
did: string;
|
|
14
|
+
email?: string;
|
|
15
|
+
}
|
|
16
|
+
/** A strong-ref to an AT Protocol record (used for reply roots/parents). */
|
|
17
|
+
export interface AtUriRef {
|
|
18
|
+
uri: string;
|
|
19
|
+
cid: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CreateRecordResult {
|
|
22
|
+
uri: string;
|
|
23
|
+
cid: string;
|
|
24
|
+
}
|
|
25
|
+
export interface BlueskyApiErrorBody {
|
|
26
|
+
error?: string;
|
|
27
|
+
message?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare class BlueskyApiError extends Error {
|
|
30
|
+
readonly statusCode: number;
|
|
31
|
+
readonly errorCode?: string;
|
|
32
|
+
constructor(message: string, statusCode: number, errorCode?: string);
|
|
33
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { XConfig, OutputFormat, AuthMethod, AuthStatus } from '../types';
|
|
2
|
+
import { OAuth1Client } from './oauth1';
|
|
3
|
+
export interface RequestOptions {
|
|
4
|
+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
5
|
+
params?: Record<string, string | number | boolean | string[] | undefined>;
|
|
6
|
+
body?: Record<string, unknown> | unknown[] | string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
format?: OutputFormat;
|
|
9
|
+
authMethod?: AuthMethod;
|
|
10
|
+
}
|
|
11
|
+
export declare class XClient {
|
|
12
|
+
private readonly apiKey;
|
|
13
|
+
private readonly apiSecret;
|
|
14
|
+
private bearerToken?;
|
|
15
|
+
private readonly baseUrl;
|
|
16
|
+
private accessToken?;
|
|
17
|
+
private refreshToken?;
|
|
18
|
+
private tokenExpiresAt?;
|
|
19
|
+
private clientId?;
|
|
20
|
+
private clientSecret?;
|
|
21
|
+
private oauth1Client?;
|
|
22
|
+
private onTokenRefresh?;
|
|
23
|
+
constructor(config: XConfig);
|
|
24
|
+
/**
|
|
25
|
+
* Set callback for token refresh events
|
|
26
|
+
*/
|
|
27
|
+
setTokenRefreshCallback(callback: (tokens: {
|
|
28
|
+
accessToken: string;
|
|
29
|
+
refreshToken?: string;
|
|
30
|
+
expiresAt: number;
|
|
31
|
+
}) => void): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get OAuth 2.0 Bearer token using client credentials (app-only)
|
|
34
|
+
*/
|
|
35
|
+
private getAppBearerToken;
|
|
36
|
+
/**
|
|
37
|
+
* Check if user access token is expired
|
|
38
|
+
*/
|
|
39
|
+
private isTokenExpired;
|
|
40
|
+
/**
|
|
41
|
+
* Refresh the user access token
|
|
42
|
+
*/
|
|
43
|
+
private refreshUserToken;
|
|
44
|
+
/**
|
|
45
|
+
* Get the appropriate access token for requests
|
|
46
|
+
*/
|
|
47
|
+
private getAccessToken;
|
|
48
|
+
/**
|
|
49
|
+
* Determine the auth method to use
|
|
50
|
+
*/
|
|
51
|
+
getAuthMethod(): AuthMethod;
|
|
52
|
+
/**
|
|
53
|
+
* Get auth status
|
|
54
|
+
*/
|
|
55
|
+
getAuthStatus(): AuthStatus;
|
|
56
|
+
/**
|
|
57
|
+
* Check if we have user context (OAuth 2.0)
|
|
58
|
+
*/
|
|
59
|
+
hasUserContext(): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Check if we have OAuth 1.0a credentials
|
|
62
|
+
*/
|
|
63
|
+
hasOAuth1(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Get the OAuth 1.0a client (for media uploads)
|
|
66
|
+
*/
|
|
67
|
+
getOAuth1Client(): OAuth1Client | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Set user tokens (for after OAuth flow)
|
|
70
|
+
*/
|
|
71
|
+
setUserTokens(tokens: {
|
|
72
|
+
accessToken: string;
|
|
73
|
+
refreshToken?: string;
|
|
74
|
+
expiresAt?: number;
|
|
75
|
+
}): void;
|
|
76
|
+
/**
|
|
77
|
+
* Set OAuth 1.0a tokens
|
|
78
|
+
*/
|
|
79
|
+
setOAuth1Tokens(oauthToken: string, oauthTokenSecret: string): void;
|
|
80
|
+
private buildUrl;
|
|
81
|
+
/**
|
|
82
|
+
* Make an authenticated request to the X API v2
|
|
83
|
+
*/
|
|
84
|
+
request<T>(path: string, options?: RequestOptions): Promise<T>;
|
|
85
|
+
get<T>(path: string, params?: Record<string, string | number | boolean | string[] | undefined>): Promise<T>;
|
|
86
|
+
post<T>(path: string, body?: Record<string, unknown> | unknown[] | string | object, params?: Record<string, string | number | boolean | string[] | undefined>): Promise<T>;
|
|
87
|
+
delete<T>(path: string, params?: Record<string, string | number | boolean | string[] | undefined>): Promise<T>;
|
|
88
|
+
/**
|
|
89
|
+
* Get a preview of the API key (for display/debugging)
|
|
90
|
+
*/
|
|
91
|
+
getApiKeyPreview(): string;
|
|
92
|
+
/**
|
|
93
|
+
* Check if bearer token is set
|
|
94
|
+
*/
|
|
95
|
+
hasBearerToken(): boolean;
|
|
96
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { XConfig, AuthStatus } from '../types';
|
|
2
|
+
import { XClient } from './client';
|
|
3
|
+
import { TweetsApi } from './tweets';
|
|
4
|
+
import { UsersApi } from './users';
|
|
5
|
+
import { MediaApi } from './media';
|
|
6
|
+
/**
|
|
7
|
+
* Main X (Twitter) API v2 connector class
|
|
8
|
+
*/
|
|
9
|
+
export declare class X {
|
|
10
|
+
private readonly client;
|
|
11
|
+
private mediaApi?;
|
|
12
|
+
readonly tweets: TweetsApi;
|
|
13
|
+
readonly users: UsersApi;
|
|
14
|
+
constructor(config: XConfig);
|
|
15
|
+
/**
|
|
16
|
+
* Get the media API (requires OAuth 1.0a)
|
|
17
|
+
* Returns undefined if OAuth 1.0a is not configured
|
|
18
|
+
*/
|
|
19
|
+
get media(): MediaApi | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* Check if media upload is available
|
|
22
|
+
*/
|
|
23
|
+
hasMediaUpload(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Create a client from environment variables
|
|
26
|
+
* Looks for X_API_KEY, X_API_SECRET, and optionally OAuth tokens
|
|
27
|
+
*/
|
|
28
|
+
static fromEnv(): X;
|
|
29
|
+
/**
|
|
30
|
+
* Get a preview of the API key (for debugging)
|
|
31
|
+
*/
|
|
32
|
+
getApiKeyPreview(): string;
|
|
33
|
+
/**
|
|
34
|
+
* Check if bearer token is cached
|
|
35
|
+
*/
|
|
36
|
+
hasBearerToken(): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Check if user context is available (OAuth 2.0)
|
|
39
|
+
*/
|
|
40
|
+
hasUserContext(): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Check if OAuth 1.0a is available
|
|
43
|
+
*/
|
|
44
|
+
hasOAuth1(): boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Get current authentication status
|
|
47
|
+
*/
|
|
48
|
+
getAuthStatus(): AuthStatus;
|
|
49
|
+
/**
|
|
50
|
+
* Set user tokens (after OAuth flow)
|
|
51
|
+
*/
|
|
52
|
+
setUserTokens(tokens: {
|
|
53
|
+
accessToken: string;
|
|
54
|
+
refreshToken?: string;
|
|
55
|
+
expiresAt?: number;
|
|
56
|
+
}): void;
|
|
57
|
+
/**
|
|
58
|
+
* Set OAuth 1.0a tokens
|
|
59
|
+
*/
|
|
60
|
+
setOAuth1Tokens(oauthToken: string, oauthTokenSecret: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Set callback for token refresh events
|
|
63
|
+
*/
|
|
64
|
+
setTokenRefreshCallback(callback: (tokens: {
|
|
65
|
+
accessToken: string;
|
|
66
|
+
refreshToken?: string;
|
|
67
|
+
expiresAt: number;
|
|
68
|
+
}) => void): void;
|
|
69
|
+
/**
|
|
70
|
+
* Get the underlying client for direct API access
|
|
71
|
+
*/
|
|
72
|
+
getClient(): XClient;
|
|
73
|
+
}
|
|
74
|
+
export { X as Connector };
|
|
75
|
+
export { XClient } from './client';
|
|
76
|
+
export { TweetsApi } from './tweets';
|
|
77
|
+
export { UsersApi } from './users';
|
|
78
|
+
export { MediaApi } from './media';
|
|
79
|
+
export { OAuth1Client } from './oauth1';
|
|
80
|
+
export * from './oauth';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media Upload API (v1.1)
|
|
3
|
+
* Uses OAuth 1.0a for authentication
|
|
4
|
+
*/
|
|
5
|
+
import { OAuth1Client } from './oauth1';
|
|
6
|
+
export type MediaCategory = 'tweet_image' | 'tweet_gif' | 'tweet_video' | 'dm_image' | 'dm_gif' | 'dm_video';
|
|
7
|
+
export interface MediaUploadResult {
|
|
8
|
+
media_id: number;
|
|
9
|
+
media_id_string: string;
|
|
10
|
+
media_key?: string;
|
|
11
|
+
size?: number;
|
|
12
|
+
expires_after_secs?: number;
|
|
13
|
+
image?: {
|
|
14
|
+
image_type: string;
|
|
15
|
+
w: number;
|
|
16
|
+
h: number;
|
|
17
|
+
};
|
|
18
|
+
video?: {
|
|
19
|
+
video_type: string;
|
|
20
|
+
};
|
|
21
|
+
processing_info?: {
|
|
22
|
+
state: 'pending' | 'in_progress' | 'failed' | 'succeeded';
|
|
23
|
+
check_after_secs?: number;
|
|
24
|
+
progress_percent?: number;
|
|
25
|
+
error?: {
|
|
26
|
+
code: number;
|
|
27
|
+
name: string;
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface MediaUploadOptions {
|
|
33
|
+
altText?: string;
|
|
34
|
+
category?: MediaCategory;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Media Upload API class
|
|
38
|
+
*/
|
|
39
|
+
export declare class MediaApi {
|
|
40
|
+
private oauth1Client;
|
|
41
|
+
constructor(oauth1Client: OAuth1Client);
|
|
42
|
+
/**
|
|
43
|
+
* Upload media from a file path
|
|
44
|
+
*/
|
|
45
|
+
uploadFile(filePath: string, options?: MediaUploadOptions): Promise<MediaUploadResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Upload media from a buffer
|
|
48
|
+
*/
|
|
49
|
+
uploadBuffer(data: Buffer, mimeType: string, options?: MediaUploadOptions): Promise<MediaUploadResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Upload media from a URL
|
|
52
|
+
*/
|
|
53
|
+
uploadFromUrl(url: string, options?: MediaUploadOptions): Promise<MediaUploadResult>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.0 Authorization Code Flow with PKCE
|
|
3
|
+
* For user-context authentication (posting tweets, DMs, etc.)
|
|
4
|
+
*/
|
|
5
|
+
import { type Server } from 'http';
|
|
6
|
+
export declare const OAUTH2_SCOPES: {
|
|
7
|
+
readonly 'tweet.read': "Read tweets";
|
|
8
|
+
readonly 'users.read': "Read user profiles";
|
|
9
|
+
readonly 'follows.read': "Read follows";
|
|
10
|
+
readonly 'list.read': "Read lists";
|
|
11
|
+
readonly 'space.read': "Read spaces";
|
|
12
|
+
readonly 'mute.read': "Read mutes";
|
|
13
|
+
readonly 'like.read': "Read likes";
|
|
14
|
+
readonly 'block.read': "Read blocks";
|
|
15
|
+
readonly 'bookmark.read': "Read bookmarks";
|
|
16
|
+
readonly 'tweet.write': "Post and delete tweets";
|
|
17
|
+
readonly 'follows.write': "Follow and unfollow users";
|
|
18
|
+
readonly 'list.write': "Create, update, delete lists";
|
|
19
|
+
readonly 'mute.write': "Mute and unmute users";
|
|
20
|
+
readonly 'like.write': "Like and unlike tweets";
|
|
21
|
+
readonly 'block.write': "Block and unblock users";
|
|
22
|
+
readonly 'bookmark.write': "Add and remove bookmarks";
|
|
23
|
+
readonly 'dm.read': "Read direct messages";
|
|
24
|
+
readonly 'dm.write': "Send direct messages";
|
|
25
|
+
readonly 'offline.access': "Stay logged in (refresh tokens)";
|
|
26
|
+
};
|
|
27
|
+
export type OAuth2Scope = keyof typeof OAUTH2_SCOPES;
|
|
28
|
+
export declare const DEFAULT_SCOPES: OAuth2Scope[];
|
|
29
|
+
export interface OAuth2Config {
|
|
30
|
+
clientId: string;
|
|
31
|
+
clientSecret?: string;
|
|
32
|
+
redirectUri: string;
|
|
33
|
+
scopes?: OAuth2Scope[];
|
|
34
|
+
}
|
|
35
|
+
export interface OAuth2Tokens {
|
|
36
|
+
accessToken: string;
|
|
37
|
+
refreshToken?: string;
|
|
38
|
+
expiresIn: number;
|
|
39
|
+
expiresAt: number;
|
|
40
|
+
scope: string;
|
|
41
|
+
tokenType: string;
|
|
42
|
+
}
|
|
43
|
+
export interface PKCEChallenge {
|
|
44
|
+
codeVerifier: string;
|
|
45
|
+
codeChallenge: string;
|
|
46
|
+
state: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Generate PKCE code verifier and challenge
|
|
50
|
+
*/
|
|
51
|
+
export declare function generatePKCE(): PKCEChallenge;
|
|
52
|
+
/**
|
|
53
|
+
* Build OAuth 2.0 authorization URL
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildAuthorizationUrl(config: OAuth2Config, pkce: PKCEChallenge): string;
|
|
56
|
+
/**
|
|
57
|
+
* Exchange authorization code for tokens
|
|
58
|
+
*/
|
|
59
|
+
export declare function exchangeCodeForTokens(config: OAuth2Config, code: string, codeVerifier: string): Promise<OAuth2Tokens>;
|
|
60
|
+
/**
|
|
61
|
+
* Refresh access token using refresh token
|
|
62
|
+
*/
|
|
63
|
+
export declare function refreshAccessToken(config: OAuth2Config, refreshToken: string): Promise<OAuth2Tokens>;
|
|
64
|
+
/**
|
|
65
|
+
* Revoke a token (access or refresh)
|
|
66
|
+
*/
|
|
67
|
+
export declare function revokeToken(config: OAuth2Config, token: string, tokenTypeHint?: 'access_token' | 'refresh_token'): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Start local callback server to receive OAuth redirect
|
|
70
|
+
*/
|
|
71
|
+
export declare function startCallbackServer(port: number, expectedState: string): Promise<{
|
|
72
|
+
code: string;
|
|
73
|
+
server: Server;
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Get the authenticated user's info
|
|
77
|
+
*/
|
|
78
|
+
export declare function getAuthenticatedUser(accessToken: string): Promise<{
|
|
79
|
+
id: string;
|
|
80
|
+
name: string;
|
|
81
|
+
username: string;
|
|
82
|
+
}>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 1.0a Authentication
|
|
3
|
+
* Required for legacy endpoints like media upload (v1.1 API)
|
|
4
|
+
*/
|
|
5
|
+
export interface OAuth1Config {
|
|
6
|
+
consumerKey: string;
|
|
7
|
+
consumerSecret: string;
|
|
8
|
+
accessToken?: string;
|
|
9
|
+
accessTokenSecret?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface OAuth1Tokens {
|
|
12
|
+
oauthToken: string;
|
|
13
|
+
oauthTokenSecret: string;
|
|
14
|
+
userId?: string;
|
|
15
|
+
screenName?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface OAuth1RequestToken {
|
|
18
|
+
oauthToken: string;
|
|
19
|
+
oauthTokenSecret: string;
|
|
20
|
+
oauthCallbackConfirmed: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build OAuth 1.0a Authorization header
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildOAuth1Header(config: OAuth1Config, method: string, url: string, additionalParams?: Record<string, string>): string;
|
|
26
|
+
/**
|
|
27
|
+
* Get request token (Step 1 of 3-legged OAuth)
|
|
28
|
+
*/
|
|
29
|
+
export declare function getRequestToken(config: OAuth1Config, callbackUrl: string): Promise<OAuth1RequestToken>;
|
|
30
|
+
/**
|
|
31
|
+
* Build authorization URL (Step 2 of 3-legged OAuth)
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildOAuth1AuthorizationUrl(oauthToken: string): string;
|
|
34
|
+
/**
|
|
35
|
+
* Exchange request token for access token (Step 3 of 3-legged OAuth)
|
|
36
|
+
*/
|
|
37
|
+
export declare function getAccessToken(config: OAuth1Config, oauthToken: string, oauthTokenSecret: string, oauthVerifier: string): Promise<OAuth1Tokens>;
|
|
38
|
+
/**
|
|
39
|
+
* Make an OAuth 1.0a authenticated request
|
|
40
|
+
*/
|
|
41
|
+
export declare function oauth1Request<T>(config: OAuth1Config, method: string, url: string, body?: Record<string, string> | FormData | string, additionalHeaders?: Record<string, string>): Promise<T>;
|
|
42
|
+
/**
|
|
43
|
+
* OAuth 1.0a client for making authenticated requests
|
|
44
|
+
*/
|
|
45
|
+
export declare class OAuth1Client {
|
|
46
|
+
private config;
|
|
47
|
+
constructor(config: OAuth1Config);
|
|
48
|
+
/**
|
|
49
|
+
* Check if we have user tokens
|
|
50
|
+
*/
|
|
51
|
+
hasUserTokens(): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Set user tokens
|
|
54
|
+
*/
|
|
55
|
+
setTokens(oauthToken: string, oauthTokenSecret: string): void;
|
|
56
|
+
/**
|
|
57
|
+
* Make authenticated GET request
|
|
58
|
+
*/
|
|
59
|
+
get<T>(url: string, params?: Record<string, string>): Promise<T>;
|
|
60
|
+
/**
|
|
61
|
+
* Make authenticated POST request
|
|
62
|
+
*/
|
|
63
|
+
post<T>(url: string, body?: Record<string, string> | FormData | string, headers?: Record<string, string>): Promise<T>;
|
|
64
|
+
/**
|
|
65
|
+
* Build authorization header for a request
|
|
66
|
+
*/
|
|
67
|
+
buildAuthHeader(method: string, url: string, params?: Record<string, string>): string;
|
|
68
|
+
}
|