tentacle-sdk 0.0.1
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/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/index.cjs +889 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1562 -0
- package/dist/index.d.ts +1562 -0
- package/dist/index.js +884 -0
- package/dist/index.js.map +1 -0
- package/docs/api/classes/DeviceAuthFlow.md +107 -0
- package/docs/api/classes/FileCredentialStore.md +95 -0
- package/docs/api/classes/TentacleClient.md +118 -0
- package/docs/api/classes/TentacleError.md +69 -0
- package/docs/api/index.md +117 -0
- package/docs/api/interfaces/AppJson.md +20 -0
- package/docs/api/interfaces/ChatMessageEmoji.md +16 -0
- package/docs/api/interfaces/ChatMessageEmote.md +16 -0
- package/docs/api/interfaces/ChatMessagePosition.md +14 -0
- package/docs/api/interfaces/CommonChatMessage.md +27 -0
- package/docs/api/interfaces/CommonEventJson.md +32 -0
- package/docs/api/interfaces/CredentialStore.md +55 -0
- package/docs/api/interfaces/DeviceAuthInitResult.md +17 -0
- package/docs/api/interfaces/DeviceAuthOptions.md +18 -0
- package/docs/api/interfaces/DeviceAuthPollResult.md +14 -0
- package/docs/api/interfaces/DonationUnlock.md +16 -0
- package/docs/api/interfaces/FileCredentialStoreOptions.md +13 -0
- package/docs/api/interfaces/GiftedSubUnlock.md +15 -0
- package/docs/api/interfaces/KickBadge.md +15 -0
- package/docs/api/interfaces/KickChatMessageJson.md +35 -0
- package/docs/api/interfaces/KickEventJson_ChannelFollow.md +25 -0
- package/docs/api/interfaces/KickEventJson_ChannelSubscriptionGifts.md +25 -0
- package/docs/api/interfaces/KickEventJson_ChannelSubscriptionNew.md +25 -0
- package/docs/api/interfaces/KickEventJson_ChannelSubscriptionRenewal.md +25 -0
- package/docs/api/interfaces/KickEventJson_LivestreamStatusUpdated.md +24 -0
- package/docs/api/interfaces/RealtimeEvent_StreamChatMessage.md +14 -0
- package/docs/api/interfaces/RealtimeEvent_StreamEvent.md +14 -0
- package/docs/api/interfaces/RealtimeEvent_StreamViewerActivity.md +14 -0
- package/docs/api/interfaces/RealtimeSubscribeOptions.md +16 -0
- package/docs/api/interfaces/StreamViewerActivityJson.md +16 -0
- package/docs/api/interfaces/SubUnlock.md +15 -0
- package/docs/api/interfaces/SubathonStats_Donations.md +23 -0
- package/docs/api/interfaces/SubathonStats_GiftedSubscriptions.md +22 -0
- package/docs/api/interfaces/SubathonStats_Subscriptions.md +20 -0
- package/docs/api/interfaces/TentacleClientConfig.md +14 -0
- package/docs/api/interfaces/TentacleClientCreateOptions.md +15 -0
- package/docs/api/interfaces/TwitchChatMessageJson.md +41 -0
- package/docs/api/interfaces/TwitchEventJson_Cheer.md +29 -0
- package/docs/api/interfaces/TwitchEventJson_Follow.md +27 -0
- package/docs/api/interfaces/TwitchEventJson_Raid.md +27 -0
- package/docs/api/interfaces/TwitchEventJson_RedemptionAdd.md +34 -0
- package/docs/api/interfaces/TwitchEventJson_StreamOnline.md +26 -0
- package/docs/api/interfaces/TwitchEventJson_Subscription.md +28 -0
- package/docs/api/interfaces/TwitchEventJson_SubscriptionGift.md +30 -0
- package/docs/api/interfaces/TwitchUserInfo.md +24 -0
- package/docs/api/interfaces/ViewerActionJson.md +18 -0
- package/docs/api/interfaces/ViewerJson.md +23 -0
- package/docs/api/interfaces/ViewerKickJson.md +25 -0
- package/docs/api/interfaces/ViewerMiniJson.md +21 -0
- package/docs/api/interfaces/ViewerPropertyJsonBase.md +22 -0
- package/docs/api/interfaces/ViewerPropertyJson_Bool.md +22 -0
- package/docs/api/interfaces/ViewerPropertyJson_Number.md +22 -0
- package/docs/api/interfaces/ViewerPropertyJson_String.md +22 -0
- package/docs/api/interfaces/ViewerTwitchJson.md +24 -0
- package/docs/api/interfaces/ViewersByPropertyOutput.md +17 -0
- package/docs/api/type-aliases/DateIsoString.md +9 -0
- package/docs/api/type-aliases/KickEventJson.md +9 -0
- package/docs/api/type-aliases/OrderDirection.md +9 -0
- package/docs/api/type-aliases/RealtimeEvent.md +36 -0
- package/docs/api/type-aliases/StreamChatMessageJson.md +9 -0
- package/docs/api/type-aliases/StreamEventJson.md +9 -0
- package/docs/api/type-aliases/StreamPlatform.md +9 -0
- package/docs/api/type-aliases/TwitchEventJson.md +9 -0
- package/docs/api/type-aliases/TwitchEventType.md +9 -0
- package/docs/api/type-aliases/UnsubscribeFunction.md +22 -0
- package/docs/api/type-aliases/ViewerPropertyJson.md +9 -0
- package/docs/api/type-aliases/ViewerPropertyType.md +9 -0
- package/docs/overview.md +160 -0
- package/package.json +54 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1562 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP utilities for the Tentacle SDK.
|
|
3
|
+
* Uses tRPC HTTP protocol to communicate with the Tentacle API.
|
|
4
|
+
*
|
|
5
|
+
* @module http
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown by the Tentacle SDK when an API request fails.
|
|
9
|
+
*/
|
|
10
|
+
declare class TentacleError extends Error {
|
|
11
|
+
/**
|
|
12
|
+
* HTTP status code of the failed request.
|
|
13
|
+
*/
|
|
14
|
+
readonly status: number;
|
|
15
|
+
/**
|
|
16
|
+
* Error code from the server, if available.
|
|
17
|
+
*/
|
|
18
|
+
readonly code?: string;
|
|
19
|
+
constructor(message: string, status: number, code?: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for the HTTP client.
|
|
23
|
+
*/
|
|
24
|
+
interface HttpClientConfig {
|
|
25
|
+
/**
|
|
26
|
+
* Base URL of the Tentacle API.
|
|
27
|
+
* @example "https://api.tentacle.live"
|
|
28
|
+
*/
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
/**
|
|
31
|
+
* Access token for authentication.
|
|
32
|
+
* Obtain this from the Tentacle dashboard or via the auth API.
|
|
33
|
+
*/
|
|
34
|
+
accessToken?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* HTTP client for making tRPC requests to the Tentacle API.
|
|
38
|
+
*/
|
|
39
|
+
declare class HttpClient {
|
|
40
|
+
private readonly baseUrl;
|
|
41
|
+
private readonly accessToken?;
|
|
42
|
+
constructor(config: HttpClientConfig);
|
|
43
|
+
/**
|
|
44
|
+
* Get the headers for a request.
|
|
45
|
+
*/
|
|
46
|
+
private getHeaders;
|
|
47
|
+
/**
|
|
48
|
+
* Build the tRPC URL for a procedure call.
|
|
49
|
+
*
|
|
50
|
+
* @param procedure - Full procedure path (e.g., "apps.list")
|
|
51
|
+
* @param input - Optional input for queries (will be URL encoded)
|
|
52
|
+
*/
|
|
53
|
+
private buildTrpcUrl;
|
|
54
|
+
/**
|
|
55
|
+
* Handle the tRPC response.
|
|
56
|
+
*/
|
|
57
|
+
private handleResponse;
|
|
58
|
+
/**
|
|
59
|
+
* Make a tRPC query (GET request).
|
|
60
|
+
*
|
|
61
|
+
* @param procedure - Full procedure path (e.g., "apps.list")
|
|
62
|
+
* @param input - Optional input data
|
|
63
|
+
* @returns The response data
|
|
64
|
+
* @throws {TentacleError} If the request fails
|
|
65
|
+
*/
|
|
66
|
+
query<T>(procedure: string, input?: unknown): Promise<T>;
|
|
67
|
+
/**
|
|
68
|
+
* Make a tRPC mutation (POST request).
|
|
69
|
+
*
|
|
70
|
+
* @param procedure - Full procedure path (e.g., "apps.create")
|
|
71
|
+
* @param input - Input data for the mutation
|
|
72
|
+
* @returns The response data
|
|
73
|
+
* @throws {TentacleError} If the request fails
|
|
74
|
+
*/
|
|
75
|
+
mutate<T>(procedure: string, input?: unknown): Promise<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Get the base URL for SSE connections.
|
|
78
|
+
*/
|
|
79
|
+
getBaseUrl(): string;
|
|
80
|
+
/**
|
|
81
|
+
* Get the access token for SSE connections.
|
|
82
|
+
*/
|
|
83
|
+
getAccessToken(): string | undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Type definitions for the Tentacle SDK.
|
|
88
|
+
*
|
|
89
|
+
* These types mirror the server's Zod schemas to ensure type safety.
|
|
90
|
+
* All types are defined inline to make the SDK self-contained.
|
|
91
|
+
*
|
|
92
|
+
* @module types
|
|
93
|
+
*/
|
|
94
|
+
/**
|
|
95
|
+
* ISO 8601 date string.
|
|
96
|
+
*/
|
|
97
|
+
type DateIsoString = string;
|
|
98
|
+
/**
|
|
99
|
+
* Stream platform.
|
|
100
|
+
*/
|
|
101
|
+
type StreamPlatform = "twitch" | "kick";
|
|
102
|
+
/**
|
|
103
|
+
* Position of an emote or emoji in a chat message.
|
|
104
|
+
*/
|
|
105
|
+
interface ChatMessagePosition {
|
|
106
|
+
start: number;
|
|
107
|
+
end: number;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Emoji in a chat message.
|
|
111
|
+
*/
|
|
112
|
+
interface ChatMessageEmoji {
|
|
113
|
+
code: string;
|
|
114
|
+
name: string;
|
|
115
|
+
count: number;
|
|
116
|
+
positions: ChatMessagePosition[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Emote in a chat message.
|
|
120
|
+
*/
|
|
121
|
+
interface ChatMessageEmote {
|
|
122
|
+
id: string;
|
|
123
|
+
name: string;
|
|
124
|
+
count: number;
|
|
125
|
+
positions: ChatMessagePosition[];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Base fields for all chat messages.
|
|
129
|
+
*/
|
|
130
|
+
interface CommonChatMessage {
|
|
131
|
+
$command: string | null;
|
|
132
|
+
$commandArgs: string[];
|
|
133
|
+
$createdAt: DateIsoString;
|
|
134
|
+
$emojis: Record<string, ChatMessageEmoji>;
|
|
135
|
+
$emotes: Record<string, ChatMessageEmote>;
|
|
136
|
+
$html: string;
|
|
137
|
+
$id: string;
|
|
138
|
+
$kind: "ChatMessageJson";
|
|
139
|
+
$text: string;
|
|
140
|
+
$viewerId: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Twitch chat message.
|
|
144
|
+
*/
|
|
145
|
+
interface TwitchChatMessageJson extends CommonChatMessage {
|
|
146
|
+
$platform: "twitch";
|
|
147
|
+
$type: "chat.message";
|
|
148
|
+
bits: number;
|
|
149
|
+
channelId: string;
|
|
150
|
+
color: string | null;
|
|
151
|
+
emoteOnly: boolean;
|
|
152
|
+
id: string;
|
|
153
|
+
isCheer: boolean;
|
|
154
|
+
isFirst: boolean;
|
|
155
|
+
isHighlight: boolean;
|
|
156
|
+
isRedemption: boolean;
|
|
157
|
+
isReply: boolean;
|
|
158
|
+
isReturningChatter: boolean;
|
|
159
|
+
message: string;
|
|
160
|
+
userInfo: TwitchUserInfo | null;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Twitch user info.
|
|
164
|
+
*/
|
|
165
|
+
interface TwitchUserInfo {
|
|
166
|
+
badgeInfo: Record<string, string>;
|
|
167
|
+
badges: Record<string, string>;
|
|
168
|
+
color: string | null;
|
|
169
|
+
displayName: string;
|
|
170
|
+
id: string;
|
|
171
|
+
isBroadcaster: boolean;
|
|
172
|
+
isFounder: boolean;
|
|
173
|
+
isMod: boolean;
|
|
174
|
+
isSubscriber: boolean;
|
|
175
|
+
isVip: boolean;
|
|
176
|
+
name: string;
|
|
177
|
+
userType: string | null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Kick chat message.
|
|
181
|
+
*/
|
|
182
|
+
interface KickChatMessageJson extends CommonChatMessage {
|
|
183
|
+
$platform: "kick";
|
|
184
|
+
$type: "chat.message";
|
|
185
|
+
chatroomId: number;
|
|
186
|
+
content: string;
|
|
187
|
+
createdAt: string;
|
|
188
|
+
id: string;
|
|
189
|
+
senderId: number;
|
|
190
|
+
type: string;
|
|
191
|
+
username: string;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Chat message from Twitch or Kick.
|
|
195
|
+
*/
|
|
196
|
+
type StreamChatMessageJson = TwitchChatMessageJson | KickChatMessageJson;
|
|
197
|
+
/**
|
|
198
|
+
* Base fields for all stream events.
|
|
199
|
+
*/
|
|
200
|
+
interface CommonEventJson {
|
|
201
|
+
$createdAt: DateIsoString;
|
|
202
|
+
$id: string;
|
|
203
|
+
$kind: "EventJson";
|
|
204
|
+
$userId: string;
|
|
205
|
+
$viewerId: string | null;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Twitch event types.
|
|
209
|
+
*/
|
|
210
|
+
type TwitchEventType = "channel.ban" | "channel.cheer" | "channel.follow" | "channel.raid" | "channel.channel_points_custom_reward_redemption.add" | "channel.shield_mode.begin" | "channel.shield_mode.end" | "channel.shoutout.receive" | "channel.subscribe" | "channel.subscription.gift" | "channel.subscription.message" | "stream.online" | "stream.offline";
|
|
211
|
+
/**
|
|
212
|
+
* Twitch follow event.
|
|
213
|
+
*/
|
|
214
|
+
interface TwitchEventJson_Follow extends CommonEventJson {
|
|
215
|
+
$platform: "twitch";
|
|
216
|
+
$type: "channel.follow";
|
|
217
|
+
followedAt: string;
|
|
218
|
+
userId: string;
|
|
219
|
+
userDisplayName: string;
|
|
220
|
+
userName: string;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Twitch subscription event.
|
|
224
|
+
*/
|
|
225
|
+
interface TwitchEventJson_Subscription extends CommonEventJson {
|
|
226
|
+
$platform: "twitch";
|
|
227
|
+
$type: "channel.subscribe";
|
|
228
|
+
isGift: boolean;
|
|
229
|
+
tier: string;
|
|
230
|
+
userId: string;
|
|
231
|
+
userDisplayName: string;
|
|
232
|
+
userName: string;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Twitch subscription gift event.
|
|
236
|
+
*/
|
|
237
|
+
interface TwitchEventJson_SubscriptionGift extends CommonEventJson {
|
|
238
|
+
$platform: "twitch";
|
|
239
|
+
$type: "channel.subscription.gift";
|
|
240
|
+
cumulativeTotal: number | null;
|
|
241
|
+
isAnonymous: boolean;
|
|
242
|
+
tier: string;
|
|
243
|
+
total: number;
|
|
244
|
+
userId: string | null;
|
|
245
|
+
userDisplayName: string | null;
|
|
246
|
+
userName: string | null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Twitch cheer event.
|
|
250
|
+
*/
|
|
251
|
+
interface TwitchEventJson_Cheer extends CommonEventJson {
|
|
252
|
+
$platform: "twitch";
|
|
253
|
+
$type: "channel.cheer";
|
|
254
|
+
bits: number;
|
|
255
|
+
isAnonymous: boolean;
|
|
256
|
+
message: string;
|
|
257
|
+
userId: string | null;
|
|
258
|
+
userDisplayName: string | null;
|
|
259
|
+
userName: string | null;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Twitch raid event.
|
|
263
|
+
*/
|
|
264
|
+
interface TwitchEventJson_Raid extends CommonEventJson {
|
|
265
|
+
$platform: "twitch";
|
|
266
|
+
$type: "channel.raid";
|
|
267
|
+
fromBroadcasterUserId: string;
|
|
268
|
+
fromBroadcasterUserName: string;
|
|
269
|
+
fromBroadcasterUserDisplayName: string;
|
|
270
|
+
viewers: number;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Twitch channel point redemption event.
|
|
274
|
+
*/
|
|
275
|
+
interface TwitchEventJson_RedemptionAdd extends CommonEventJson {
|
|
276
|
+
$platform: "twitch";
|
|
277
|
+
$type: "channel.channel_points_custom_reward_redemption.add";
|
|
278
|
+
id: string;
|
|
279
|
+
rewardId: string;
|
|
280
|
+
rewardTitle: string;
|
|
281
|
+
rewardCost: number;
|
|
282
|
+
rewardPrompt: string;
|
|
283
|
+
userId: string;
|
|
284
|
+
userDisplayName: string;
|
|
285
|
+
userName: string;
|
|
286
|
+
userInput: string;
|
|
287
|
+
status: string;
|
|
288
|
+
redeemedAt: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Twitch stream online event.
|
|
292
|
+
*/
|
|
293
|
+
interface TwitchEventJson_StreamOnline extends CommonEventJson {
|
|
294
|
+
$platform: "twitch";
|
|
295
|
+
$type: "stream.online";
|
|
296
|
+
id: string;
|
|
297
|
+
type: string;
|
|
298
|
+
startedAt: string;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* All Twitch event types.
|
|
302
|
+
*/
|
|
303
|
+
type TwitchEventJson = TwitchEventJson_Follow | TwitchEventJson_Subscription | TwitchEventJson_SubscriptionGift | TwitchEventJson_Cheer | TwitchEventJson_Raid | TwitchEventJson_RedemptionAdd | TwitchEventJson_StreamOnline;
|
|
304
|
+
/**
|
|
305
|
+
* Kick follow event.
|
|
306
|
+
*/
|
|
307
|
+
interface KickEventJson_ChannelFollow extends CommonEventJson {
|
|
308
|
+
$platform: "kick";
|
|
309
|
+
$type: "channel.followed";
|
|
310
|
+
followersCount: number;
|
|
311
|
+
username: string;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Kick subscription new event.
|
|
315
|
+
*/
|
|
316
|
+
interface KickEventJson_ChannelSubscriptionNew extends CommonEventJson {
|
|
317
|
+
$platform: "kick";
|
|
318
|
+
$type: "channel.subscription.new";
|
|
319
|
+
months: number;
|
|
320
|
+
username: string;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Kick subscription renewal event.
|
|
324
|
+
*/
|
|
325
|
+
interface KickEventJson_ChannelSubscriptionRenewal extends CommonEventJson {
|
|
326
|
+
$platform: "kick";
|
|
327
|
+
$type: "channel.subscription.renewal";
|
|
328
|
+
months: number;
|
|
329
|
+
username: string;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Kick subscription gifts event.
|
|
333
|
+
*/
|
|
334
|
+
interface KickEventJson_ChannelSubscriptionGifts extends CommonEventJson {
|
|
335
|
+
$platform: "kick";
|
|
336
|
+
$type: "channel.subscription.gifts";
|
|
337
|
+
giftedUsernames: string[];
|
|
338
|
+
gifterUsername: string;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Kick livestream status updated event.
|
|
342
|
+
*/
|
|
343
|
+
interface KickEventJson_LivestreamStatusUpdated extends CommonEventJson {
|
|
344
|
+
$platform: "kick";
|
|
345
|
+
$type: "livestream.status.updated";
|
|
346
|
+
isLive: boolean;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* All Kick event types.
|
|
350
|
+
*/
|
|
351
|
+
type KickEventJson = KickEventJson_ChannelFollow | KickEventJson_ChannelSubscriptionNew | KickEventJson_ChannelSubscriptionRenewal | KickEventJson_ChannelSubscriptionGifts | KickEventJson_LivestreamStatusUpdated;
|
|
352
|
+
/**
|
|
353
|
+
* Stream event from Twitch or Kick.
|
|
354
|
+
*/
|
|
355
|
+
type StreamEventJson = TwitchEventJson | KickEventJson;
|
|
356
|
+
/**
|
|
357
|
+
* Viewer activity event.
|
|
358
|
+
*/
|
|
359
|
+
interface StreamViewerActivityJson {
|
|
360
|
+
id: string;
|
|
361
|
+
userId: string;
|
|
362
|
+
viewerId: string;
|
|
363
|
+
createdAt: DateIsoString;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Realtime chat message event.
|
|
367
|
+
*/
|
|
368
|
+
interface RealtimeEvent_StreamChatMessage {
|
|
369
|
+
kind: "StreamChatMessage";
|
|
370
|
+
payload: StreamChatMessageJson;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Realtime stream event.
|
|
374
|
+
*/
|
|
375
|
+
interface RealtimeEvent_StreamEvent {
|
|
376
|
+
kind: "StreamEvent";
|
|
377
|
+
payload: StreamEventJson;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Realtime viewer activity event.
|
|
381
|
+
*/
|
|
382
|
+
interface RealtimeEvent_StreamViewerActivity {
|
|
383
|
+
kind: "StreamViewerActivity";
|
|
384
|
+
payload: StreamViewerActivityJson;
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Realtime event from the Tentacle server.
|
|
388
|
+
*
|
|
389
|
+
* This is a discriminated union - use `event.kind` to determine the event type:
|
|
390
|
+
* - `StreamChatMessage`: Chat message from Twitch or Kick
|
|
391
|
+
* - `StreamEvent`: Stream event (follow, sub, raid, cheer, etc.)
|
|
392
|
+
* - `StreamViewerActivity`: Viewer activity update
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```typescript
|
|
396
|
+
* client.realtime.subscribe({
|
|
397
|
+
* onEvent: (event) => {
|
|
398
|
+
* switch (event.kind) {
|
|
399
|
+
* case 'StreamChatMessage':
|
|
400
|
+
* console.log(`[${event.payload.$platform}] ${event.payload.$text}`)
|
|
401
|
+
* break
|
|
402
|
+
* case 'StreamEvent':
|
|
403
|
+
* if (event.payload.$platform === 'twitch' && event.payload.$type === 'channel.follow') {
|
|
404
|
+
* console.log(`New follower: ${event.payload.userDisplayName}`)
|
|
405
|
+
* }
|
|
406
|
+
* break
|
|
407
|
+
* case 'StreamViewerActivity':
|
|
408
|
+
* console.log(`Viewer ${event.payload.viewerId} active`)
|
|
409
|
+
* break
|
|
410
|
+
* }
|
|
411
|
+
* }
|
|
412
|
+
* })
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
type RealtimeEvent = RealtimeEvent_StreamChatMessage | RealtimeEvent_StreamEvent | RealtimeEvent_StreamViewerActivity;
|
|
416
|
+
/**
|
|
417
|
+
* App.
|
|
418
|
+
*/
|
|
419
|
+
interface AppJson {
|
|
420
|
+
createdAt: DateIsoString;
|
|
421
|
+
id: string;
|
|
422
|
+
isActive: boolean;
|
|
423
|
+
isDefault: boolean;
|
|
424
|
+
name: string;
|
|
425
|
+
state: unknown;
|
|
426
|
+
updatedAt: DateIsoString;
|
|
427
|
+
userId: string;
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Viewer property type.
|
|
431
|
+
*/
|
|
432
|
+
type ViewerPropertyType = "number" | "bool" | "string";
|
|
433
|
+
/**
|
|
434
|
+
* Base viewer property fields.
|
|
435
|
+
*/
|
|
436
|
+
interface ViewerPropertyJsonBase {
|
|
437
|
+
id: string;
|
|
438
|
+
appId: string;
|
|
439
|
+
name: string;
|
|
440
|
+
viewerId: string;
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Number viewer property.
|
|
444
|
+
*/
|
|
445
|
+
interface ViewerPropertyJson_Number extends ViewerPropertyJsonBase {
|
|
446
|
+
type: "number";
|
|
447
|
+
value: number;
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Boolean viewer property.
|
|
451
|
+
*/
|
|
452
|
+
interface ViewerPropertyJson_Bool extends ViewerPropertyJsonBase {
|
|
453
|
+
type: "bool";
|
|
454
|
+
value: boolean;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* String viewer property.
|
|
458
|
+
*/
|
|
459
|
+
interface ViewerPropertyJson_String extends ViewerPropertyJsonBase {
|
|
460
|
+
type: "string";
|
|
461
|
+
value: string;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Viewer property.
|
|
465
|
+
*/
|
|
466
|
+
type ViewerPropertyJson = ViewerPropertyJson_Number | ViewerPropertyJson_Bool | ViewerPropertyJson_String;
|
|
467
|
+
/**
|
|
468
|
+
* Kick badge.
|
|
469
|
+
*/
|
|
470
|
+
interface KickBadge {
|
|
471
|
+
type: string;
|
|
472
|
+
text: string;
|
|
473
|
+
count?: number;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Viewer Kick data.
|
|
477
|
+
*/
|
|
478
|
+
interface ViewerKickJson {
|
|
479
|
+
createdAt: DateIsoString;
|
|
480
|
+
updatedAt: DateIsoString;
|
|
481
|
+
viewerId: string;
|
|
482
|
+
id: number;
|
|
483
|
+
username: string;
|
|
484
|
+
badges?: KickBadge[] | null;
|
|
485
|
+
isBroadcaster: boolean;
|
|
486
|
+
isModerator: boolean;
|
|
487
|
+
isOwner: boolean;
|
|
488
|
+
isStaff: boolean;
|
|
489
|
+
isSubscriber: boolean;
|
|
490
|
+
isVerified: boolean;
|
|
491
|
+
isVip: boolean;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Viewer Twitch data.
|
|
495
|
+
*/
|
|
496
|
+
interface ViewerTwitchJson {
|
|
497
|
+
createdAt: DateIsoString;
|
|
498
|
+
updatedAt: DateIsoString;
|
|
499
|
+
viewerId: string;
|
|
500
|
+
id: string;
|
|
501
|
+
username: string;
|
|
502
|
+
displayName: string;
|
|
503
|
+
profileImageUrl?: string | null;
|
|
504
|
+
isBroadcaster: boolean;
|
|
505
|
+
isFounder: boolean;
|
|
506
|
+
isMod: boolean;
|
|
507
|
+
isSubscriber: boolean;
|
|
508
|
+
isVip: boolean;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Viewer (mini).
|
|
512
|
+
*/
|
|
513
|
+
interface ViewerMiniJson {
|
|
514
|
+
id: string;
|
|
515
|
+
createdAt: DateIsoString;
|
|
516
|
+
updatedAt: DateIsoString;
|
|
517
|
+
kick?: ViewerKickJson | null;
|
|
518
|
+
twitch?: ViewerTwitchJson | null;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Viewer (full).
|
|
522
|
+
*/
|
|
523
|
+
interface ViewerJson extends ViewerMiniJson {
|
|
524
|
+
isMock?: boolean;
|
|
525
|
+
properties?: Record<string, ViewerPropertyJson> | null;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Viewer action.
|
|
529
|
+
*/
|
|
530
|
+
interface ViewerActionJson {
|
|
531
|
+
id: string;
|
|
532
|
+
name: string;
|
|
533
|
+
data: unknown;
|
|
534
|
+
appId: string;
|
|
535
|
+
viewerId: string;
|
|
536
|
+
createdAt: DateIsoString;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Subscription unlock.
|
|
540
|
+
*/
|
|
541
|
+
interface SubUnlock {
|
|
542
|
+
subs: number;
|
|
543
|
+
title: string;
|
|
544
|
+
reached: boolean;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Subscription stats.
|
|
548
|
+
*/
|
|
549
|
+
interface SubathonStats_Subscriptions {
|
|
550
|
+
count: number;
|
|
551
|
+
goal: number;
|
|
552
|
+
goalProgress: number;
|
|
553
|
+
newestSubViewers: ViewerJson[];
|
|
554
|
+
unlocks: SubUnlock[];
|
|
555
|
+
nextUnlock: {
|
|
556
|
+
subs: number;
|
|
557
|
+
title: string;
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Gifted subscription unlock.
|
|
562
|
+
*/
|
|
563
|
+
interface GiftedSubUnlock {
|
|
564
|
+
giftedSubs: number;
|
|
565
|
+
title: string;
|
|
566
|
+
reached: boolean;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Gifted subscription stats.
|
|
570
|
+
*/
|
|
571
|
+
interface SubathonStats_GiftedSubscriptions {
|
|
572
|
+
count: number;
|
|
573
|
+
goal: number;
|
|
574
|
+
goalProgress: number;
|
|
575
|
+
latestGiftedSub: unknown;
|
|
576
|
+
topGifterViewers: ViewerJson[];
|
|
577
|
+
viewerIdToTotal: Record<string, number>;
|
|
578
|
+
unlocks: GiftedSubUnlock[];
|
|
579
|
+
nextUnlock: {
|
|
580
|
+
giftedSubs: number;
|
|
581
|
+
title: string;
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Donation unlock.
|
|
586
|
+
*/
|
|
587
|
+
interface DonationUnlock {
|
|
588
|
+
dollars: number;
|
|
589
|
+
dollarsText: string;
|
|
590
|
+
title: string;
|
|
591
|
+
reached: boolean;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Donation stats.
|
|
595
|
+
*/
|
|
596
|
+
interface SubathonStats_Donations {
|
|
597
|
+
dollars: number;
|
|
598
|
+
goal: number;
|
|
599
|
+
goalProgress: number;
|
|
600
|
+
latestCheer: unknown;
|
|
601
|
+
topDonorViewers: ViewerJson[];
|
|
602
|
+
viewerIdToTotalBits: Record<string, number>;
|
|
603
|
+
unlocks: DonationUnlock[];
|
|
604
|
+
nextUnlock: {
|
|
605
|
+
dollars: number;
|
|
606
|
+
dollarsText: string;
|
|
607
|
+
title: string;
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Order direction for pagination.
|
|
612
|
+
*/
|
|
613
|
+
type OrderDirection = "asc" | "desc";
|
|
614
|
+
/**
|
|
615
|
+
* Viewers by property response.
|
|
616
|
+
*/
|
|
617
|
+
interface ViewersByPropertyOutput {
|
|
618
|
+
property: {
|
|
619
|
+
name: string;
|
|
620
|
+
type: ViewerPropertyType;
|
|
621
|
+
appId: string;
|
|
622
|
+
};
|
|
623
|
+
viewers: Array<ViewerMiniJson & {
|
|
624
|
+
properties: Record<string, ViewerPropertyJson>;
|
|
625
|
+
}>;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* Realtime subscription utilities for the Tentacle SDK.
|
|
630
|
+
* Uses Server-Sent Events (SSE) via tRPC to receive live updates from Twitch and Kick.
|
|
631
|
+
*
|
|
632
|
+
* @module realtime
|
|
633
|
+
*/
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Options for subscribing to realtime events.
|
|
637
|
+
*/
|
|
638
|
+
interface RealtimeSubscribeOptions {
|
|
639
|
+
/**
|
|
640
|
+
* Callback invoked when a realtime event is received.
|
|
641
|
+
* Events include chat messages, stream events (follows, subs, raids, etc.),
|
|
642
|
+
* and viewer activity.
|
|
643
|
+
*
|
|
644
|
+
* @param event - The realtime event with `kind` discriminator and `payload`.
|
|
645
|
+
*
|
|
646
|
+
* @example
|
|
647
|
+
* ```typescript
|
|
648
|
+
* onEvent: (event) => {
|
|
649
|
+
* switch (event.kind) {
|
|
650
|
+
* case 'StreamChatMessage':
|
|
651
|
+
* console.log(`${event.payload.userInfo?.displayName}: ${event.payload.$text}`)
|
|
652
|
+
* break
|
|
653
|
+
* case 'StreamEvent':
|
|
654
|
+
* if (event.payload.$platform === 'twitch' && event.payload.$type === 'channel.follow') {
|
|
655
|
+
* console.log(`New follower: ${event.payload.userDisplayName}`)
|
|
656
|
+
* }
|
|
657
|
+
* break
|
|
658
|
+
* }
|
|
659
|
+
* }
|
|
660
|
+
* ```
|
|
661
|
+
*/
|
|
662
|
+
onEvent: (event: RealtimeEvent) => void;
|
|
663
|
+
/**
|
|
664
|
+
* Callback invoked when an error occurs.
|
|
665
|
+
* The subscription will automatically attempt to reconnect.
|
|
666
|
+
*
|
|
667
|
+
* @param error - The error that occurred.
|
|
668
|
+
*/
|
|
669
|
+
onError?: (error: Error) => void;
|
|
670
|
+
/**
|
|
671
|
+
* Callback invoked when the connection is established.
|
|
672
|
+
*/
|
|
673
|
+
onOpen?: () => void;
|
|
674
|
+
/**
|
|
675
|
+
* Callback invoked when the connection is closed.
|
|
676
|
+
*/
|
|
677
|
+
onClose?: () => void;
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Function to unsubscribe from realtime events.
|
|
681
|
+
* Call this to close the SSE connection and stop receiving events.
|
|
682
|
+
*
|
|
683
|
+
* @example
|
|
684
|
+
* ```typescript
|
|
685
|
+
* const unsubscribe = client.realtime.subscribe({ onEvent: ... })
|
|
686
|
+
* // Later, when done:
|
|
687
|
+
* unsubscribe()
|
|
688
|
+
* ```
|
|
689
|
+
*/
|
|
690
|
+
type UnsubscribeFunction = () => void;
|
|
691
|
+
/**
|
|
692
|
+
* Realtime API for subscribing to Twitch and Kick events.
|
|
693
|
+
*/
|
|
694
|
+
declare class RealtimeApi {
|
|
695
|
+
private readonly baseUrl;
|
|
696
|
+
private readonly accessToken?;
|
|
697
|
+
constructor(baseUrl: string, accessToken?: string);
|
|
698
|
+
/**
|
|
699
|
+
* Subscribe to realtime events from Twitch and Kick.
|
|
700
|
+
*
|
|
701
|
+
* This establishes a Server-Sent Events (SSE) connection to receive live updates:
|
|
702
|
+
* - **StreamChatMessage**: Chat messages from Twitch or Kick
|
|
703
|
+
* - **StreamEvent**: Events like follows, subscriptions, raids, cheers
|
|
704
|
+
* - **StreamViewerActivity**: Viewer activity updates
|
|
705
|
+
*
|
|
706
|
+
* Each event includes viewer data (when available) via the `$viewerId` field
|
|
707
|
+
* and platform-specific user info.
|
|
708
|
+
*
|
|
709
|
+
* @param options - Subscription options with event callbacks
|
|
710
|
+
* @returns Function to unsubscribe and close the connection
|
|
711
|
+
*
|
|
712
|
+
* @example
|
|
713
|
+
* ```typescript
|
|
714
|
+
* const unsubscribe = client.realtime.subscribe({
|
|
715
|
+
* onEvent: (event) => {
|
|
716
|
+
* switch (event.kind) {
|
|
717
|
+
* case 'StreamChatMessage':
|
|
718
|
+
* // Chat message from Twitch or Kick
|
|
719
|
+
* const msg = event.payload
|
|
720
|
+
* console.log(`[${msg.$platform}] ${msg.$text}`)
|
|
721
|
+
* console.log(`Viewer ID: ${msg.$viewerId}`)
|
|
722
|
+
* break
|
|
723
|
+
*
|
|
724
|
+
* case 'StreamEvent':
|
|
725
|
+
* // Stream event (follow, sub, raid, etc.)
|
|
726
|
+
* const evt = event.payload
|
|
727
|
+
* if (evt.$platform === 'twitch') {
|
|
728
|
+
* switch (evt.$type) {
|
|
729
|
+
* case 'channel.follow':
|
|
730
|
+
* console.log(`New Twitch follower: ${evt.userDisplayName}`)
|
|
731
|
+
* break
|
|
732
|
+
* case 'channel.subscribe':
|
|
733
|
+
* console.log(`New Twitch sub: ${evt.userDisplayName}`)
|
|
734
|
+
* break
|
|
735
|
+
* case 'channel.raid':
|
|
736
|
+
* console.log(`Raid from ${evt.fromBroadcasterUserName} with ${evt.viewers} viewers`)
|
|
737
|
+
* break
|
|
738
|
+
* }
|
|
739
|
+
* } else if (evt.$platform === 'kick') {
|
|
740
|
+
* switch (evt.$type) {
|
|
741
|
+
* case 'channel.followed':
|
|
742
|
+
* console.log(`New Kick follower: ${evt.username}`)
|
|
743
|
+
* break
|
|
744
|
+
* case 'channel.subscription.new':
|
|
745
|
+
* console.log(`New Kick sub: ${evt.username}`)
|
|
746
|
+
* break
|
|
747
|
+
* }
|
|
748
|
+
* }
|
|
749
|
+
* break
|
|
750
|
+
*
|
|
751
|
+
* case 'StreamViewerActivity':
|
|
752
|
+
* console.log(`Viewer activity: ${event.payload.viewerId}`)
|
|
753
|
+
* break
|
|
754
|
+
* }
|
|
755
|
+
* },
|
|
756
|
+
* onError: (error) => console.error('Connection error:', error),
|
|
757
|
+
* onOpen: () => console.log('Connected!'),
|
|
758
|
+
* onClose: () => console.log('Disconnected'),
|
|
759
|
+
* })
|
|
760
|
+
*
|
|
761
|
+
* // When done, unsubscribe:
|
|
762
|
+
* unsubscribe()
|
|
763
|
+
* ```
|
|
764
|
+
*
|
|
765
|
+
* @throws {Error} If no access token is configured
|
|
766
|
+
*/
|
|
767
|
+
subscribe(options: RealtimeSubscribeOptions): UnsubscribeFunction;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Credential store interface for persisting access tokens.
|
|
772
|
+
*
|
|
773
|
+
* Implement this interface to provide custom credential storage.
|
|
774
|
+
* The SDK includes a FileCredentialStore for Node.js environments.
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* ```typescript
|
|
778
|
+
* // Custom credential store for Unreal Engine (PuerTS)
|
|
779
|
+
* class UnrealCredentialStore implements CredentialStore {
|
|
780
|
+
* async getAccessToken(): Promise<string | null> {
|
|
781
|
+
* return UE.SaveGame.LoadString("TentacleAccessToken")
|
|
782
|
+
* }
|
|
783
|
+
*
|
|
784
|
+
* async setAccessToken(token: string): Promise<void> {
|
|
785
|
+
* UE.SaveGame.SaveString("TentacleAccessToken", token)
|
|
786
|
+
* }
|
|
787
|
+
*
|
|
788
|
+
* async clearAccessToken(): Promise<void> {
|
|
789
|
+
* UE.SaveGame.Delete("TentacleAccessToken")
|
|
790
|
+
* }
|
|
791
|
+
* }
|
|
792
|
+
* ```
|
|
793
|
+
*
|
|
794
|
+
* @module auth/credential-store
|
|
795
|
+
*/
|
|
796
|
+
/**
|
|
797
|
+
* Interface for persisting access tokens.
|
|
798
|
+
*
|
|
799
|
+
* Implementations should securely store tokens in a platform-appropriate way.
|
|
800
|
+
* For Node.js, use FileCredentialStore. For other platforms (Unity, Unreal),
|
|
801
|
+
* implement this interface using the platform's native storage APIs.
|
|
802
|
+
*/
|
|
803
|
+
interface CredentialStore {
|
|
804
|
+
/**
|
|
805
|
+
* Retrieves the stored access token.
|
|
806
|
+
*
|
|
807
|
+
* @returns The access token, or null if none is stored.
|
|
808
|
+
*/
|
|
809
|
+
getAccessToken(): Promise<string | null>;
|
|
810
|
+
/**
|
|
811
|
+
* Stores an access token.
|
|
812
|
+
*
|
|
813
|
+
* @param token - The access token to store.
|
|
814
|
+
*/
|
|
815
|
+
setAccessToken(token: string): Promise<void>;
|
|
816
|
+
/**
|
|
817
|
+
* Removes the stored access token.
|
|
818
|
+
*/
|
|
819
|
+
clearAccessToken(): Promise<void>;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Device authorization flow for the Tentacle SDK.
|
|
824
|
+
*
|
|
825
|
+
* Implements OAuth 2.0 Device Authorization Grant (RFC 8628) for
|
|
826
|
+
* authenticating devices that cannot easily display a web browser.
|
|
827
|
+
*
|
|
828
|
+
* @module auth/device-auth
|
|
829
|
+
*/
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Result of initiating device authorization.
|
|
833
|
+
*/
|
|
834
|
+
interface DeviceAuthInitResult {
|
|
835
|
+
/** Code used by SDK to poll for authorization status. */
|
|
836
|
+
deviceCode: string;
|
|
837
|
+
/** User-friendly code displayed to the user (e.g., "ABCD-1234"). */
|
|
838
|
+
userCode: string;
|
|
839
|
+
/** URL where user should navigate to enter the code. */
|
|
840
|
+
verificationUrl: string;
|
|
841
|
+
/** Seconds until this authorization request expires. */
|
|
842
|
+
expiresIn: number;
|
|
843
|
+
/** Recommended polling interval in seconds. */
|
|
844
|
+
interval: number;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Result of polling device authorization status.
|
|
848
|
+
*/
|
|
849
|
+
interface DeviceAuthPollResult {
|
|
850
|
+
/** Current status of the authorization request. */
|
|
851
|
+
status: "pending" | "approved" | "denied" | "expired";
|
|
852
|
+
/** Access token (only present when status is "approved"). */
|
|
853
|
+
accessToken?: string;
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Options for the device authorization flow.
|
|
857
|
+
*/
|
|
858
|
+
interface DeviceAuthOptions {
|
|
859
|
+
/** Optional client information displayed to the user during approval. */
|
|
860
|
+
clientInfo?: string;
|
|
861
|
+
/**
|
|
862
|
+
* Callback invoked when user authorization is required.
|
|
863
|
+
* Display the verification URL and code to the user.
|
|
864
|
+
*/
|
|
865
|
+
onAuthRequired: (params: {
|
|
866
|
+
verificationUrl: string;
|
|
867
|
+
userCode: string;
|
|
868
|
+
}) => void;
|
|
869
|
+
/**
|
|
870
|
+
* Optional callback invoked when authorization is approved.
|
|
871
|
+
*/
|
|
872
|
+
onAuthApproved?: () => void;
|
|
873
|
+
/**
|
|
874
|
+
* Optional callback invoked when authorization is denied.
|
|
875
|
+
*/
|
|
876
|
+
onAuthDenied?: () => void;
|
|
877
|
+
/**
|
|
878
|
+
* Optional callback invoked when authorization times out.
|
|
879
|
+
*/
|
|
880
|
+
onAuthTimeout?: () => void;
|
|
881
|
+
/**
|
|
882
|
+
* Timeout in milliseconds for the polling loop.
|
|
883
|
+
* Defaults to 600000 (10 minutes).
|
|
884
|
+
*/
|
|
885
|
+
pollTimeout?: number;
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Device authorization flow implementation.
|
|
889
|
+
*
|
|
890
|
+
* @example
|
|
891
|
+
* ```typescript
|
|
892
|
+
* const flow = new DeviceAuthFlow("https://api.tentacle.live")
|
|
893
|
+
*
|
|
894
|
+
* // Initiate the flow
|
|
895
|
+
* const { deviceCode, userCode, verificationUrl } = await flow.initiate({
|
|
896
|
+
* clientInfo: "My Game v1.0",
|
|
897
|
+
* })
|
|
898
|
+
*
|
|
899
|
+
* // Display to user
|
|
900
|
+
* console.log(`Visit ${verificationUrl}`)
|
|
901
|
+
* console.log(`Enter code: ${userCode}`)
|
|
902
|
+
*
|
|
903
|
+
* // Poll until approved
|
|
904
|
+
* const result = await flow.pollUntilComplete(deviceCode, 5000)
|
|
905
|
+
* if (result.status === "approved") {
|
|
906
|
+
* console.log(`Authenticated! Token: ${result.accessToken}`)
|
|
907
|
+
* }
|
|
908
|
+
* ```
|
|
909
|
+
*/
|
|
910
|
+
declare class DeviceAuthFlow {
|
|
911
|
+
private readonly baseUrl;
|
|
912
|
+
constructor(baseUrl: string);
|
|
913
|
+
/**
|
|
914
|
+
* Initiates a device authorization request.
|
|
915
|
+
*
|
|
916
|
+
* @param options - Options for the request.
|
|
917
|
+
* @returns Device and user codes for authorization.
|
|
918
|
+
*/
|
|
919
|
+
initiate(options?: {
|
|
920
|
+
clientInfo?: string;
|
|
921
|
+
}): Promise<DeviceAuthInitResult>;
|
|
922
|
+
/**
|
|
923
|
+
* Polls for the current authorization status.
|
|
924
|
+
*
|
|
925
|
+
* @param deviceCode - The device code from initiate().
|
|
926
|
+
* @returns Current authorization status.
|
|
927
|
+
*/
|
|
928
|
+
poll(deviceCode: string): Promise<DeviceAuthPollResult>;
|
|
929
|
+
/**
|
|
930
|
+
* Polls until authorization is complete (approved, denied, or expired).
|
|
931
|
+
*
|
|
932
|
+
* @param deviceCode - The device code from initiate().
|
|
933
|
+
* @param intervalMs - Polling interval in milliseconds.
|
|
934
|
+
* @param timeoutMs - Maximum time to wait in milliseconds.
|
|
935
|
+
* @returns Final authorization result.
|
|
936
|
+
*/
|
|
937
|
+
pollUntilComplete(deviceCode: string, intervalMs?: number, timeoutMs?: number): Promise<DeviceAuthPollResult>;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* Main Tentacle SDK client.
|
|
942
|
+
*
|
|
943
|
+
* @module client
|
|
944
|
+
*/
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Configuration options for the TentacleClient.
|
|
948
|
+
*/
|
|
949
|
+
interface TentacleClientConfig {
|
|
950
|
+
/**
|
|
951
|
+
* Base URL of the Tentacle API.
|
|
952
|
+
*
|
|
953
|
+
* @example "https://api.tentacle.live"
|
|
954
|
+
*/
|
|
955
|
+
baseUrl: string;
|
|
956
|
+
/**
|
|
957
|
+
* Access token for authentication.
|
|
958
|
+
* Required for most API operations.
|
|
959
|
+
*
|
|
960
|
+
* You can obtain an access token from the Tentacle dashboard.
|
|
961
|
+
*
|
|
962
|
+
* @example "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
963
|
+
*/
|
|
964
|
+
accessToken?: string;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Options for creating a TentacleClient with automatic authentication.
|
|
968
|
+
*/
|
|
969
|
+
interface TentacleClientCreateOptions {
|
|
970
|
+
/**
|
|
971
|
+
* Base URL of the Tentacle API.
|
|
972
|
+
*
|
|
973
|
+
* @example "https://api.tentacle.live"
|
|
974
|
+
*/
|
|
975
|
+
baseUrl: string;
|
|
976
|
+
/**
|
|
977
|
+
* Credential store for persisting access tokens.
|
|
978
|
+
* The SDK will check for a cached token and use it if valid.
|
|
979
|
+
*/
|
|
980
|
+
credentialStore: CredentialStore;
|
|
981
|
+
/**
|
|
982
|
+
* Options for the device authorization flow.
|
|
983
|
+
* Used when no valid cached token is available.
|
|
984
|
+
*/
|
|
985
|
+
deviceAuthOptions: DeviceAuthOptions;
|
|
986
|
+
}
|
|
987
|
+
/**
|
|
988
|
+
* Apps API for managing apps and viewer properties.
|
|
989
|
+
*/
|
|
990
|
+
declare class AppsApi {
|
|
991
|
+
private readonly http;
|
|
992
|
+
constructor(http: HttpClient);
|
|
993
|
+
/**
|
|
994
|
+
* Create a new app.
|
|
995
|
+
*
|
|
996
|
+
* @param options - App creation options
|
|
997
|
+
* @param options.name - Name of the app
|
|
998
|
+
* @returns The created app
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```typescript
|
|
1002
|
+
* const { app } = await client.apps.create({ name: "My Game" })
|
|
1003
|
+
* console.log(`Created app: ${app.id}`)
|
|
1004
|
+
* ```
|
|
1005
|
+
*/
|
|
1006
|
+
create(options: {
|
|
1007
|
+
name: string;
|
|
1008
|
+
}): Promise<{
|
|
1009
|
+
app: AppJson;
|
|
1010
|
+
}>;
|
|
1011
|
+
/**
|
|
1012
|
+
* List all apps for the current user.
|
|
1013
|
+
*
|
|
1014
|
+
* @returns Array of apps
|
|
1015
|
+
*
|
|
1016
|
+
* @example
|
|
1017
|
+
* ```typescript
|
|
1018
|
+
* const { apps } = await client.apps.list()
|
|
1019
|
+
* for (const app of apps) {
|
|
1020
|
+
* console.log(`${app.name}: ${app.id}`)
|
|
1021
|
+
* }
|
|
1022
|
+
* ```
|
|
1023
|
+
*/
|
|
1024
|
+
list(): Promise<{
|
|
1025
|
+
apps: AppJson[];
|
|
1026
|
+
}>;
|
|
1027
|
+
/**
|
|
1028
|
+
* Get an app by name.
|
|
1029
|
+
*
|
|
1030
|
+
* @param options - Query options
|
|
1031
|
+
* @param options.name - Name of the app
|
|
1032
|
+
* @returns The app
|
|
1033
|
+
*
|
|
1034
|
+
* @example
|
|
1035
|
+
* ```typescript
|
|
1036
|
+
* const { app } = await client.apps.getByName({ name: "My Game" })
|
|
1037
|
+
* console.log(`App ID: ${app.id}`)
|
|
1038
|
+
* ```
|
|
1039
|
+
*/
|
|
1040
|
+
getByName(options: {
|
|
1041
|
+
name: string;
|
|
1042
|
+
}): Promise<{
|
|
1043
|
+
app: AppJson;
|
|
1044
|
+
}>;
|
|
1045
|
+
/**
|
|
1046
|
+
* List apps for a viewer.
|
|
1047
|
+
* Requires viewer authentication.
|
|
1048
|
+
*
|
|
1049
|
+
* @param options - Query options
|
|
1050
|
+
* @param options.where - Filter options
|
|
1051
|
+
* @param options.where.isActive - Filter by active status
|
|
1052
|
+
* @returns Array of apps
|
|
1053
|
+
*
|
|
1054
|
+
* @example
|
|
1055
|
+
* ```typescript
|
|
1056
|
+
* const { apps } = await client.apps.listForViewer({ where: { isActive: true } })
|
|
1057
|
+
* ```
|
|
1058
|
+
*/
|
|
1059
|
+
listForViewer(options?: {
|
|
1060
|
+
where?: {
|
|
1061
|
+
isActive?: boolean;
|
|
1062
|
+
};
|
|
1063
|
+
}): Promise<{
|
|
1064
|
+
apps: AppJson[];
|
|
1065
|
+
}>;
|
|
1066
|
+
/**
|
|
1067
|
+
* Create or update viewer properties.
|
|
1068
|
+
*
|
|
1069
|
+
* @param properties - Array of viewer properties to create/update
|
|
1070
|
+
* @returns Success status
|
|
1071
|
+
*
|
|
1072
|
+
* @example
|
|
1073
|
+
* ```typescript
|
|
1074
|
+
* await client.apps.createViewerProperties([
|
|
1075
|
+
* { id: "prop1", appId: "app1", viewerId: "v1", name: "score", type: "number", value: 100 },
|
|
1076
|
+
* ])
|
|
1077
|
+
* ```
|
|
1078
|
+
*/
|
|
1079
|
+
createViewerProperties(properties: ViewerPropertyJson[]): Promise<{
|
|
1080
|
+
success: boolean;
|
|
1081
|
+
}>;
|
|
1082
|
+
/**
|
|
1083
|
+
* Update viewer properties.
|
|
1084
|
+
*
|
|
1085
|
+
* @param properties - Array of viewer properties to update
|
|
1086
|
+
* @returns Success status
|
|
1087
|
+
*
|
|
1088
|
+
* @example
|
|
1089
|
+
* ```typescript
|
|
1090
|
+
* await client.apps.updateViewerProperties([
|
|
1091
|
+
* { id: "prop1", appId: "app1", viewerId: "v1", name: "score", type: "number", value: 150 },
|
|
1092
|
+
* ])
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
updateViewerProperties(properties: ViewerPropertyJson[]): Promise<{
|
|
1096
|
+
success: boolean;
|
|
1097
|
+
}>;
|
|
1098
|
+
/**
|
|
1099
|
+
* Get viewers by property.
|
|
1100
|
+
*
|
|
1101
|
+
* @param options - Query options
|
|
1102
|
+
* @param options.appId - App ID
|
|
1103
|
+
* @param options.propertyName - Property name to query
|
|
1104
|
+
* @param options.propertyType - Property type
|
|
1105
|
+
* @param options.orderDirection - Order direction (asc/desc)
|
|
1106
|
+
* @param options.take - Number of results (1-1000, default 20)
|
|
1107
|
+
* @returns Viewers with the specified property
|
|
1108
|
+
*
|
|
1109
|
+
* @example
|
|
1110
|
+
* ```typescript
|
|
1111
|
+
* const result = await client.apps.getViewersByProperty({
|
|
1112
|
+
* appId: "app1",
|
|
1113
|
+
* propertyName: "score",
|
|
1114
|
+
* propertyType: "number",
|
|
1115
|
+
* orderDirection: "desc",
|
|
1116
|
+
* take: 10,
|
|
1117
|
+
* })
|
|
1118
|
+
* for (const viewer of result.viewers) {
|
|
1119
|
+
* console.log(`${viewer.twitch?.displayName}: ${viewer.properties.score.value}`)
|
|
1120
|
+
* }
|
|
1121
|
+
* ```
|
|
1122
|
+
*/
|
|
1123
|
+
getViewersByProperty(options: {
|
|
1124
|
+
appId: string;
|
|
1125
|
+
propertyName: string;
|
|
1126
|
+
propertyType: ViewerPropertyType;
|
|
1127
|
+
orderDirection?: OrderDirection;
|
|
1128
|
+
take?: number;
|
|
1129
|
+
}): Promise<ViewersByPropertyOutput>;
|
|
1130
|
+
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Stream API for accessing chat messages and events.
|
|
1133
|
+
*/
|
|
1134
|
+
declare class StreamApi {
|
|
1135
|
+
private readonly http;
|
|
1136
|
+
constructor(http: HttpClient);
|
|
1137
|
+
/**
|
|
1138
|
+
* Get the latest chat messages from Twitch and Kick.
|
|
1139
|
+
*
|
|
1140
|
+
* @param options - Query options
|
|
1141
|
+
* @param options.take - Maximum number of messages to return (default: 50)
|
|
1142
|
+
* @param options.isCommand - Filter to only command messages (starting with !)
|
|
1143
|
+
* @returns Array of chat messages from both platforms
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```typescript
|
|
1147
|
+
* // Get latest 50 chat messages
|
|
1148
|
+
* const messages = await client.stream.getChatMessages()
|
|
1149
|
+
*
|
|
1150
|
+
* // Get latest 10 command messages
|
|
1151
|
+
* const commands = await client.stream.getChatMessages({
|
|
1152
|
+
* take: 10,
|
|
1153
|
+
* isCommand: true,
|
|
1154
|
+
* })
|
|
1155
|
+
*
|
|
1156
|
+
* for (const msg of messages) {
|
|
1157
|
+
* console.log(`[${msg.$platform}] ${msg.$text}`)
|
|
1158
|
+
* }
|
|
1159
|
+
* ```
|
|
1160
|
+
*/
|
|
1161
|
+
getChatMessages(options?: {
|
|
1162
|
+
take?: number;
|
|
1163
|
+
isCommand?: boolean;
|
|
1164
|
+
}): Promise<StreamChatMessageJson[]>;
|
|
1165
|
+
/**
|
|
1166
|
+
* Get the latest stream events from Twitch and Kick.
|
|
1167
|
+
*
|
|
1168
|
+
* Events include follows, subscriptions, raids, cheers, and more.
|
|
1169
|
+
*
|
|
1170
|
+
* @param options - Query options
|
|
1171
|
+
* @param options.take - Maximum number of events to return (default: 50)
|
|
1172
|
+
* @returns Array of stream events from both platforms
|
|
1173
|
+
*
|
|
1174
|
+
* @example
|
|
1175
|
+
* ```typescript
|
|
1176
|
+
* const events = await client.stream.getEvents({ take: 20 })
|
|
1177
|
+
*
|
|
1178
|
+
* for (const event of events) {
|
|
1179
|
+
* if (event.$platform === 'twitch') {
|
|
1180
|
+
* switch (event.$type) {
|
|
1181
|
+
* case 'channel.follow':
|
|
1182
|
+
* console.log(`New follower: ${event.userDisplayName}`)
|
|
1183
|
+
* break
|
|
1184
|
+
* case 'channel.subscribe':
|
|
1185
|
+
* console.log(`New subscriber: ${event.userDisplayName}`)
|
|
1186
|
+
* break
|
|
1187
|
+
* }
|
|
1188
|
+
* }
|
|
1189
|
+
* }
|
|
1190
|
+
* ```
|
|
1191
|
+
*/
|
|
1192
|
+
getEvents(options?: {
|
|
1193
|
+
take?: number;
|
|
1194
|
+
}): Promise<StreamEventJson[]>;
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Subathon API for accessing subathon statistics.
|
|
1198
|
+
*/
|
|
1199
|
+
declare class SubathonApi {
|
|
1200
|
+
private readonly http;
|
|
1201
|
+
constructor(http: HttpClient);
|
|
1202
|
+
/**
|
|
1203
|
+
* Get subscription stats.
|
|
1204
|
+
*
|
|
1205
|
+
* @returns Subscription statistics
|
|
1206
|
+
*
|
|
1207
|
+
* @example
|
|
1208
|
+
* ```typescript
|
|
1209
|
+
* const stats = await client.subathonStats.getSubs()
|
|
1210
|
+
* console.log(`Subs: ${stats.count}/${stats.goal}`)
|
|
1211
|
+
* ```
|
|
1212
|
+
*/
|
|
1213
|
+
getSubs(): Promise<SubathonStats_Subscriptions>;
|
|
1214
|
+
/**
|
|
1215
|
+
* Get gifted subscription stats.
|
|
1216
|
+
*
|
|
1217
|
+
* @returns Gifted subscription statistics
|
|
1218
|
+
*
|
|
1219
|
+
* @example
|
|
1220
|
+
* ```typescript
|
|
1221
|
+
* const stats = await client.subathonStats.getGiftedSubs()
|
|
1222
|
+
* console.log(`Gifted subs: ${stats.count}`)
|
|
1223
|
+
* ```
|
|
1224
|
+
*/
|
|
1225
|
+
getGiftedSubs(): Promise<SubathonStats_GiftedSubscriptions>;
|
|
1226
|
+
/**
|
|
1227
|
+
* Get donation stats.
|
|
1228
|
+
*
|
|
1229
|
+
* @returns Donation statistics
|
|
1230
|
+
*
|
|
1231
|
+
* @example
|
|
1232
|
+
* ```typescript
|
|
1233
|
+
* const stats = await client.subathonStats.getDonations()
|
|
1234
|
+
* console.log(`Donations: $${stats.dollars}`)
|
|
1235
|
+
* ```
|
|
1236
|
+
*/
|
|
1237
|
+
getDonations(): Promise<SubathonStats_Donations>;
|
|
1238
|
+
/**
|
|
1239
|
+
* Get subscription stats for overlay.
|
|
1240
|
+
* Public endpoint - no authentication required.
|
|
1241
|
+
*
|
|
1242
|
+
* @param options - Query options
|
|
1243
|
+
* @param options.email - User email
|
|
1244
|
+
* @returns Subscription statistics or null if user not found
|
|
1245
|
+
*
|
|
1246
|
+
* @example
|
|
1247
|
+
* ```typescript
|
|
1248
|
+
* const stats = await client.subathonStats.getOverlaySubs({ email: "user@example.com" })
|
|
1249
|
+
* if (stats) {
|
|
1250
|
+
* console.log(`Subs: ${stats.count}`)
|
|
1251
|
+
* }
|
|
1252
|
+
* ```
|
|
1253
|
+
*/
|
|
1254
|
+
getOverlaySubs(options: {
|
|
1255
|
+
email: string;
|
|
1256
|
+
}): Promise<SubathonStats_Subscriptions | null>;
|
|
1257
|
+
/**
|
|
1258
|
+
* Get gifted subscription stats for overlay.
|
|
1259
|
+
* Public endpoint - no authentication required.
|
|
1260
|
+
*
|
|
1261
|
+
* @param options - Query options
|
|
1262
|
+
* @param options.email - User email
|
|
1263
|
+
* @returns Gifted subscription statistics or null if user not found
|
|
1264
|
+
*
|
|
1265
|
+
* @example
|
|
1266
|
+
* ```typescript
|
|
1267
|
+
* const stats = await client.subathonStats.getOverlayGiftedSubs({ email: "user@example.com" })
|
|
1268
|
+
* ```
|
|
1269
|
+
*/
|
|
1270
|
+
getOverlayGiftedSubs(options: {
|
|
1271
|
+
email: string;
|
|
1272
|
+
}): Promise<SubathonStats_GiftedSubscriptions | null>;
|
|
1273
|
+
/**
|
|
1274
|
+
* Get donation stats for overlay.
|
|
1275
|
+
* Public endpoint - no authentication required.
|
|
1276
|
+
*
|
|
1277
|
+
* @param options - Query options
|
|
1278
|
+
* @param options.email - User email
|
|
1279
|
+
* @returns Donation statistics or null if user not found
|
|
1280
|
+
*
|
|
1281
|
+
* @example
|
|
1282
|
+
* ```typescript
|
|
1283
|
+
* const stats = await client.subathonStats.getOverlayDonations({ email: "user@example.com" })
|
|
1284
|
+
* ```
|
|
1285
|
+
*/
|
|
1286
|
+
getOverlayDonations(options: {
|
|
1287
|
+
email: string;
|
|
1288
|
+
}): Promise<SubathonStats_Donations | null>;
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Viewer API for accessing viewer data.
|
|
1292
|
+
*/
|
|
1293
|
+
declare class ViewerApi {
|
|
1294
|
+
private readonly http;
|
|
1295
|
+
constructor(http: HttpClient);
|
|
1296
|
+
/**
|
|
1297
|
+
* Create a viewer action.
|
|
1298
|
+
* Requires viewer authentication.
|
|
1299
|
+
*
|
|
1300
|
+
* @param options - Action options
|
|
1301
|
+
* @param options.name - Action name
|
|
1302
|
+
* @param options.data - Action data
|
|
1303
|
+
* @param options.appId - App ID
|
|
1304
|
+
* @returns Success status
|
|
1305
|
+
*
|
|
1306
|
+
* @example
|
|
1307
|
+
* ```typescript
|
|
1308
|
+
* await client.viewer.createAction({
|
|
1309
|
+
* name: "button_click",
|
|
1310
|
+
* data: { buttonId: "play" },
|
|
1311
|
+
* appId: "app1",
|
|
1312
|
+
* })
|
|
1313
|
+
* ```
|
|
1314
|
+
*/
|
|
1315
|
+
createAction(options: {
|
|
1316
|
+
name: string;
|
|
1317
|
+
data: unknown;
|
|
1318
|
+
appId: string;
|
|
1319
|
+
}): Promise<{
|
|
1320
|
+
success: boolean;
|
|
1321
|
+
}>;
|
|
1322
|
+
/**
|
|
1323
|
+
* Get mini viewer data.
|
|
1324
|
+
*
|
|
1325
|
+
* @param options - Query options
|
|
1326
|
+
* @param options.viewerId - Viewer ID
|
|
1327
|
+
* @returns Viewer mini data
|
|
1328
|
+
*
|
|
1329
|
+
* @example
|
|
1330
|
+
* ```typescript
|
|
1331
|
+
* const viewer = await client.viewer.getMini({ viewerId: "v1" })
|
|
1332
|
+
* console.log(`Twitch: ${viewer.twitch?.displayName}`)
|
|
1333
|
+
* ```
|
|
1334
|
+
*/
|
|
1335
|
+
getMini(options: {
|
|
1336
|
+
viewerId: string;
|
|
1337
|
+
}): Promise<ViewerMiniJson>;
|
|
1338
|
+
/**
|
|
1339
|
+
* Get full viewer data including properties.
|
|
1340
|
+
*
|
|
1341
|
+
* @param options - Query options
|
|
1342
|
+
* @param options.viewerId - Viewer ID
|
|
1343
|
+
* @returns Full viewer data
|
|
1344
|
+
*
|
|
1345
|
+
* @example
|
|
1346
|
+
* ```typescript
|
|
1347
|
+
* const viewer = await client.viewer.get({ viewerId: "v1" })
|
|
1348
|
+
* console.log(`Twitch: ${viewer.twitch?.displayName}`)
|
|
1349
|
+
* if (viewer.properties) {
|
|
1350
|
+
* for (const [name, prop] of Object.entries(viewer.properties)) {
|
|
1351
|
+
* console.log(`${name}: ${prop.value}`)
|
|
1352
|
+
* }
|
|
1353
|
+
* }
|
|
1354
|
+
* ```
|
|
1355
|
+
*/
|
|
1356
|
+
get(options: {
|
|
1357
|
+
viewerId: string;
|
|
1358
|
+
}): Promise<ViewerJson>;
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Main client for the Tentacle API.
|
|
1362
|
+
*
|
|
1363
|
+
* Provides access to Tentacle API endpoints including:
|
|
1364
|
+
* - **realtime**: Subscribe to live Twitch and Kick events via SSE
|
|
1365
|
+
* - **apps**: Manage apps and viewer properties
|
|
1366
|
+
* - **stream**: Access chat messages and events history
|
|
1367
|
+
* - **subathon**: Access subathon statistics
|
|
1368
|
+
* - **viewer**: Access viewer data
|
|
1369
|
+
*
|
|
1370
|
+
* @example
|
|
1371
|
+
* ```typescript
|
|
1372
|
+
* import { TentacleClient } from 'tentacle-sdk'
|
|
1373
|
+
*
|
|
1374
|
+
* const client = new TentacleClient({
|
|
1375
|
+
* baseUrl: 'https://api.tentacle.live',
|
|
1376
|
+
* accessToken: 'your-access-token',
|
|
1377
|
+
* })
|
|
1378
|
+
*
|
|
1379
|
+
* // Subscribe to realtime events (Twitch + Kick)
|
|
1380
|
+
* const unsubscribe = client.realtime.subscribe({
|
|
1381
|
+
* onEvent: (event) => {
|
|
1382
|
+
* if (event.kind === 'StreamChatMessage') {
|
|
1383
|
+
* console.log(`Chat: ${event.payload.$text}`)
|
|
1384
|
+
* } else if (event.kind === 'StreamEvent') {
|
|
1385
|
+
* console.log(`Event: ${event.payload.$type}`)
|
|
1386
|
+
* }
|
|
1387
|
+
* },
|
|
1388
|
+
* })
|
|
1389
|
+
*
|
|
1390
|
+
* // Get recent chat messages
|
|
1391
|
+
* const messages = await client.stream.getChatMessages({ take: 10 })
|
|
1392
|
+
* ```
|
|
1393
|
+
*/
|
|
1394
|
+
declare class TentacleClient {
|
|
1395
|
+
private readonly http;
|
|
1396
|
+
/**
|
|
1397
|
+
* Creates a TentacleClient with automatic authentication.
|
|
1398
|
+
*
|
|
1399
|
+
* This factory method handles the device authorization flow:
|
|
1400
|
+
* 1. Checks for a cached token in the credential store
|
|
1401
|
+
* 2. Validates the cached token with the API
|
|
1402
|
+
* 3. If invalid or missing, initiates device authorization
|
|
1403
|
+
* 4. Caches the new token after successful authorization
|
|
1404
|
+
*
|
|
1405
|
+
* @param options - Creation options
|
|
1406
|
+
* @returns A configured TentacleClient
|
|
1407
|
+
*
|
|
1408
|
+
* @example
|
|
1409
|
+
* ```typescript
|
|
1410
|
+
* const client = await TentacleClient.create({
|
|
1411
|
+
* baseUrl: "https://api.tentacle.live",
|
|
1412
|
+
* credentialStore: new FileCredentialStore(),
|
|
1413
|
+
* deviceAuthOptions: {
|
|
1414
|
+
* clientInfo: "My Unreal Game",
|
|
1415
|
+
* onAuthRequired: ({ verificationUrl, userCode }) => {
|
|
1416
|
+
* console.log(`Visit: ${verificationUrl}`)
|
|
1417
|
+
* console.log(`Enter code: ${userCode}`)
|
|
1418
|
+
* },
|
|
1419
|
+
* },
|
|
1420
|
+
* })
|
|
1421
|
+
* ```
|
|
1422
|
+
*/
|
|
1423
|
+
static create(options: TentacleClientCreateOptions): Promise<TentacleClient>;
|
|
1424
|
+
/**
|
|
1425
|
+
* Apps API for managing apps and viewer properties.
|
|
1426
|
+
*
|
|
1427
|
+
* @example
|
|
1428
|
+
* ```typescript
|
|
1429
|
+
* const { apps } = await client.apps.list()
|
|
1430
|
+
* const { app } = await client.apps.create({ name: "My Game" })
|
|
1431
|
+
* ```
|
|
1432
|
+
*/
|
|
1433
|
+
readonly apps: AppsApi;
|
|
1434
|
+
/**
|
|
1435
|
+
* Realtime API for subscribing to live Twitch and Kick events.
|
|
1436
|
+
*
|
|
1437
|
+
* Use this to receive:
|
|
1438
|
+
* - Chat messages from Twitch and Kick
|
|
1439
|
+
* - Stream events (follows, subs, raids, cheers, etc.)
|
|
1440
|
+
* - Viewer activity updates
|
|
1441
|
+
*
|
|
1442
|
+
* @example
|
|
1443
|
+
* ```typescript
|
|
1444
|
+
* const unsubscribe = client.realtime.subscribe({
|
|
1445
|
+
* onEvent: (event) => {
|
|
1446
|
+
* switch (event.kind) {
|
|
1447
|
+
* case 'StreamChatMessage':
|
|
1448
|
+
* console.log(event.payload.$text)
|
|
1449
|
+
* break
|
|
1450
|
+
* case 'StreamEvent':
|
|
1451
|
+
* console.log(event.payload.$type)
|
|
1452
|
+
* break
|
|
1453
|
+
* }
|
|
1454
|
+
* },
|
|
1455
|
+
* })
|
|
1456
|
+
* ```
|
|
1457
|
+
*/
|
|
1458
|
+
readonly realtime: RealtimeApi;
|
|
1459
|
+
/**
|
|
1460
|
+
* Stream API for accessing chat messages and events history.
|
|
1461
|
+
*
|
|
1462
|
+
* @example
|
|
1463
|
+
* ```typescript
|
|
1464
|
+
* const messages = await client.stream.getChatMessages({ take: 50 })
|
|
1465
|
+
* const events = await client.stream.getEvents({ take: 20 })
|
|
1466
|
+
* ```
|
|
1467
|
+
*/
|
|
1468
|
+
readonly stream: StreamApi;
|
|
1469
|
+
/**
|
|
1470
|
+
* Subathon API for accessing subathon statistics.
|
|
1471
|
+
*
|
|
1472
|
+
* @example
|
|
1473
|
+
* ```typescript
|
|
1474
|
+
* const subs = await client.subathon.getSubs()
|
|
1475
|
+
* const donations = await client.subathon.getDonations()
|
|
1476
|
+
* ```
|
|
1477
|
+
*/
|
|
1478
|
+
readonly subathon: SubathonApi;
|
|
1479
|
+
/**
|
|
1480
|
+
* Viewer API for accessing viewer data.
|
|
1481
|
+
*
|
|
1482
|
+
* @example
|
|
1483
|
+
* ```typescript
|
|
1484
|
+
* const viewer = await client.viewer.get({ viewerId: "v1" })
|
|
1485
|
+
* ```
|
|
1486
|
+
*/
|
|
1487
|
+
readonly viewer: ViewerApi;
|
|
1488
|
+
/**
|
|
1489
|
+
* Create a new Tentacle client.
|
|
1490
|
+
*
|
|
1491
|
+
* @param config - Client configuration
|
|
1492
|
+
* @param config.baseUrl - Base URL of the Tentacle API
|
|
1493
|
+
* @param config.accessToken - Access token for authentication
|
|
1494
|
+
*
|
|
1495
|
+
* @example
|
|
1496
|
+
* ```typescript
|
|
1497
|
+
* const client = new TentacleClient({
|
|
1498
|
+
* baseUrl: 'https://api.tentacle.live',
|
|
1499
|
+
* accessToken: 'your-access-token',
|
|
1500
|
+
* })
|
|
1501
|
+
* ```
|
|
1502
|
+
*/
|
|
1503
|
+
constructor(config: TentacleClientConfig);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/**
|
|
1507
|
+
* File-based credential store for Node.js environments.
|
|
1508
|
+
*
|
|
1509
|
+
* Stores access tokens in a JSON file on the local filesystem.
|
|
1510
|
+
* Default location: ~/.tentacle/credentials.json
|
|
1511
|
+
*
|
|
1512
|
+
* @module auth/file-credential-store
|
|
1513
|
+
*/
|
|
1514
|
+
|
|
1515
|
+
/**
|
|
1516
|
+
* Options for configuring the FileCredentialStore.
|
|
1517
|
+
*/
|
|
1518
|
+
interface FileCredentialStoreOptions {
|
|
1519
|
+
/**
|
|
1520
|
+
* Path to the credentials file.
|
|
1521
|
+
* Defaults to ~/.tentacle/credentials.json
|
|
1522
|
+
*/
|
|
1523
|
+
path?: string;
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* File-based credential store implementation.
|
|
1527
|
+
*
|
|
1528
|
+
* Stores access tokens in a JSON file with restricted permissions (0o600).
|
|
1529
|
+
* Uses dynamic imports for Node.js fs module to support non-Node environments.
|
|
1530
|
+
*
|
|
1531
|
+
* @example
|
|
1532
|
+
* ```typescript
|
|
1533
|
+
* const store = new FileCredentialStore()
|
|
1534
|
+
* await store.setAccessToken("my-token")
|
|
1535
|
+
* const token = await store.getAccessToken()
|
|
1536
|
+
* ```
|
|
1537
|
+
*/
|
|
1538
|
+
declare class FileCredentialStore implements CredentialStore {
|
|
1539
|
+
private readonly path;
|
|
1540
|
+
constructor(options?: FileCredentialStoreOptions);
|
|
1541
|
+
/**
|
|
1542
|
+
* Gets the default credentials file path.
|
|
1543
|
+
*/
|
|
1544
|
+
private getDefaultPath;
|
|
1545
|
+
/**
|
|
1546
|
+
* Retrieves the stored access token.
|
|
1547
|
+
*/
|
|
1548
|
+
getAccessToken(): Promise<string | null>;
|
|
1549
|
+
/**
|
|
1550
|
+
* Stores an access token.
|
|
1551
|
+
*
|
|
1552
|
+
* Creates the directory if it doesn't exist.
|
|
1553
|
+
* Sets file permissions to 0o600 (user read/write only).
|
|
1554
|
+
*/
|
|
1555
|
+
setAccessToken(token: string): Promise<void>;
|
|
1556
|
+
/**
|
|
1557
|
+
* Removes the stored access token.
|
|
1558
|
+
*/
|
|
1559
|
+
clearAccessToken(): Promise<void>;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
export { type AppJson, type ChatMessageEmoji, type ChatMessageEmote, type ChatMessagePosition, type CommonChatMessage, type CommonEventJson, type CredentialStore, type DateIsoString, DeviceAuthFlow, type DeviceAuthInitResult, type DeviceAuthOptions, type DeviceAuthPollResult, type DonationUnlock, FileCredentialStore, type FileCredentialStoreOptions, type GiftedSubUnlock, type KickBadge, type KickChatMessageJson, type KickEventJson, type KickEventJson_ChannelFollow, type KickEventJson_ChannelSubscriptionGifts, type KickEventJson_ChannelSubscriptionNew, type KickEventJson_ChannelSubscriptionRenewal, type KickEventJson_LivestreamStatusUpdated, type OrderDirection, type RealtimeEvent, type RealtimeEvent_StreamChatMessage, type RealtimeEvent_StreamEvent, type RealtimeEvent_StreamViewerActivity, type RealtimeSubscribeOptions, type StreamChatMessageJson, type StreamEventJson, type StreamPlatform, type StreamViewerActivityJson, type SubUnlock, type SubathonStats_Donations, type SubathonStats_GiftedSubscriptions, type SubathonStats_Subscriptions, TentacleClient, type TentacleClientConfig, type TentacleClientCreateOptions, TentacleError, type TwitchChatMessageJson, type TwitchEventJson, type TwitchEventJson_Cheer, type TwitchEventJson_Follow, type TwitchEventJson_Raid, type TwitchEventJson_RedemptionAdd, type TwitchEventJson_StreamOnline, type TwitchEventJson_Subscription, type TwitchEventJson_SubscriptionGift, type TwitchEventType, type TwitchUserInfo, type UnsubscribeFunction, type ViewerActionJson, type ViewerJson, type ViewerKickJson, type ViewerMiniJson, type ViewerPropertyJson, type ViewerPropertyJsonBase, type ViewerPropertyJson_Bool, type ViewerPropertyJson_Number, type ViewerPropertyJson_String, type ViewerPropertyType, type ViewerTwitchJson, type ViewersByPropertyOutput };
|