@antcoder/birdxtwittercli 0.8.0

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.
Files changed (214) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/LICENSE +21 -0
  3. package/README.md +388 -0
  4. package/dist/cli/pagination.d.ts +35 -0
  5. package/dist/cli/pagination.d.ts.map +1 -0
  6. package/dist/cli/pagination.js +43 -0
  7. package/dist/cli/pagination.js.map +1 -0
  8. package/dist/cli/program.d.ts +5 -0
  9. package/dist/cli/program.d.ts.map +1 -0
  10. package/dist/cli/program.js +113 -0
  11. package/dist/cli/program.js.map +1 -0
  12. package/dist/cli/shared.d.ts +77 -0
  13. package/dist/cli/shared.d.ts.map +1 -0
  14. package/dist/cli/shared.js +327 -0
  15. package/dist/cli/shared.js.map +1 -0
  16. package/dist/cli.d.ts +12 -0
  17. package/dist/cli.d.ts.map +1 -0
  18. package/dist/cli.js +29 -0
  19. package/dist/cli.js.map +1 -0
  20. package/dist/commands/bookmarks.d.ts +4 -0
  21. package/dist/commands/bookmarks.d.ts.map +1 -0
  22. package/dist/commands/bookmarks.js +189 -0
  23. package/dist/commands/bookmarks.js.map +1 -0
  24. package/dist/commands/check.d.ts +4 -0
  25. package/dist/commands/check.d.ts.map +1 -0
  26. package/dist/commands/check.js +43 -0
  27. package/dist/commands/check.js.map +1 -0
  28. package/dist/commands/follow.d.ts +4 -0
  29. package/dist/commands/follow.d.ts.map +1 -0
  30. package/dist/commands/follow.js +91 -0
  31. package/dist/commands/follow.js.map +1 -0
  32. package/dist/commands/help.d.ts +4 -0
  33. package/dist/commands/help.d.ts.map +1 -0
  34. package/dist/commands/help.js +19 -0
  35. package/dist/commands/help.js.map +1 -0
  36. package/dist/commands/home.d.ts +4 -0
  37. package/dist/commands/home.d.ts.map +1 -0
  38. package/dist/commands/home.js +43 -0
  39. package/dist/commands/home.js.map +1 -0
  40. package/dist/commands/lists.d.ts +4 -0
  41. package/dist/commands/lists.d.ts.map +1 -0
  42. package/dist/commands/lists.js +213 -0
  43. package/dist/commands/lists.js.map +1 -0
  44. package/dist/commands/news.d.ts +4 -0
  45. package/dist/commands/news.d.ts.map +1 -0
  46. package/dist/commands/news.js +131 -0
  47. package/dist/commands/news.js.map +1 -0
  48. package/dist/commands/post.d.ts +4 -0
  49. package/dist/commands/post.d.ts.map +1 -0
  50. package/dist/commands/post.js +101 -0
  51. package/dist/commands/post.js.map +1 -0
  52. package/dist/commands/query-ids.d.ts +4 -0
  53. package/dist/commands/query-ids.d.ts.map +1 -0
  54. package/dist/commands/query-ids.js +80 -0
  55. package/dist/commands/query-ids.js.map +1 -0
  56. package/dist/commands/read.d.ts +4 -0
  57. package/dist/commands/read.d.ts.map +1 -0
  58. package/dist/commands/read.js +152 -0
  59. package/dist/commands/read.js.map +1 -0
  60. package/dist/commands/search.d.ts +4 -0
  61. package/dist/commands/search.d.ts.map +1 -0
  62. package/dist/commands/search.js +115 -0
  63. package/dist/commands/search.js.map +1 -0
  64. package/dist/commands/unbookmark.d.ts +4 -0
  65. package/dist/commands/unbookmark.d.ts.map +1 -0
  66. package/dist/commands/unbookmark.js +36 -0
  67. package/dist/commands/unbookmark.js.map +1 -0
  68. package/dist/commands/user-tweets.d.ts +4 -0
  69. package/dist/commands/user-tweets.d.ts.map +1 -0
  70. package/dist/commands/user-tweets.js +109 -0
  71. package/dist/commands/user-tweets.js.map +1 -0
  72. package/dist/commands/users.d.ts +4 -0
  73. package/dist/commands/users.d.ts.map +1 -0
  74. package/dist/commands/users.js +295 -0
  75. package/dist/commands/users.js.map +1 -0
  76. package/dist/index.d.ts +2 -0
  77. package/dist/index.d.ts.map +1 -0
  78. package/dist/index.js +2 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/lib/cli-args.d.ts +7 -0
  81. package/dist/lib/cli-args.d.ts.map +1 -0
  82. package/dist/lib/cli-args.js +25 -0
  83. package/dist/lib/cli-args.js.map +1 -0
  84. package/dist/lib/cookies.d.ts +31 -0
  85. package/dist/lib/cookies.d.ts.map +1 -0
  86. package/dist/lib/cookies.js +173 -0
  87. package/dist/lib/cookies.js.map +1 -0
  88. package/dist/lib/extract-bookmark-folder-id.d.ts +2 -0
  89. package/dist/lib/extract-bookmark-folder-id.d.ts.map +1 -0
  90. package/dist/lib/extract-bookmark-folder-id.js +20 -0
  91. package/dist/lib/extract-bookmark-folder-id.js.map +1 -0
  92. package/dist/lib/extract-list-id.d.ts +2 -0
  93. package/dist/lib/extract-list-id.d.ts.map +1 -0
  94. package/dist/lib/extract-list-id.js +19 -0
  95. package/dist/lib/extract-list-id.js.map +1 -0
  96. package/dist/lib/extract-tweet-id.d.ts +2 -0
  97. package/dist/lib/extract-tweet-id.d.ts.map +1 -0
  98. package/dist/lib/extract-tweet-id.js +14 -0
  99. package/dist/lib/extract-tweet-id.js.map +1 -0
  100. package/dist/lib/features.json +17 -0
  101. package/dist/lib/index.d.ts +10 -0
  102. package/dist/lib/index.d.ts.map +1 -0
  103. package/dist/lib/index.js +4 -0
  104. package/dist/lib/index.js.map +1 -0
  105. package/dist/lib/normalize-handle.d.ts +6 -0
  106. package/dist/lib/normalize-handle.d.ts.map +1 -0
  107. package/dist/lib/normalize-handle.js +31 -0
  108. package/dist/lib/normalize-handle.js.map +1 -0
  109. package/dist/lib/output.d.ts +29 -0
  110. package/dist/lib/output.d.ts.map +1 -0
  111. package/dist/lib/output.js +88 -0
  112. package/dist/lib/output.js.map +1 -0
  113. package/dist/lib/paginate-cursor.d.ts +27 -0
  114. package/dist/lib/paginate-cursor.d.ts.map +1 -0
  115. package/dist/lib/paginate-cursor.js +37 -0
  116. package/dist/lib/paginate-cursor.js.map +1 -0
  117. package/dist/lib/query-ids.json +20 -0
  118. package/dist/lib/runtime-features.d.ts +19 -0
  119. package/dist/lib/runtime-features.d.ts.map +1 -0
  120. package/dist/lib/runtime-features.js +151 -0
  121. package/dist/lib/runtime-features.js.map +1 -0
  122. package/dist/lib/runtime-query-ids.d.ts +33 -0
  123. package/dist/lib/runtime-query-ids.d.ts.map +1 -0
  124. package/dist/lib/runtime-query-ids.js +264 -0
  125. package/dist/lib/runtime-query-ids.js.map +1 -0
  126. package/dist/lib/thread-filters.d.ts +8 -0
  127. package/dist/lib/thread-filters.d.ts.map +1 -0
  128. package/dist/lib/thread-filters.js +124 -0
  129. package/dist/lib/thread-filters.js.map +1 -0
  130. package/dist/lib/twitter-client-base.d.ts +38 -0
  131. package/dist/lib/twitter-client-base.d.ts.map +1 -0
  132. package/dist/lib/twitter-client-base.js +129 -0
  133. package/dist/lib/twitter-client-base.js.map +1 -0
  134. package/dist/lib/twitter-client-bookmarks.d.ts +7 -0
  135. package/dist/lib/twitter-client-bookmarks.d.ts.map +1 -0
  136. package/dist/lib/twitter-client-bookmarks.js +61 -0
  137. package/dist/lib/twitter-client-bookmarks.js.map +1 -0
  138. package/dist/lib/twitter-client-constants.d.ts +44 -0
  139. package/dist/lib/twitter-client-constants.d.ts.map +1 -0
  140. package/dist/lib/twitter-client-constants.js +51 -0
  141. package/dist/lib/twitter-client-constants.js.map +1 -0
  142. package/dist/lib/twitter-client-engagement.d.ts +16 -0
  143. package/dist/lib/twitter-client-engagement.d.ts.map +1 -0
  144. package/dist/lib/twitter-client-engagement.js +81 -0
  145. package/dist/lib/twitter-client-engagement.js.map +1 -0
  146. package/dist/lib/twitter-client-features.d.ts +14 -0
  147. package/dist/lib/twitter-client-features.d.ts.map +1 -0
  148. package/dist/lib/twitter-client-features.js +347 -0
  149. package/dist/lib/twitter-client-features.js.map +1 -0
  150. package/dist/lib/twitter-client-follow.d.ts +8 -0
  151. package/dist/lib/twitter-client-follow.d.ts.map +1 -0
  152. package/dist/lib/twitter-client-follow.js +178 -0
  153. package/dist/lib/twitter-client-follow.js.map +1 -0
  154. package/dist/lib/twitter-client-home.d.ts +13 -0
  155. package/dist/lib/twitter-client-home.d.ts.map +1 -0
  156. package/dist/lib/twitter-client-home.js +138 -0
  157. package/dist/lib/twitter-client-home.js.map +1 -0
  158. package/dist/lib/twitter-client-lists.d.ts +12 -0
  159. package/dist/lib/twitter-client-lists.d.ts.map +1 -0
  160. package/dist/lib/twitter-client-lists.js +390 -0
  161. package/dist/lib/twitter-client-lists.js.map +1 -0
  162. package/dist/lib/twitter-client-media.d.ts +11 -0
  163. package/dist/lib/twitter-client-media.d.ts.map +1 -0
  164. package/dist/lib/twitter-client-media.js +136 -0
  165. package/dist/lib/twitter-client-media.js.map +1 -0
  166. package/dist/lib/twitter-client-news.d.ts +47 -0
  167. package/dist/lib/twitter-client-news.d.ts.map +1 -0
  168. package/dist/lib/twitter-client-news.js +283 -0
  169. package/dist/lib/twitter-client-news.js.map +1 -0
  170. package/dist/lib/twitter-client-posting.d.ts +8 -0
  171. package/dist/lib/twitter-client-posting.d.ts.map +1 -0
  172. package/dist/lib/twitter-client-posting.js +218 -0
  173. package/dist/lib/twitter-client-posting.js.map +1 -0
  174. package/dist/lib/twitter-client-search.d.ts +19 -0
  175. package/dist/lib/twitter-client-search.d.ts.map +1 -0
  176. package/dist/lib/twitter-client-search.js +157 -0
  177. package/dist/lib/twitter-client-search.js.map +1 -0
  178. package/dist/lib/twitter-client-timelines.d.ts +23 -0
  179. package/dist/lib/twitter-client-timelines.d.ts.map +1 -0
  180. package/dist/lib/twitter-client-timelines.js +471 -0
  181. package/dist/lib/twitter-client-timelines.js.map +1 -0
  182. package/dist/lib/twitter-client-tweet-detail.d.ts +25 -0
  183. package/dist/lib/twitter-client-tweet-detail.d.ts.map +1 -0
  184. package/dist/lib/twitter-client-tweet-detail.js +295 -0
  185. package/dist/lib/twitter-client-tweet-detail.js.map +1 -0
  186. package/dist/lib/twitter-client-types.d.ts +407 -0
  187. package/dist/lib/twitter-client-types.d.ts.map +1 -0
  188. package/dist/lib/twitter-client-types.js +2 -0
  189. package/dist/lib/twitter-client-types.js.map +1 -0
  190. package/dist/lib/twitter-client-user-lookup.d.ts +16 -0
  191. package/dist/lib/twitter-client-user-lookup.d.ts.map +1 -0
  192. package/dist/lib/twitter-client-user-lookup.js +224 -0
  193. package/dist/lib/twitter-client-user-lookup.js.map +1 -0
  194. package/dist/lib/twitter-client-user-tweets.d.ts +22 -0
  195. package/dist/lib/twitter-client-user-tweets.d.ts.map +1 -0
  196. package/dist/lib/twitter-client-user-tweets.js +154 -0
  197. package/dist/lib/twitter-client-user-tweets.js.map +1 -0
  198. package/dist/lib/twitter-client-users.d.ts +9 -0
  199. package/dist/lib/twitter-client-users.d.ts.map +1 -0
  200. package/dist/lib/twitter-client-users.js +358 -0
  201. package/dist/lib/twitter-client-users.js.map +1 -0
  202. package/dist/lib/twitter-client-utils.d.ts +173 -0
  203. package/dist/lib/twitter-client-utils.d.ts.map +1 -0
  204. package/dist/lib/twitter-client-utils.js +511 -0
  205. package/dist/lib/twitter-client-utils.js.map +1 -0
  206. package/dist/lib/twitter-client.d.ts +23 -0
  207. package/dist/lib/twitter-client.d.ts.map +1 -0
  208. package/dist/lib/twitter-client.js +21 -0
  209. package/dist/lib/twitter-client.js.map +1 -0
  210. package/dist/lib/version.d.ts +6 -0
  211. package/dist/lib/version.d.ts.map +1 -0
  212. package/dist/lib/version.js +174 -0
  213. package/dist/lib/version.js.map +1 -0
  214. package/package.json +61 -0
