rettiwt-api 6.3.0-alpha.0 → 7.0.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 (130) hide show
  1. package/README.md +81 -31
  2. package/dist/Rettiwt.d.ts +6 -2
  3. package/dist/Rettiwt.js +7 -3
  4. package/dist/Rettiwt.js.map +1 -1
  5. package/dist/cli.js +3 -1
  6. package/dist/cli.js.map +1 -1
  7. package/dist/collections/Extractors.d.ts +15 -2
  8. package/dist/collections/Extractors.js +12 -1
  9. package/dist/collections/Extractors.js.map +1 -1
  10. package/dist/collections/Groups.js +8 -0
  11. package/dist/collections/Groups.js.map +1 -1
  12. package/dist/collections/Requests.js +8 -0
  13. package/dist/collections/Requests.js.map +1 -1
  14. package/dist/commands/Space.d.ts +10 -0
  15. package/dist/commands/Space.js +38 -0
  16. package/dist/commands/Space.js.map +1 -0
  17. package/dist/commands/User.js +139 -0
  18. package/dist/commands/User.js.map +1 -1
  19. package/dist/enums/Resource.d.ts +8 -1
  20. package/dist/enums/Resource.js +8 -0
  21. package/dist/enums/Resource.js.map +1 -1
  22. package/dist/index.d.ts +11 -1
  23. package/dist/index.js +6 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/models/RettiwtConfig.d.ts +26 -3
  26. package/dist/models/RettiwtConfig.js +68 -3
  27. package/dist/models/RettiwtConfig.js.map +1 -1
  28. package/dist/models/args/FetchArgs.d.ts +3 -0
  29. package/dist/models/args/FetchArgs.js +6 -0
  30. package/dist/models/args/FetchArgs.js.map +1 -1
  31. package/dist/models/args/PostArgs.d.ts +24 -1
  32. package/dist/models/args/PostArgs.js +52 -1
  33. package/dist/models/args/PostArgs.js.map +1 -1
  34. package/dist/models/data/Space.d.ts +70 -0
  35. package/dist/models/data/Space.js +177 -0
  36. package/dist/models/data/Space.js.map +1 -0
  37. package/dist/models/data/UserAbout.d.ts +44 -0
  38. package/dist/models/data/UserAbout.js +129 -0
  39. package/dist/models/data/UserAbout.js.map +1 -0
  40. package/dist/requests/Space.d.ts +15 -0
  41. package/dist/requests/Space.js +74 -0
  42. package/dist/requests/Space.js.map +1 -0
  43. package/dist/requests/Tweet.d.ts +4 -0
  44. package/dist/requests/Tweet.js +57 -0
  45. package/dist/requests/Tweet.js.map +1 -1
  46. package/dist/requests/User.d.ts +21 -0
  47. package/dist/requests/User.js +64 -0
  48. package/dist/requests/User.js.map +1 -1
  49. package/dist/services/internal/AuthService.d.ts +25 -0
  50. package/dist/services/internal/AuthService.js +121 -0
  51. package/dist/services/internal/AuthService.js.map +1 -1
  52. package/dist/services/public/DirectMessageService.js +3 -3
  53. package/dist/services/public/DirectMessageService.js.map +1 -1
  54. package/dist/services/public/FetcherService.d.ts +4 -3
  55. package/dist/services/public/FetcherService.js +22 -16
  56. package/dist/services/public/FetcherService.js.map +1 -1
  57. package/dist/services/public/ListService.js +5 -5
  58. package/dist/services/public/ListService.js.map +1 -1
  59. package/dist/services/public/SpaceService.d.ts +42 -0
  60. package/dist/services/public/SpaceService.js +60 -0
  61. package/dist/services/public/SpaceService.js.map +1 -0
  62. package/dist/services/public/TweetService.js +26 -23
  63. package/dist/services/public/TweetService.js.map +1 -1
  64. package/dist/services/public/UserService.d.ts +79 -0
  65. package/dist/services/public/UserService.js +203 -23
  66. package/dist/services/public/UserService.js.map +1 -1
  67. package/dist/types/RettiwtConfig.d.ts +33 -3
  68. package/dist/types/args/FetchArgs.d.ts +35 -1
  69. package/dist/types/args/PostArgs.d.ts +44 -1
  70. package/dist/types/data/Space.d.ts +89 -0
  71. package/dist/types/data/Space.js +3 -0
  72. package/dist/types/data/Space.js.map +1 -0
  73. package/dist/types/data/UserAbout.d.ts +68 -0
  74. package/dist/types/data/UserAbout.js +3 -0
  75. package/dist/types/data/UserAbout.js.map +1 -0
  76. package/dist/types/raw/base/Space.d.ts +43 -22
  77. package/dist/types/raw/space/AudioSpaceById.d.ts +50 -0
  78. package/dist/types/raw/space/AudioSpaceById.js +4 -0
  79. package/dist/types/raw/space/AudioSpaceById.js.map +1 -0
  80. package/dist/types/raw/space/Details.d.ts +2 -309
  81. package/dist/types/raw/tweet/Post.d.ts +16 -1
  82. package/dist/types/raw/user/About.d.ts +65 -0
  83. package/dist/types/raw/user/About.js +4 -0
  84. package/dist/types/raw/user/About.js.map +1 -0
  85. package/dist/types/raw/user/ChangePassword.d.ts +8 -0
  86. package/dist/types/raw/user/ChangePassword.js +3 -0
  87. package/dist/types/raw/user/ChangePassword.js.map +1 -0
  88. package/dist/types/raw/user/ProfileUpdate.d.ts +1 -0
  89. package/dist/types/raw/user/Settings.d.ts +21 -0
  90. package/dist/types/raw/user/Settings.js +4 -0
  91. package/dist/types/raw/user/Settings.js.map +1 -0
  92. package/package.json +6 -4
  93. package/src/Rettiwt.ts +10 -3
  94. package/src/cli.ts +3 -1
  95. package/src/collections/Extractors.ts +22 -3
  96. package/src/collections/Groups.ts +8 -0
  97. package/src/collections/Requests.ts +11 -0
  98. package/src/commands/Space.ts +46 -0
  99. package/src/commands/User.ts +159 -0
  100. package/src/enums/Resource.ts +9 -0
  101. package/src/index.ts +11 -1
  102. package/src/models/RettiwtConfig.ts +81 -6
  103. package/src/models/args/FetchArgs.ts +6 -0
  104. package/src/models/args/PostArgs.ts +58 -1
  105. package/src/models/data/Space.ts +201 -0
  106. package/src/models/data/UserAbout.ts +161 -0
  107. package/src/requests/Space.ts +76 -0
  108. package/src/requests/Tweet.ts +59 -0
  109. package/src/requests/User.ts +69 -0
  110. package/src/services/internal/AuthService.ts +149 -1
  111. package/src/services/public/DirectMessageService.ts +3 -3
  112. package/src/services/public/FetcherService.ts +25 -18
  113. package/src/services/public/ListService.ts +5 -5
  114. package/src/services/public/SpaceService.ts +65 -0
  115. package/src/services/public/TweetService.ts +27 -24
  116. package/src/services/public/UserService.ts +247 -23
  117. package/src/types/RettiwtConfig.ts +35 -3
  118. package/src/types/args/FetchArgs.ts +41 -1
  119. package/src/types/args/PostArgs.ts +50 -1
  120. package/src/types/data/Space.ts +122 -0
  121. package/src/types/data/UserAbout.ts +87 -0
  122. package/src/types/raw/base/Space.ts +42 -22
  123. package/src/types/raw/space/AudioSpaceById.ts +57 -0
  124. package/src/types/raw/space/Details.ts +3 -352
  125. package/src/types/raw/tweet/Post.ts +19 -1
  126. package/src/types/raw/user/About.ts +77 -0
  127. package/src/types/raw/user/ChangePassword.ts +8 -0
  128. package/src/types/raw/user/ProfileUpdate.ts +1 -0
  129. package/src/types/raw/user/Settings.ts +23 -0
  130. package/tsconfig.json +2 -2
package/src/index.ts CHANGED
@@ -26,14 +26,17 @@ export * from './models/data/DirectMessage';
26
26
  export * from './models/data/Inbox';
27
27
  export * from './models/data/List';
28
28
  export * from './models/data/Notification';
29
+ export * from './models/data/Space';
29
30
  export * from './models/data/Tweet';
30
31
  export * from './models/data/User';
32
+ export * from './models/data/UserAbout';
31
33
  export * from './models/errors/TwitterError';
32
34
 
33
35
  // REQUESTS
34
36
  export * from './requests/DirectMessage';
35
37
  export * from './requests/List';
36
38
  export * from './requests/Media';
39
+ export * from './requests/Space';
37
40
  export * from './requests/Tweet';
38
41
  export * from './requests/User';
39
42
 
@@ -41,6 +44,7 @@ export * from './requests/User';
41
44
  export * from './services/public/DirectMessageService';
42
45
  export * from './services/public/FetcherService';
43
46
  export * from './services/public/ListService';
47
+ export * from './services/public/SpaceService';
44
48
  export * from './services/public/TweetService';
45
49
  export * from './services/public/UserService';
46
50
 
@@ -55,8 +59,10 @@ export * from './types/data/DirectMessage';
55
59
  export * from './types/data/Inbox';
56
60
  export * from './types/data/List';
57
61
  export * from './types/data/Notification';
62
+ export * from './types/data/Space';
58
63
  export * from './types/data/Tweet';
59
64
  export * from './types/data/User';
65
+ export * from './types/data/UserAbout';
60
66
  export * from './types/errors/TwitterError';
61
67
  export * from './types/params/Variables';
62
68
  export { IAnalytics as IRawAnalytics } from './types/raw/base/Analytic';
@@ -68,7 +74,7 @@ export { IList as IRawList } from './types/raw/base/List';
68
74
  export { IMedia as IRawMedia } from './types/raw/base/Media';