@@ -0,0 +1,173 @@
1
+ import type { GraphqlTweetResult, TweetData, TweetMedia, TwitterUser } from './twitter-client-types.js';
2
+ export declare function normalizeQuoteDepth(value?: number): number;
3
+ export declare function firstText(...values: Array<string | undefined | null>): string | undefined;
4
+ export declare function collectTextFields(value: unknown, keys: Set<string>, output: string[]): void;
5
+ export declare function uniqueOrdered(values: string[]): string[];
6
+ /** Inline style range for text formatting (Bold, Italic, etc.) */
7
+ interface InlineStyleRange {
8
+ offset: number;
9
+ length: number;
10
+ style: string;
11
+ }
12
+ /** Entity range linking a portion of text to an entity in entityMap */
13
+ interface EntityRange {
14
+ key: number;
15
+ offset: number;
16
+ length: number;
17
+ }
18
+ /** A content block in Draft.js format */
19
+ interface ContentBlock {
20
+ key: string;
21
+ type: string;
22
+ text: string;
23
+ data?: {
24
+ mentions?: Array<{
25
+ fromIndex: number;
26
+ toIndex: number;
27
+ text: string;
28
+ }>;
29
+ };
30
+ entityRanges?: EntityRange[];
31
+ inlineStyleRanges?: InlineStyleRange[];
32
+ }
33
+ /** Entity data for different entity types */
34
+ interface EntityValue {
35
+ type: string;
36
+ mutability: string;
37
+ data: {
38
+ markdown?: string;
39
+ url?: string;
40
+ tweetId?: string;
41
+ };
42
+ }
43
+ /** Entity map entry */
44
+ interface EntityMapEntry {
45
+ key: string;
46
+ value: EntityValue;
47
+ }
48
+ /** Draft.js content state structure */
49
+ interface ContentState {
50
+ blocks: ContentBlock[];
51
+ entityMap?: Array<EntityMapEntry> | Record<string, EntityValue>;
52
+ }
53
+ /**
54
+ * Renders a Draft.js content_state into readable markdown/text format.
55
+ * Handles blocks (paragraphs, headers, lists) and entities (code blocks, links, tweets, dividers).
56
+ */
57
+ export declare function renderContentState(contentState: ContentState | undefined): string | undefined;
58
+ export declare function extractArticleText(result: GraphqlTweetResult | undefined): string | undefined;
59
+ export declare function extractNoteTweetText(result: GraphqlTweetResult | undefined): string | undefined;
60
+ export declare function extractTweetText(result: GraphqlTweetResult | undefined): string | undefined;
61
+ export declare function extractArticleMetadata(result: GraphqlTweetResult | undefined): {
62
+ title: string;
63
+ previewText?: string;
64
+ } | undefined;
65
+ export declare function extractMedia(result: GraphqlTweetResult | undefined): TweetMedia[] | undefined;
66
+ export declare function unwrapTweetResult(result: GraphqlTweetResult | undefined): GraphqlTweetResult | undefined;
67
+ export interface MapTweetResultOptions {
68
+ quoteDepth: number;
69
+ includeRaw?: boolean;
70
+ }
71
+ export declare function mapTweetResult(result: GraphqlTweetResult | undefined, quoteDepthOrOptions: number | MapTweetResultOptions): TweetData | undefined;
72
+ export declare function findTweetInInstructions(instructions: Array<{
73
+ entries?: Array<{
74
+ content?: {
75
+ itemContent?: {
76
+ tweet_results?: {
77
+ result?: GraphqlTweetResult;
78
+ };
79
+ };
80
+ };
81
+ }>;
82
+ }> | undefined, tweetId: string): GraphqlTweetResult | undefined;
83
+ export declare function collectTweetResultsFromEntry(entry: {
84
+ content?: {
85
+ itemContent?: {
86
+ tweet_results?: {
87
+ result?: GraphqlTweetResult;
88
+ };
89
+ };
90
+ item?: {
91
+ itemContent?: {
92
+ tweet_results?: {
93
+ result?: GraphqlTweetResult;
94
+ };
95
+ };
96
+ };
97
+ items?: Array<{
98
+ item?: {
99
+ itemContent?: {
100
+ tweet_results?: {
101
+ result?: GraphqlTweetResult;
102
+ };
103
+ };
104
+ };
105
+ itemContent?: {
106
+ tweet_results?: {
107
+ result?: GraphqlTweetResult;
108
+ };
109
+ };
110
+ content?: {
111
+ itemContent?: {
112
+ tweet_results?: {
113
+ result?: GraphqlTweetResult;
114
+ };
115
+ };
116
+ };
117
+ }>;
118
+ };
119
+ }): GraphqlTweetResult[];
120
+ export interface ParseTweetsOptions {
121
+ quoteDepth: number;
122
+ includeRaw?: boolean;
123
+ }
124
+ export declare function parseTweetsFromInstructions(instructions: Array<{
125
+ entries?: Array<{
126
+ content?: {
127
+ itemContent?: {
128
+ tweet_results?: {
129
+ result?: GraphqlTweetResult;
130
+ };
131
+ };
132
+ item?: {
133
+ itemContent?: {
134
+ tweet_results?: {
135
+ result?: GraphqlTweetResult;
136
+ };
137
+ };
138
+ };
139
+ items?: Array<{
140
+ item?: {
141
+ itemContent?: {
142
+ tweet_results?: {
143
+ result?: GraphqlTweetResult;
144
+ };
145
+ };
146
+ };
147
+ itemContent?: {
148
+ tweet_results?: {
149
+ result?: GraphqlTweetResult;
150
+ };
151
+ };
152
+ content?: {
153
+ itemContent?: {
154
+ tweet_results?: {
155
+ result?: GraphqlTweetResult;
156
+ };
157
+ };
158
+ };
159
+ }>;
160
+ };
161
+ }>;
162
+ }> | undefined, quoteDepthOrOptions: number | ParseTweetsOptions): TweetData[];
163
+ export declare function extractCursorFromInstructions(instructions: Array<{
164
+ entries?: Array<{
165
+ content?: unknown;
166
+ }>;
167
+ }> | undefined, cursorType?: string): string | undefined;
168
+ export declare function parseUsersFromInstructions(instructions: Array<{
169
+ type?: string;
170
+ entries?: Array<unknown>;
171
+ }> | undefined): TwitterUser[];
172
+ export {};
173
+ //# sourceMappingURL=twitter-client-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"twitter-client-utils.d.ts","sourceRoot":"","sources":["../../src/lib/twitter-client-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,511 @@
1
+ export function normalizeQuoteDepth(value) {
2
+ if (value === undefined || value === null) {
3
+ return 1;
4
+ }
5
+ if (!Number.isFinite(value)) {
6
+ return 1;
7
+ }
8
+ return Math.max(0, Math.floor(value));
9
+ }
10
+ export function firstText(...values) {
11
+ for (const value of values) {
12
+ if (typeof value === 'string') {
13
+ const trimmed = value.trim();
14
+ if (trimmed) {
15
+ return trimmed;
16
+ }
17
+ }
18
+ }
19
+ return undefined;
20
+ }
21
+ export function collectTextFields(value, keys, output) {
22
+ if (!value) {
23
+ return;
24
+ }
25
+ if (typeof value === 'string') {
26
+ return;
27
+ }
28
+ if (Array.isArray(value)) {
29
+ for (const item of value) {
30
+ collectTextFields(item, keys, output);
31
+ }
32
+ return;
33
+ }
34
+ if (typeof value === 'object') {
35
+ for (const [key, nested] of Object.entries(value)) {
36
+ if (keys.has(key)) {
37
+ if (typeof nested === 'string') {
38
+ const trimmed = nested.trim();
39
+ if (trimmed) {
40
+ output.push(trimmed);
41
+ }
42
+ continue;
43
+ }
44
+ }
45
+ collectTextFields(nested, keys, output);
46
+ }
47
+ }
48
+ }
49
+ export function uniqueOrdered(values) {
50
+ const seen = new Set();
51
+ const result = [];
52
+ for (const value of values) {
53
+ if (seen.has(value)) {
54
+ continue;
55
+ }
56
+ seen.add(value);
57
+ result.push(value);
58
+ }
59
+ return result;
60
+ }
61
+ /**
62
+ * Renders a Draft.js content_state into readable markdown/text format.
63
+ * Handles blocks (paragraphs, headers, lists) and entities (code blocks, links, tweets, dividers).
64
+ */
65
+ export function renderContentState(contentState) {
66
+ if (!contentState?.blocks || contentState.blocks.length === 0) {
67
+ return undefined;
68
+ }
69
+ // Build entity lookup map from array/object formats
70
+ const entityMap = new Map();
71
+ const rawEntityMap = contentState.entityMap ?? [];
72
+ if (Array.isArray(rawEntityMap)) {
73
+ for (const entry of rawEntityMap) {
74
+ const key = Number.parseInt(entry.key, 10);
75
+ if (!Number.isNaN(key)) {
76
+ entityMap.set(key, entry.value);
77
+ }
78
+ }
79
+ }
80
+ else {
81
+ for (const [key, value] of Object.entries(rawEntityMap)) {
82
+ const keyNumber = Number.parseInt(key, 10);
83
+ if (!Number.isNaN(keyNumber)) {
84
+ entityMap.set(keyNumber, value);
85
+ }
86
+ }
87
+ }
88
+ const outputLines = [];
89
+ let orderedListCounter = 0;
90
+ let previousBlockType;
91
+ for (const block of contentState.blocks) {
92
+ // Reset ordered list counter when leaving ordered list context
93
+ if (block.type !== 'ordered-list-item' && previousBlockType === 'ordered-list-item') {
94
+ orderedListCounter = 0;
95
+ }
96
+ switch (block.type) {
97
+ case 'unstyled': {
98
+ // Plain paragraph - just output text with any inline formatting
99
+ const text = renderBlockText(block, entityMap);
100
+ if (text) {
101
+ outputLines.push(text);
102
+ }
103
+ break;
104
+ }
105
+ case 'header-one': {
106
+ const text = renderBlockText(block, entityMap);
107
+ if (text) {
108
+ outputLines.push(`# ${text}`);
109
+ }
110
+ break;
111
+ }
112
+ case 'header-two': {
113
+ const text = renderBlockText(block, entityMap);
114
+ if (text) {
115
+ outputLines.push(`## ${text}`);
116
+ }
117
+ break;
118
+ }
119
+ case 'header-three': {
120
+ const text = renderBlockText(block, entityMap);
121
+ if (text) {
122
+ outputLines.push(`### ${text}`);
123
+ }
124
+ break;
125
+ }
126
+ case 'unordered-list-item': {
127
+ const text = renderBlockText(block, entityMap);
128
+ if (text) {
129
+ outputLines.push(`- ${text}`);
130
+ }
131
+ break;
132
+ }
133
+ case 'ordered-list-item': {
134
+ orderedListCounter++;
135
+ const text = renderBlockText(block, entityMap);
136
+ if (text) {
137
+ outputLines.push(`${orderedListCounter}. ${text}`);
138
+ }
139
+ break;
140
+ }
141
+ case 'blockquote': {
142
+ const text = renderBlockText(block, entityMap);
143
+ if (text) {
144
+ outputLines.push(`> ${text}`);
145
+ }
146
+ break;
147
+ }
148
+ case 'atomic': {
149
+ // Atomic blocks are placeholders for embedded entities
150
+ const entityContent = renderAtomicBlock(block, entityMap);
151
+ if (entityContent) {
152
+ outputLines.push(entityContent);
153
+ }
154
+ break;
155
+ }
156
+ default: {
157
+ // Fallback: just output the text
158
+ const text = renderBlockText(block, entityMap);
159
+ if (text) {
160
+ outputLines.push(text);
161
+ }
162
+ }
163
+ }
164
+ previousBlockType = block.type;
165
+ }
166
+ const result = outputLines.join('\n\n');
167
+ return result.trim() || undefined;
168
+ }
169
+ /**
170
+ * Renders text content of a block, applying inline link entities.
171
+ */
172
+ function renderBlockText(block, entityMap) {
173
+ let text = block.text;
174
+ // Handle LINK entities by appending URL in markdown format
175
+ // Process in reverse order to not mess up offsets
176
+ const linkRanges = (block.entityRanges ?? [])
177
+ .filter((range) => {
178
+ const entity = entityMap.get(range.key);
179
+ return entity?.type === 'LINK' && entity.data.url;
180
+ })
181
+ .sort((a, b) => b.offset - a.offset);
182
+ for (const range of linkRanges) {
183
+ const entity = entityMap.get(range.key);
184
+ if (entity?.data.url) {
185
+ const linkText = text.slice(range.offset, range.offset + range.length);
186
+ const markdownLink = `[${linkText}](${entity.data.url})`;
187
+ text = text.slice(0, range.offset) + markdownLink + text.slice(range.offset + range.length);
188
+ }
189
+ }
190
+ return text.trim();
191
+ }
192
+ /**
193
+ * Renders an atomic block by looking up its entity and returning appropriate content.
194
+ */
195
+ function renderAtomicBlock(block, entityMap) {
196
+ const entityRanges = block.entityRanges ?? [];
197
+ if (entityRanges.length === 0) {
198
+ return undefined;
199
+ }
200
+ const entityKey = entityRanges[0].key;
201
+ const entity = entityMap.get(entityKey);
202
+ if (!entity) {
203
+ return undefined;
204
+ }
205
+ switch (entity.type) {
206
+ case 'MARKDOWN':
207
+ // Code blocks and other markdown content - output as-is
208
+ return entity.data.markdown?.trim();
209
+ case 'DIVIDER':
210
+ return '---';
211
+ case 'TWEET':
212
+ if (entity.data.tweetId) {
213
+ return `[Embedded Tweet: https://x.com/i/status/${entity.data.tweetId}]`;
214
+ }
215
+ return undefined;
216
+ case 'LINK':
217
+ if (entity.data.url) {
218
+ return `[Link: ${entity.data.url}]`;
219
+ }
220
+ return undefined;
221
+ case 'IMAGE':
222
+ // Images in atomic blocks - could extract URL if available
223
+ return '[Image]';
224
+ default:
225
+ return undefined;
226
+ }
227
+ }
228
+ export function extractArticleText(result) {
229
+ const article = result?.article;
230
+ if (!article) {
231
+ return undefined;
232
+ }
233
+ const articleResult = article.article_results?.result ?? article;
234
+ if (process.env.BIRD_DEBUG_ARTICLE === '1') {
235
+ console.error('[bird][debug][article] payload:', JSON.stringify({
236
+ rest_id: result?.rest_id,
237
+ article: articleResult,
238
+ note_tweet: result?.note_tweet?.note_tweet_results?.result ?? null,
239
+ }, null, 2));
240
+ }
241
+ const title = firstText(articleResult.title, article.title);
242
+ // Try to render from rich content_state first (Draft.js format with blocks + entityMap)
243
+ // This preserves code blocks, embedded tweets, markdown, etc.
244
+ const contentState = article.article_results?.result?.content_state;
245
+ const richBody = renderContentState(contentState);
246
+ if (richBody) {
247
+ // Rich content found - prepend title if not already included
248
+ if (title) {
249
+ const normalizedTitle = title.trim();
250
+ const trimmedBody = richBody.trimStart();
251
+ const headingMatches = [`# ${normalizedTitle}`, `## ${normalizedTitle}`, `### ${normalizedTitle}`];
252
+ const hasTitle = trimmedBody === normalizedTitle ||
253
+ trimmedBody.startsWith(`${normalizedTitle}\n`) ||
254
+ headingMatches.some((heading) => trimmedBody.startsWith(heading));
255
+ if (!hasTitle) {
256
+ return `${title}\n\n${richBody}`;
257
+ }
258
+ }
259
+ return richBody;
260
+ }
261
+ // Fallback to plain text extraction for articles without rich content_state
262
+ let body = firstText(articleResult.plain_text, article.plain_text, articleResult.body?.text, articleResult.body?.richtext?.text, articleResult.body?.rich_text?.text, articleResult.content?.text, articleResult.content?.richtext?.text, articleResult.content?.rich_text?.text, articleResult.text, articleResult.richtext?.text, articleResult.rich_text?.text, article.body?.text, article.body?.richtext?.text, article.body?.rich_text?.text, article.content?.text, article.content?.richtext?.text, article.content?.rich_text?.text, article.text, article.richtext?.text, article.rich_text?.text);
263
+ if (body && title && body.trim() === title.trim()) {
264
+ body = undefined;
265
+ }
266
+ if (!body) {
267
+ const collected = [];
268
+ collectTextFields(articleResult, new Set(['text', 'title']), collected);
269
+ collectTextFields(article, new Set(['text', 'title']), collected);
270
+ const unique = uniqueOrdered(collected);
271
+ const filtered = title ? unique.filter((value) => value !== title) : unique;
272
+ if (filtered.length > 0) {
273
+ body = filtered.join('\n\n');
274
+ }
275
+ }
276
+ if (title && body && !body.startsWith(title)) {
277
+ return `${title}\n\n${body}`;
278
+ }
279
+ return body ?? title;
280
+ }
281
+ export function extractNoteTweetText(result) {
282
+ const note = result?.note_tweet?.note_tweet_results?.result;
283
+ if (!note) {
284
+ return undefined;
285
+ }
286
+ return firstText(note.text, note.richtext?.text, note.rich_text?.text, note.content?.text, note.content?.richtext?.text, note.content?.rich_text?.text);
287
+ }
288
+ export function extractTweetText(result) {
289
+ return extractArticleText(result) ?? extractNoteTweetText(result) ?? firstText(result?.legacy?.full_text);
290
+ }
291
+ export function extractArticleMetadata(result) {
292
+ const article = result?.article;
293
+ if (!article) {
294
+ return undefined;
295
+ }
296
+ const articleResult = article.article_results?.result ?? article;
297
+ const title = firstText(articleResult.title, article.title);
298
+ if (!title) {
299
+ return undefined;
300
+ }
301
+ // preview_text is available in home timeline responses
302
+ const previewText = firstText(articleResult.preview_text, article.preview_text);
303
+ return { title, previewText };
304
+ }
305
+ export function extractMedia(result) {
306
+ // Prefer extended_entities (has video info), fall back to entities
307
+ const rawMedia = result?.legacy?.extended_entities?.media ?? result?.legacy?.entities?.media;
308
+ if (!rawMedia || rawMedia.length === 0) {
309
+ return undefined;
310
+ }
311
+ const media = [];
312
+ for (const item of rawMedia) {
313
+ if (!item.type || !item.media_url_https) {
314
+ continue;
315
+ }
316
+ const mediaItem = {
317
+ type: item.type,
318
+ url: item.media_url_https,
319
+ };
320
+ // Get dimensions from largest available size
321
+ const sizes = item.sizes;
322
+ if (sizes?.large) {
323
+ mediaItem.width = sizes.large.w;
324
+ mediaItem.height = sizes.large.h;
325
+ }
326
+ else if (sizes?.medium) {
327
+ mediaItem.width = sizes.medium.w;
328
+ mediaItem.height = sizes.medium.h;
329
+ }
330
+ // For thumbnails/previews
331
+ if (sizes?.small) {
332
+ mediaItem.previewUrl = `${item.media_url_https}:small`;
333
+ }
334
+ // Extract video URL for video/animated_gif
335
+ if ((item.type === 'video' || item.type === 'animated_gif') && item.video_info?.variants) {
336
+ // Prefer highest bitrate MP4, fall back to first MP4 when bitrate is missing.
337
+ const mp4Variants = item.video_info.variants.filter((v) => v.content_type === 'video/mp4' && typeof v.url === 'string');
338
+ const mp4WithBitrate = mp4Variants
339
+ .filter((v) => typeof v.bitrate === 'number')
340
+ .sort((a, b) => b.bitrate - a.bitrate);
341
+ const selectedVariant = mp4WithBitrate[0] ?? mp4Variants[0];
342
+ if (selectedVariant) {
343
+ mediaItem.videoUrl = selectedVariant.url;
344
+ }
345
+ if (typeof item.video_info.duration_millis === 'number') {
346
+ mediaItem.durationMs = item.video_info.duration_millis;
347
+ }
348
+ }
349
+ media.push(mediaItem);
350
+ }
351
+ return media.length > 0 ? media : undefined;
352
+ }
353
+ export function unwrapTweetResult(result) {
354
+ if (!result) {
355
+ return undefined;
356
+ }
357
+ if (result.tweet) {
358
+ return result.tweet;
359
+ }
360
+ return result;
361
+ }
362
+ export function mapTweetResult(result, quoteDepthOrOptions) {
363
+ const options = typeof quoteDepthOrOptions === 'number' ? { quoteDepth: quoteDepthOrOptions } : quoteDepthOrOptions;
364
+ const { quoteDepth, includeRaw = false } = options;
365
+ const userResult = result?.core?.user_results?.result;
366
+ const userLegacy = userResult?.legacy;
367
+ const userCore = userResult?.core;
368
+ const username = userLegacy?.screen_name ?? userCore?.screen_name;
369
+ const name = userLegacy?.name ?? userCore?.name ?? username;
370
+ const userId = userResult?.rest_id;
371
+ if (!result?.rest_id || !username) {
372
+ return undefined;
373
+ }
374
+ const text = extractTweetText(result);
375
+ if (!text) {
376
+ return undefined;
377
+ }
378
+ let quotedTweet;
379
+ if (quoteDepth > 0) {
380
+ const quotedResult = unwrapTweetResult(result.quoted_status_result?.result);
381
+ if (quotedResult) {
382
+ quotedTweet = mapTweetResult(quotedResult, { quoteDepth: quoteDepth - 1, includeRaw });
383
+ }
384
+ }
385
+ const media = extractMedia(result);
386
+ const article = extractArticleMetadata(result);
387
+ const tweetData = {
388
+ id: result.rest_id,
389
+ text,
390
+ createdAt: result.legacy?.created_at,
391
+ replyCount: result.legacy?.reply_count,
392
+ retweetCount: result.legacy?.retweet_count,
393
+ likeCount: result.legacy?.favorite_count,
394
+ conversationId: result.legacy?.conversation_id_str,
395
+ inReplyToStatusId: result.legacy?.in_reply_to_status_id_str ?? undefined,
396
+ author: {
397
+ username,
398
+ name: name || username,
399
+ },
400
+ authorId: userId,
401
+ quotedTweet,
402
+ media,
403
+ article,
404
+ };
405
+ if (includeRaw) {
406
+ tweetData._raw = result;
407
+ }
408
+ return tweetData;
409
+ }
410
+ export function findTweetInInstructions(instructions, tweetId) {
411
+ if (!instructions) {
412
+ return undefined;
413
+ }
414
+ for (const instruction of instructions) {
415
+ for (const entry of instruction.entries || []) {
416
+ const result = entry.content?.itemContent?.tweet_results?.result;
417
+ if (result?.rest_id === tweetId) {
418
+ return result;
419
+ }
420
+ }
421
+ }
422
+ return undefined;
423
+ }
424
+ export function collectTweetResultsFromEntry(entry) {
425
+ const results = [];
426
+ const pushResult = (result) => {
427
+ if (result?.rest_id) {
428
+ results.push(result);
429
+ }
430
+ };
431
+ const content = entry.content;
432
+ pushResult(content?.itemContent?.tweet_results?.result);
433
+ pushResult(content?.item?.itemContent?.tweet_results?.result);
434
+ for (const item of content?.items ?? []) {
435
+ pushResult(item?.item?.itemContent?.tweet_results?.result);
436
+ pushResult(item?.itemContent?.tweet_results?.result);
437
+ pushResult(item?.content?.itemContent?.tweet_results?.result);
438
+ }
439
+ return results;
440
+ }
441
+ export function parseTweetsFromInstructions(instructions, quoteDepthOrOptions) {
442
+ const options = typeof quoteDepthOrOptions === 'number' ? { quoteDepth: quoteDepthOrOptions } : quoteDepthOrOptions;
443
+ const { quoteDepth, includeRaw = false } = options;
444
+ const tweets = [];
445
+ const seen = new Set();
446
+ for (const instruction of instructions ?? []) {
447
+ for (const entry of instruction.entries ?? []) {
448
+ const results = collectTweetResultsFromEntry(entry);
449
+ for (const result of results) {
450
+ const mapped = mapTweetResult(result, { quoteDepth, includeRaw });
451
+ if (!mapped || seen.has(mapped.id)) {
452
+ continue;
453
+ }
454
+ seen.add(mapped.id);
455
+ tweets.push(mapped);
456
+ }
457
+ }
458
+ }
459
+ return tweets;
460
+ }
461
+ export function extractCursorFromInstructions(instructions, cursorType = 'Bottom') {
462
+ for (const instruction of instructions ?? []) {
463
+ for (const entry of instruction.entries ?? []) {
464
+ const content = entry.content;
465
+ if (content?.cursorType === cursorType && typeof content.value === 'string' && content.value.length > 0) {
466
+ return content.value;
467
+ }
468
+ }
469
+ }
470
+ return undefined;
471
+ }
472
+ export function parseUsersFromInstructions(instructions) {
473
+ if (!instructions) {
474
+ return [];
475
+ }
476
+ const users = [];
477
+ for (const instruction of instructions) {
478
+ if (!instruction.entries) {
479
+ continue;
480
+ }
481
+ for (const entry of instruction.entries) {
482
+ const content = entry?.content;
483
+ const rawUserResult = content?.itemContent?.user_results?.result;
484
+ const userResult = rawUserResult?.__typename === 'UserWithVisibilityResults' && rawUserResult.user
485
+ ? rawUserResult.user
486
+ : rawUserResult;
487
+ if (!userResult || userResult.__typename !== 'User') {
488
+ continue;
489
+ }
490
+ const legacy = userResult.legacy;
491
+ const core = userResult.core;
492
+ const username = legacy?.screen_name ?? core?.screen_name;
493
+ if (!userResult.rest_id || !username) {
494
+ continue;
495
+ }
496
+ users.push({
497
+ id: userResult.rest_id,
498
+ username,
499
+ name: legacy?.name ?? core?.name ?? username,
500
+ description: legacy?.description,
501
+ followersCount: legacy?.followers_count,
502
+ followingCount: legacy?.friends_count,
503
+ isBlueVerified: userResult.is_blue_verified,
504
+ profileImageUrl: legacy?.profile_image_url_https ?? userResult.avatar?.image_url,
505
+ createdAt: legacy?.created_at ?? core?.created_at,
506
+ });
507
+ }
508
+ }
509
+ return users;
510
+ }
511
+ //# sourceMappingURL=twitter-client-utils.js.map