69
75
  export { IMessage as IRawMessage } from './types/raw/base/Message';
70
76
  export { INotification as IRawNotification } from './types/raw/base/Notification';
71
- export { ISpace as IRawSpace } from './types/raw/base/Space';
77
+ export { IRawSpace } from './types/raw/base/Space';
72
78
  export { ITweet as IRawTweet } from './types/raw/base/Tweet';
73
79
  export { IUser as IRawUser } from './types/raw/base/User';
74
80
  export { IDataResult as IRawDataResult } from './types/raw/composite/DataResult';
@@ -83,6 +89,7 @@ export { IListTweetsResponse as IRawListTweetsResponse } from './types/raw/list/
83
89
  export { IMediaFinalizeUploadResponse as IRawMediaFinalizeUploadResponse } from './types/raw/media/FinalizeUpload';
84
90
  export { IMediaInitializeUploadResponse as IRawMediaInitializeUploadResponse } from './types/raw/media/InitalizeUpload';
85
91
  export { IMediaLiveVideoStreamResponse as IRawMediaLiveVideoStreamResponse } from './types/raw/media/LiveVideoStream';
92
+ export { IAudioSpaceByIdResponse as IRawSpaceDetailsResponse } from './types/raw/space/AudioSpaceById';
86
93
  export { ITweetDetailsResponse as IRawTweetDetailsResponse } from './types/raw/tweet/Details';
87
94
  export { ITweetDetailsBulkResponse as IRawTweetDetailsBulkResponse } from './types/raw/tweet/DetailsBulk';
88
95
  export { ITweetLikeResponse as IRawTweetLikeResponse } from './types/raw/tweet/Like';
@@ -97,6 +104,7 @@ export { ITweetUnlikeResponse as IRawTweetUnlikeResponse } from './types/raw/twe
97
104
  export { ITweetUnpostResponse as IRawTweetUnpostResponse } from './types/raw/tweet/Unpost';
98
105
  export { ITweetUnretweetResponse as IRawTweetUnretweetResponse } from './types/raw/tweet/Unretweet';
99
106
  export { ITweetUnscheduleResponse as ITRawTweetUnscheduleResponse } from './types/raw/tweet/Unschedule';
107
+ export { IUserAboutResponse as IRawUserAboutResponse } from './types/raw/user/About';
100
108
  export { IUserAffiliatesResponse as IRawUserAffiliatesResponse } from './types/raw/user/Affiliates';
101
109
  export { IUserAnalyticsResponse as IRawUserAnalyticsResponse } from './types/raw/user/Analytics';
102
110
  export { IUserBookmarkFoldersResponse as IRawUserBookmarkFoldersResponse } from './types/raw/user/BookmarkFolders';
@@ -120,6 +128,8 @@ export { IUserTweetsResponse as IRawUserTweetsResponse } from './types/raw/user/
120
128
  export { IUserTweetsAndRepliesResponse as IRawUserTweetsAndRepliesResponse } from './types/raw/user/TweetsAndReplies';
121
129
  export { IUserUnfollowResponse as IRawUserUnfollowResponse } from './types/raw/user/Unfollow';
122
130
  export { IUserProfileUpdateResponse as IRawUserProfileUpdateResponse } from './types/raw/user/ProfileUpdate';
131
+ export { IUserSettingsResponse as IRawUserSettingsResponse } from './types/raw/user/Settings';
132
+ export { IUserChangePasswordResponse as IRawUserChangePasswordResponse } from './types/raw/user/ChangePassword';
123
133
  export * from './types/ErrorHandler';
124
134
  export * from './types/RettiwtConfig';
125
135
  export { IConversationTimelineResponse as IRawConversationTimelineResponse } from './types/raw/dm/Conversation';
@@ -1,6 +1,10 @@
1
- import { Agent } from 'https';
1
+ import { Agent as HttpAgent } from 'http';
2
+ import { Agent as HttpsAgent } from 'https';
2
3
 
4
+ import { AxiosProxyConfig, AxiosResponse } from 'axios';
5
+ import { HttpProxyAgent } from 'http-proxy-agent';
3
6
  import { HttpsProxyAgent } from 'https-proxy-agent';
7
+ import { SocksProxyAgent } from 'socks-proxy-agent';
4
8
 
5
9
  import { AuthService } from '../services/internal/AuthService';
6
10
  import { IErrorHandler } from '../types/ErrorHandler';
@@ -34,7 +38,9 @@ export class RettiwtConfig implements IRettiwtConfig {
34
38
  // Parameters for internal use
35
39
  private _apiKey?: string;
36
40
  private _headers: { [key: string]: string };
37
- private _httpsAgent: Agent;
41
+ private _httpAgent: HttpAgent;
42
+ private _httpsAgent: HttpsAgent;
43
+ private _proxy?: AxiosProxyConfig | string | null;
38
44
  private _userId: string | undefined;
39
45
 
40
46
  // Parameters that can be set once, upon initialization
@@ -42,6 +48,7 @@ export class RettiwtConfig implements IRettiwtConfig {
42
48
  public readonly errorHandler?: IErrorHandler;
43
49
  public readonly logging?: boolean;
44
50
  public readonly maxRetries: number;
51
+ public readonly responseMiddleware?: (response: AxiosResponse) => void | Promise<void>;
45
52
  public readonly timeout?: number;
46
53
 
47
54
  /**
@@ -49,11 +56,12 @@ export class RettiwtConfig implements IRettiwtConfig {
49
56
  */
50
57
  public constructor(config?: IRettiwtConfig) {
51
58
  this._apiKey = config?.apiKey;
52
- this._httpsAgent = config?.proxyUrl ? new HttpsProxyAgent(config?.proxyUrl) : new Agent();
59
+ this._proxy = config?.proxy;
53
60
  this._userId = config?.apiKey ? AuthService.getUserId(config?.apiKey) : undefined;
54
61
  this.delay = config?.delay ?? 0;
55
62
  this.maxRetries = config?.maxRetries ?? 0;
56
63
  this.errorHandler = config?.errorHandler;
64
+ this.responseMiddleware = config?.responseMiddleware;
57
65
  this.logging = config?.logging;
58
66
  this.timeout = config?.timeout;
59
67
  this.apiKey = config?.apiKey;
@@ -61,18 +69,49 @@ export class RettiwtConfig implements IRettiwtConfig {
61
69
  ...DefaultHeaders,
62
70
  ...config?.headers,
63
71
  };
72
+
73
+ // Initializing the HTTP(S) agent(s)
74
+ const agents = this._getRequestAgents(config?.proxy);
75
+ this._httpAgent = agents.httpAgent;
76
+ this._httpsAgent = agents.httpsAgent;
64
77
  }
65
78
 
66
79
  public get apiKey(): string | undefined {
67
80
  return this._apiKey;
68
81
  }
69
82
 
83
+ /**
84
+ * The Axios proxy configuration to use.
85
+ *
86
+ * @remarks
87
+ * <br>
88
+ * - If `proxy` is set, Axios' built-in env-variable-based proxy is disabled.
89
+ */
90
+ public get axiosProxyConfig(): AxiosProxyConfig | false | undefined {
91
+ // If user explicitly set to null or a proxy URL, disable Axios' built-in proxy
92
+ if (this._proxy === null || typeof this._proxy === 'string') {
93
+ return false;
94
+ }
95
+ // If user has set an AxiosProxyConfig, use that
96
+ if (this._proxy !== undefined) {
97
+ return this._proxy;
98
+ }
99
+
100
+ // Default: Let axios use it's built-in env-variable-based proxy.
101
+ return undefined;
102
+ }
103
+
70
104
  public get headers(): { [key: string]: string } {
71
105
  return this._headers;
72
106
  }
73
107
 
108
+ /** The HTTP agent instance to use. */
109
+ public get httpAgent(): HttpAgent {
110
+ return this._httpAgent;
111
+ }
112
+
74
113
  /** The HTTPS agent instance to use. */
75
- public get httpsAgent(): Agent {
114
+ public get httpsAgent(): HttpsAgent {
76
115
  return this._httpsAgent;
77
116
  }
78
117
 
@@ -93,8 +132,44 @@ export class RettiwtConfig implements IRettiwtConfig {
93
132
  };
94
133
  }
95
134
 
96
- public set proxyUrl(proxyUrl: URL | undefined) {
97
- this._httpsAgent = proxyUrl ? new HttpsProxyAgent(proxyUrl) : new Agent();
135
+ public set proxy(proxy: AxiosProxyConfig | string | null | undefined) {
136
+ // Update HTTP(s) agents
137
+ const agents = this._getRequestAgents(proxy);
138
+ this._httpAgent = agents.httpAgent;
139
+ this._httpsAgent = agents.httpsAgent;
140
+
141
+ this._proxy = proxy;
142
+ }
143
+
144
+ /**
145
+ * Returns the appropriate HTTP(s) agents based on the type of proxy config.
146
+ *
147
+ * @param proxy - The proxy configuration.
148
+ *
149
+ * @returns The HTTP(s) agents.
150
+ */
151
+ private _getRequestAgents(proxy?: AxiosProxyConfig | string | null): {
152
+ httpAgent: HttpAgent;
153
+ httpsAgent: HttpsAgent;
154
+ } {
155
+ let httpAgent: HttpAgent | undefined;
156
+ let httpsAgent: HttpsAgent | undefined;
157
+
158
+ if (typeof proxy === 'string' && (proxy.startsWith('http://') || proxy.startsWith('https://'))) {
159
+ httpAgent = new HttpProxyAgent(proxy);
160
+ httpsAgent = new HttpsProxyAgent(proxy);
161
+ } else if (typeof proxy === 'string' && proxy.startsWith('socks')) {
162
+ httpAgent = new SocksProxyAgent(proxy);
163
+ httpsAgent = new SocksProxyAgent(proxy);
164
+ } else {
165
+ httpAgent = new HttpAgent();
166
+ httpsAgent = new HttpsAgent();
167
+ }
168
+
169
+ return {
170
+ httpAgent: httpAgent,
171
+ httpsAgent: httpsAgent,
172
+ };
98
173
  }
99
174
  }
100
175
 
@@ -17,11 +17,14 @@ export class FetchArgs implements IFetchArgs {
17
17
  public granularity?: RawAnalyticsGranularity;
18
18
  public id?: string;
19
19
  public ids?: string[];
20
+ public isMetatagsQuery?: boolean;
20
21
  public maxId?: string;
21
22
  public metrics?: RawAnalyticsMetric[];
22
23
  public showVerifiedFollowers?: boolean;
23
24
  public sortBy?: TweetRepliesSortType;
24
25
  public toTime?: Date;
26
+ public withListeners?: boolean;
27
+ public withReplays?: boolean;
25
28
 
26
29
  /**
27
30
  * @param args - Additional user-defined arguments for fetching the resource.
@@ -29,6 +32,7 @@ export class FetchArgs implements IFetchArgs {
29
32
  public constructor(args: IFetchArgs) {
30
33
  this.id = args.id;
31
34
  this.ids = args.ids;
35
+ this.isMetatagsQuery = args.isMetatagsQuery;
32
36
  this.count = args.count;
33
37
  this.cursor = args.cursor;
34
38
  this.filter = args.filter ? new TweetFilter(args.filter) : undefined;
@@ -41,6 +45,8 @@ export class FetchArgs implements IFetchArgs {
41
45
  this.activeConversationId = args.activeConversationId;
42
46
  this.conversationId = args.conversationId;
43
47
  this.maxId = args.maxId;
48
+ this.withListeners = args.withListeners;
49
+ this.withReplays = args.withReplays;
44
50
  }
45
51
  }
46
52
 
@@ -1,4 +1,4 @@
1
- import { INewTweet, INewTweetMedia, IPostArgs, IUploadArgs } from '../../types/args/PostArgs';
1
+ import { IChangePasswordArgs, INewTweet, INewTweetMedia, IPostArgs, IUploadArgs } from '../../types/args/PostArgs';
2
2
 
3
3
  import { ProfileUpdateOptions } from './ProfileArgs';
4
4
 
@@ -8,12 +8,16 @@ import { ProfileUpdateOptions } from './ProfileArgs';
8
8
  * @public
9
9
  */
10
10
  export class PostArgs implements IPostArgs {
11
+ public changePassword?: ChangePasswordArgs;
11
12
  public conversationId?: string;
12
13
  public id?: string;
14
+ public profileBanner?: string;
15
+ public profileImage?: string;
13
16
  public profileOptions?: ProfileUpdateOptions;
14
17
  public tweet?: NewTweet;
15
18
  public upload?: UploadArgs;
16
19
  public userId?: string;
20
+ public username?: string;
17
21
 
18
22
  /**
19
23
  * @param resource - The resource to be posted.
@@ -24,8 +28,36 @@ export class PostArgs implements IPostArgs {
24
28
  this.tweet = args.tweet ? new NewTweet(args.tweet) : undefined;
25
29
  this.upload = args.upload ? new UploadArgs(args.upload) : undefined;
26
30
  this.userId = args.userId;
31
+ this.username = PostArgs._validateNonEmptyString(args.username, 'Username');
27
32
  this.conversationId = args.conversationId;
28
33
  this.profileOptions = args.profileOptions ? new ProfileUpdateOptions(args.profileOptions) : undefined;
34
+ this.profileImage = PostArgs._validateNonEmptyString(args.profileImage, 'Profile image');
35
+ this.profileBanner = PostArgs._validateNonEmptyString(args.profileBanner, 'Profile banner');
36
+ this.changePassword = args.changePassword ? new ChangePasswordArgs(args.changePassword) : undefined;
37
+ }
38
+
39
+ /**
40
+ * Validates if a data value is a valid string.
41
+ *
42
+ * @param value - The data to validate.
43
+ * @param fieldName - The field name whose value is to be validated.
44
+ *
45
+ * @returns The validated, parsed string. If data was `undefined`, returns `undefined`.
46
+ */
47
+ private static _validateNonEmptyString(value: unknown, fieldName: string): string | undefined {
48
+ if (value === undefined) {
49
+ return undefined;
50
+ }
51
+
52
+ if (typeof value !== 'string') {
53
+ throw new Error(`${fieldName} must be a string`);
54
+ }
55
+
56
+ if (value.trim().length === 0) {
57
+ throw new Error(`${fieldName} cannot be empty`);
58
+ }
59
+
60
+ return value;
29
61
  }
30
62
  }
31
63
 
@@ -91,3 +123,28 @@ export class UploadArgs implements IUploadArgs {
91
123
  this.id = args.id;
92
124
  }
93
125
  }
126
+
127
+ /**
128
+ * The args for changing authenticated user's password.
129
+ *
130
+ * @public
131
+ */
132
+ export class ChangePasswordArgs implements IChangePasswordArgs {
133
+ public currentPassword: string;
134
+ public newPassword: string;
135
+
136
+ public constructor(args: IChangePasswordArgs) {
137
+ if (!args.currentPassword || args.currentPassword.trim().length === 0) {
138
+ throw new Error('Current password cannot be empty');
139
+ }
140
+ if (!args.newPassword || args.newPassword.trim().length === 0) {
141
+ throw new Error('New password cannot be empty');
142
+ }
143
+ if (args.newPassword.length < 8) {
144
+ throw new Error('New password must be at least 8 characters long');
145
+ }
146
+
147
+ this.currentPassword = args.currentPassword;
148
+ this.newPassword = args.newPassword;
149
+ }
150
+ }
@@ -0,0 +1,201 @@
1
+ import { LogActions } from '../../enums/Logging';
2
+ import { LogService } from '../../services/internal/LogService';
3
+ import { ISpace, ISpaceParticipant, ISpaceParticipants } from '../../types/data/Space';
4
+ import {
5
+ IAudioSpace,
6
+ IAudioSpaceByIdResponse,
7
+ IAudioSpaceParticipant,
8
+ IAudioSpaceParticipants,
9
+ } from '../../types/raw/space/AudioSpaceById';
10
+
11
+ /**
12
+ * The details of a single Space.
13
+ *
14
+ * @public
15
+ */
16
+ export class Space implements ISpace {
17
+ /** The raw space details. */
18
+ private readonly _raw: IAudioSpace;
19
+
20
+ public conversationControls?: number;
21
+ public createdAt?: string;
22
+ public creatorId?: string;
23
+ public disallowJoin?: boolean;
24
+ public endedAt?: string;
25
+ public id: string;
26
+ public isEmployeeOnly?: boolean;
27
+ public isLocked?: boolean;
28
+ public isMuted?: boolean;
29
+ public isSpaceAvailableForClipping?: boolean;
30
+ public isSpaceAvailableForReplay?: boolean;
31
+ public isSubscribed?: boolean;
32
+ public mediaKey?: string;
33
+ public noIncognito?: boolean;
34
+ public participantCount?: number;
35
+ public participants?: ISpaceParticipants;
36
+ public scheduledStart?: string;
37
+ public startedAt?: string;
38
+ public state?: string;
39
+ public title?: string;
40
+ public totalLiveListeners?: number;
41
+ public totalReplayWatched?: number;
42
+ public updatedAt?: string;
43
+
44
+ /**
45
+ * @param space - The raw space details.
46
+ */
47
+ public constructor(space: IAudioSpace) {
48
+ this._raw = { ...space };
49
+
50
+ const metadata = space.metadata;
51
+
52
+ this.id = metadata?.rest_id ?? '';
53
+ this.state = metadata?.state;
54
+ this.title = metadata?.title;
55
+ this.mediaKey = metadata?.media_key;
56
+ this.createdAt = Space._timestampToIso(metadata?.created_at);
57
+ this.scheduledStart = Space._timestampToIso(metadata?.scheduled_start);
58
+ this.startedAt = Space._timestampToIso(metadata?.started_at);
59
+ this.endedAt = Space._timestampToIso(metadata?.ended_at);
60
+ this.updatedAt = Space._timestampToIso(metadata?.updated_at);
61
+ this.creatorId = metadata?.creator_results?.result?.rest_id ?? metadata?.creator_id;
62
+ this.conversationControls = metadata?.conversation_controls;
63
+ this.disallowJoin = metadata?.disallow_join;
64
+ this.isEmployeeOnly = metadata?.is_employee_only;
65
+ this.isLocked = metadata?.is_locked;
66
+ this.isMuted = metadata?.is_muted;
67
+ this.isSpaceAvailableForClipping = metadata?.is_space_available_for_clipping;
68
+ this.isSpaceAvailableForReplay = metadata?.is_space_available_for_replay;
69
+ this.noIncognito = metadata?.no_incognito;
70
+ this.totalLiveListeners = metadata?.total_live_listeners;
71
+ this.totalReplayWatched = metadata?.total_replay_watched;
72
+ this.participantCount = space.participants?.total ?? metadata?.participant_count;
73
+ this.isSubscribed = space.is_subscribed;
74
+ this.participants = Space._mapParticipants(space.participants);
75
+ }
76
+
77
+ /** The raw space details. */
78
+ public get raw(): IAudioSpace {
79
+ return { ...this._raw };
80
+ }
81
+
82
+ /**
83
+ * Maps a raw participant to a deserialized participant.
84
+ *
85
+ * @param participant - The raw participant data.
86
+ */
87
+ private static _mapParticipant(participant: IAudioSpaceParticipant): ISpaceParticipant {
88
+ const userId = participant.user_results?.rest_id ?? participant.user_results?.result?.rest_id;
89
+
90
+ return {
91
+ id: userId,
92
+ screenName: participant.twitter_screen_name,
93
+ displayName: participant.display_name,
94
+ avatarUrl: participant.avatar_url,
95
+ isVerified: participant.is_verified,
96
+ isMutedByAdmin: participant.is_muted_by_admin,
97
+ isMutedByGuest: participant.is_muted_by_guest,
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Maps raw participants to deserialized participants.
103
+ *
104
+ * @param participants - The raw participants data.
105
+ */
106
+ private static _mapParticipants(participants?: IAudioSpaceParticipants): ISpaceParticipants | undefined {
107
+ if (!participants) {
108
+ return undefined;
109
+ }
110
+
111
+ return {
112
+ total: participants.total,
113
+ admins: (participants.admins ?? []).map((participant) => Space._mapParticipant(participant)),
114
+ speakers: (participants.speakers ?? []).map((participant) => Space._mapParticipant(participant)),
115
+ listeners: (participants.listeners ?? []).map((participant) => Space._mapParticipant(participant)),
116
+ };
117
+ }
118
+
119
+ /**
120
+ * Convert timestamp to ISO string.
121
+ *
122
+ * @param value - The timestamp value.
123
+ */
124
+ private static _timestampToIso(value?: number | string): string | undefined {
125
+ if (value == undefined) {
126
+ return undefined;
127
+ }
128
+
129
+ const numeric = typeof value === 'string' ? Number(value) : value;
130
+
131
+ if (!Number.isNaN(numeric)) {
132
+ return new Date(numeric).toISOString();
133
+ }
134
+
135
+ const parsed = new Date(value);
136
+
137
+ if (!Number.isNaN(parsed.getTime())) {
138
+ return parsed.toISOString();
139
+ }
140
+
141
+ return undefined;
142
+ }
143
+
144
+ /**
145
+ * Extracts and deserializes a single target space from the given raw response data.
146
+ *
147
+ * @param response - The raw response data.
148
+ *
149
+ * @returns The target deserialized space.
150
+ */
151
+ public static single(response: IAudioSpaceByIdResponse): Space | undefined {
152
+ const audioSpace = response.data?.audioSpace;
153
+ const spaceId = audioSpace?.metadata?.rest_id;
154
+
155
+ if (audioSpace && spaceId) {
156
+ // Logging
157
+ LogService.log(LogActions.DESERIALIZE, { id: spaceId });
158
+
159
+ return new Space(audioSpace);
160
+ }
161
+
162
+ // Logging
163
+ LogService.log(LogActions.WARNING, {
164
+ action: LogActions.DESERIALIZE,
165
+ message: 'Space not found, skipping',
166
+ });
167
+
168
+ return undefined;
169
+ }
170
+
171
+ /**
172
+ * @returns A serializable JSON representation of `this` object.
173
+ */
174
+ public toJSON(): ISpace {
175
+ return {
176
+ id: this.id,
177
+ state: this.state,
178
+ title: this.title,
179
+ mediaKey: this.mediaKey,
180
+ createdAt: this.createdAt,
181
+ scheduledStart: this.scheduledStart,
182
+ startedAt: this.startedAt,
183
+ endedAt: this.endedAt,
184
+ updatedAt: this.updatedAt,
185
+ creatorId: this.creatorId,
186
+ conversationControls: this.conversationControls,
187
+ disallowJoin: this.disallowJoin,
188
+ isEmployeeOnly: this.isEmployeeOnly,
189
+ isLocked: this.isLocked,
190
+ isMuted: this.isMuted,
191
+ isSpaceAvailableForClipping: this.isSpaceAvailableForClipping,
192
+ isSpaceAvailableForReplay: this.isSpaceAvailableForReplay,
193
+ noIncognito: this.noIncognito,
194
+ totalLiveListeners: this.totalLiveListeners,
195
+ totalReplayWatched: this.totalReplayWatched,
196
+ participantCount: this.participantCount,
197
+ isSubscribed: this.isSubscribed,
198
+ participants: this.participants,
199
+ };
200
+ }
201
+ }
@@ -0,0 +1,161 @@
1
+ import { LogActions } from '../../enums/Logging';
2
+ import { LogService } from '../../services/internal/LogService';
3
+ import {
4
+ IUserAbout,
5
+ IUserAboutProfile,
6
+ IUserAboutUsernameChanges,
7
+ IUserAboutVerificationInfo,
8
+ } from '../../types/data/UserAbout';
9
+ import { IUserAboutResponse, IUserAboutResult } from '../../types/raw/user/About';
10
+
11
+ /* eslint-disable @typescript-eslint/naming-convention */
12
+ type IRawUsernameChanges = {
13
+ count?: string;
14
+ last_changed_at_msec?: string;
15
+ };
16
+ /* eslint-enable @typescript-eslint/naming-convention */
17
+
18
+ /**
19
+ * The about profile details of a single user.
20
+ *
21
+ * @public
22
+ */
23
+ export class UserAbout implements IUserAbout {
24
+ /** The raw about profile details. */
25
+ private readonly _raw: IUserAboutResult;
26
+
27
+ public aboutProfile?: IUserAboutProfile;
28
+ public createdAt: string;
29
+ public fullName: string;
30
+ public id: string;
31
+ public isProtected?: boolean;
32
+ public isVerified: boolean;
33
+ public profileImage: string;
34
+ public profileImageShape?: string;
35
+ public userName: string;
36
+ public verificationInfo?: IUserAboutVerificationInfo;
37
+
38
+ /**
39
+ * @param user - The raw about profile details.
40
+ */
41
+ public constructor(user: IUserAboutResult) {
42
+ this._raw = { ...user };
43
+
44
+ this.id = user.rest_id ?? user.id ?? '';
45
+ this.userName = user.core?.screen_name ?? '';
46
+ this.fullName = user.core?.name ?? '';
47
+ this.createdAt = new Date(user.core?.created_at ?? 0).toISOString();
48
+ this.profileImage = user.avatar?.image_url ?? '';
49
+ this.profileImageShape = user.profile_image_shape;
50
+ this.isVerified = user.is_blue_verified ?? false;
51
+ this.isProtected = user.privacy?.protected;
52
+ this.aboutProfile = UserAbout._buildAboutProfile(user);
53
+ this.verificationInfo = UserAbout._buildVerificationInfo(user);
54
+ }
55
+
56
+ /** The raw about profile details. */
57
+ public get raw(): IUserAboutResult {
58
+ return { ...this._raw };
59
+ }
60
+
61
+ private static _buildAboutProfile(user: IUserAboutResult): IUserAboutProfile | undefined {
62
+ const profile = user.about_profile;
63
+
64
+ if (!profile) {
65
+ return undefined;
66
+ }
67
+
68
+ const usernameChanges = UserAbout._buildUsernameChanges(profile.username_changes);
69
+
70
+ return {
71
+ createdCountryAccurate: profile.created_country_accurate,
72
+ accountBasedIn: profile.account_based_in,
73
+ locationAccurate: profile.location_accurate,
74
+ learnMoreUrl: profile.learn_more_url,
75
+ source: profile.source,
76
+ usernameChanges: usernameChanges,
77
+ };
78
+ }
79
+
80
+ private static _buildUsernameChanges(changes?: IRawUsernameChanges): IUserAboutUsernameChanges | undefined {
81
+ if (!changes) {
82
+ return undefined;
83
+ }
84
+
85
+ return {
86
+ count: UserAbout._toNumber(changes.count),
87
+ lastChangedAt: UserAbout._toIsoFromMsec(changes.last_changed_at_msec),
88
+ };
89
+ }
90
+
91
+ private static _buildVerificationInfo(user: IUserAboutResult): IUserAboutVerificationInfo | undefined {
92
+ const info = user.verification_info;
93
+
94
+ if (!info) {
95
+ return undefined;
96
+ }
97
+
98
+ return {
99
+ isIdentityVerified: info.is_identity_verified,
100
+ verifiedSince: UserAbout._toIsoFromMsec(info.reason?.verified_since_msec),
101
+ };
102
+ }
103
+
104
+ private static _toIsoFromMsec(value?: string | number): string | undefined {
105
+ const parsed = UserAbout._toNumber(value);
106
+
107
+ return parsed === undefined ? undefined : new Date(parsed).toISOString();
108
+ }
109
+
110
+ private static _toNumber(value?: string | number): number | undefined {
111
+ if (value === undefined || value === null) {
112
+ return undefined;
113
+ }
114
+
115
+ const parsed = typeof value === 'number' ? value : Number(value);
116
+
117
+ return Number.isFinite(parsed) ? parsed : undefined;
118
+ }
119
+
120
+ /**
121
+ * Extracts and deserializes a single target user about profile from the given raw response data.
122
+ *
123
+ * @param response - The raw response data.
124
+ *
125
+ * @returns The target deserialized user about profile.
126
+ */
127
+ public static single(response: NonNullable<unknown>): UserAbout | undefined {
128
+ const result = (response as IUserAboutResponse)?.data?.user_result_by_screen_name?.result;
129
+
130
+ if (!result || result.__typename !== 'User') {
131
+ LogService.log(LogActions.WARNING, {
132
+ action: LogActions.DESERIALIZE,
133
+ message: `User not found, skipping`,
134
+ });
135
+ return undefined;
136
+ }
137
+
138
+ // Logging
139
+ LogService.log(LogActions.DESERIALIZE, { id: result.rest_id ?? result.id });
140
+
141
+ return new UserAbout(result);
142
+ }
143
+
144
+ /**
145
+ * @returns A serializable JSON representation of `this` object.
146
+ */
147
+ public toJSON(): IUserAbout {
148
+ return {
149
+ id: this.id,
150
+ userName: this.userName,
151
+ fullName: this.fullName,
152
+ createdAt: this.createdAt,
153
+ profileImage: this.profileImage,
154
+ profileImageShape: this.profileImageShape,
155
+ isVerified: this.isVerified,
156
+ isProtected: this.isProtected,
157
+ aboutProfile: this.aboutProfile,
158
+ verificationInfo: this.verificationInfo,
159
+ };
160
+ }
161
+ }