@thestatic-tv/dcl-sdk 1.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.
- package/README.md +241 -0
- package/dist/index.d.mts +297 -0
- package/dist/index.d.ts +297 -0
- package/dist/index.js +516 -0
- package/dist/index.mjs +490 -0
- package/package.json +53 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
GuideModule: () => GuideModule,
|
|
24
|
+
HeartbeatModule: () => HeartbeatModule,
|
|
25
|
+
InteractionsModule: () => InteractionsModule,
|
|
26
|
+
KEY_TYPE_CHANNEL: () => KEY_TYPE_CHANNEL,
|
|
27
|
+
KEY_TYPE_SCENE: () => KEY_TYPE_SCENE,
|
|
28
|
+
SessionModule: () => SessionModule,
|
|
29
|
+
StaticTVClient: () => StaticTVClient
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/utils/http.ts
|
|
34
|
+
async function request(url, options = {}) {
|
|
35
|
+
const { timeout = 1e4, ...fetchOptions } = options;
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch(url, {
|
|
40
|
+
...fetchOptions,
|
|
41
|
+
signal: controller.signal
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const errorData = await response.json().catch(() => ({}));
|
|
45
|
+
throw new Error(errorData.error || `HTTP ${response.status}`);
|
|
46
|
+
}
|
|
47
|
+
return response.json();
|
|
48
|
+
} finally {
|
|
49
|
+
clearTimeout(timeoutId);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/modules/guide.ts
|
|
54
|
+
var GuideModule = class {
|
|
55
|
+
// 30 seconds
|
|
56
|
+
constructor(client) {
|
|
57
|
+
this.cachedChannels = null;
|
|
58
|
+
this.cacheTimestamp = 0;
|
|
59
|
+
this.cacheDuration = 3e4;
|
|
60
|
+
this.client = client;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get all channels from thestatic.tv
|
|
64
|
+
* Results are cached for 30 seconds
|
|
65
|
+
*/
|
|
66
|
+
async getChannels(forceRefresh = false) {
|
|
67
|
+
const now = Date.now();
|
|
68
|
+
if (!forceRefresh && this.cachedChannels && now - this.cacheTimestamp < this.cacheDuration) {
|
|
69
|
+
this.client.log("Returning cached channels");
|
|
70
|
+
return this.cachedChannels;
|
|
71
|
+
}
|
|
72
|
+
const response = await this.client.request("/guide");
|
|
73
|
+
this.cachedChannels = response.channels;
|
|
74
|
+
this.cacheTimestamp = now;
|
|
75
|
+
this.client.log(`Fetched ${response.channels.length} channels`);
|
|
76
|
+
return response.channels;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get only live channels
|
|
80
|
+
*/
|
|
81
|
+
async getLiveChannels(forceRefresh = false) {
|
|
82
|
+
const channels = await this.getChannels(forceRefresh);
|
|
83
|
+
return channels.filter((c) => c.isLive);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get a specific channel by slug
|
|
87
|
+
*/
|
|
88
|
+
async getChannel(slug) {
|
|
89
|
+
const channels = await this.getChannels();
|
|
90
|
+
return channels.find((c) => c.slug === slug);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get VODs (videos on demand)
|
|
94
|
+
*/
|
|
95
|
+
async getVods() {
|
|
96
|
+
const response = await this.client.request("/guide");
|
|
97
|
+
return response.vods;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Clear the channel cache
|
|
101
|
+
*/
|
|
102
|
+
clearCache() {
|
|
103
|
+
this.cachedChannels = null;
|
|
104
|
+
this.cacheTimestamp = 0;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// src/utils/identity.ts
|
|
109
|
+
function getPlayerWallet() {
|
|
110
|
+
try {
|
|
111
|
+
const { getPlayer } = require("@dcl/sdk/src/players");
|
|
112
|
+
const player = getPlayer();
|
|
113
|
+
return player?.userId ?? null;
|
|
114
|
+
} catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function getPlayerDisplayName() {
|
|
119
|
+
try {
|
|
120
|
+
const { getPlayer } = require("@dcl/sdk/src/players");
|
|
121
|
+
const player = getPlayer();
|
|
122
|
+
return player?.name ?? null;
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/modules/session.ts
|
|
129
|
+
var SessionModule = class {
|
|
130
|
+
constructor(client) {
|
|
131
|
+
this.sessionId = null;
|
|
132
|
+
this.heartbeatInterval = null;
|
|
133
|
+
this.isActive = false;
|
|
134
|
+
this.client = client;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the appropriate session endpoint based on key type
|
|
138
|
+
*/
|
|
139
|
+
getEndpoint() {
|
|
140
|
+
return this.client.isLite ? "/scene-session" : "/session";
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Start a new session
|
|
144
|
+
* Called automatically if autoStartSession is true
|
|
145
|
+
*/
|
|
146
|
+
async startSession(metadata) {
|
|
147
|
+
if (this.isActive) {
|
|
148
|
+
this.client.log("Session already active");
|
|
149
|
+
return this.sessionId;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
const response = await this.client.request(this.getEndpoint(), {
|
|
153
|
+
method: "POST",
|
|
154
|
+
body: JSON.stringify({
|
|
155
|
+
action: "enter",
|
|
156
|
+
walletAddress: getPlayerWallet(),
|
|
157
|
+
dclDisplayName: getPlayerDisplayName(),
|
|
158
|
+
metadata
|
|
159
|
+
})
|
|
160
|
+
});
|
|
161
|
+
if (response.success && response.sessionId) {
|
|
162
|
+
this.sessionId = response.sessionId;
|
|
163
|
+
this.isActive = true;
|
|
164
|
+
this.startHeartbeat();
|
|
165
|
+
this.client.log(`Session started: ${this.sessionId}`);
|
|
166
|
+
return this.sessionId;
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
this.client.log(`Failed to start session: ${error}`);
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Start the heartbeat interval
|
|
176
|
+
*/
|
|
177
|
+
startHeartbeat() {
|
|
178
|
+
if (this.heartbeatInterval) return;
|
|
179
|
+
const interval = this.client.getConfig().sessionHeartbeatInterval || 3e4;
|
|
180
|
+
this.heartbeatInterval = setInterval(() => {
|
|
181
|
+
this.sendHeartbeat();
|
|
182
|
+
}, interval);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Send a session heartbeat
|
|
186
|
+
*/
|
|
187
|
+
async sendHeartbeat() {
|
|
188
|
+
if (!this.sessionId || !this.isActive) return;
|
|
189
|
+
try {
|
|
190
|
+
await this.client.request(this.getEndpoint(), {
|
|
191
|
+
method: "POST",
|
|
192
|
+
body: JSON.stringify({
|
|
193
|
+
action: "heartbeat",
|
|
194
|
+
sessionId: this.sessionId
|
|
195
|
+
})
|
|
196
|
+
});
|
|
197
|
+
this.client.log("Session heartbeat sent");
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this.client.log(`Session heartbeat failed: ${error}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* End the current session
|
|
204
|
+
*/
|
|
205
|
+
async endSession() {
|
|
206
|
+
if (!this.isActive) return;
|
|
207
|
+
if (this.heartbeatInterval) {
|
|
208
|
+
clearInterval(this.heartbeatInterval);
|
|
209
|
+
this.heartbeatInterval = null;
|
|
210
|
+
}
|
|
211
|
+
if (this.sessionId) {
|
|
212
|
+
try {
|
|
213
|
+
await this.client.request(this.getEndpoint(), {
|
|
214
|
+
method: "POST",
|
|
215
|
+
body: JSON.stringify({
|
|
216
|
+
action: "leave",
|
|
217
|
+
sessionId: this.sessionId
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
this.client.log("Session ended");
|
|
221
|
+
} catch (error) {
|
|
222
|
+
this.client.log(`Failed to end session: ${error}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
this.sessionId = null;
|
|
226
|
+
this.isActive = false;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get the current session ID
|
|
230
|
+
*/
|
|
231
|
+
getSessionId() {
|
|
232
|
+
return this.sessionId;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Check if a session is currently active
|
|
236
|
+
*/
|
|
237
|
+
isSessionActive() {
|
|
238
|
+
return this.isActive;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
// src/modules/heartbeat.ts
|
|
243
|
+
var HeartbeatModule = class {
|
|
244
|
+
constructor(client) {
|
|
245
|
+
this.watchInterval = null;
|
|
246
|
+
this.currentChannel = null;
|
|
247
|
+
this.isWatching = false;
|
|
248
|
+
this.client = client;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Start tracking video watching for a channel
|
|
252
|
+
* Sends heartbeats every minute while watching
|
|
253
|
+
*
|
|
254
|
+
* @param channelSlug The slug of the channel being watched
|
|
255
|
+
*/
|
|
256
|
+
startWatching(channelSlug) {
|
|
257
|
+
if (this.isWatching && this.currentChannel === channelSlug) {
|
|
258
|
+
this.client.log(`Already watching ${channelSlug}`);
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
if (this.isWatching && this.currentChannel !== channelSlug) {
|
|
262
|
+
this.stopWatching();
|
|
263
|
+
}
|
|
264
|
+
this.currentChannel = channelSlug;
|
|
265
|
+
this.isWatching = true;
|
|
266
|
+
this.sendHeartbeat();
|
|
267
|
+
const interval = this.client.getConfig().watchHeartbeatInterval || 6e4;
|
|
268
|
+
this.watchInterval = setInterval(() => {
|
|
269
|
+
this.sendHeartbeat();
|
|
270
|
+
}, interval);
|
|
271
|
+
this.client.log(`Started watching ${channelSlug}`);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Stop tracking video watching
|
|
275
|
+
*/
|
|
276
|
+
stopWatching() {
|
|
277
|
+
if (!this.isWatching) return;
|
|
278
|
+
if (this.watchInterval) {
|
|
279
|
+
clearInterval(this.watchInterval);
|
|
280
|
+
this.watchInterval = null;
|
|
281
|
+
}
|
|
282
|
+
this.client.log(`Stopped watching ${this.currentChannel}`);
|
|
283
|
+
this.currentChannel = null;
|
|
284
|
+
this.isWatching = false;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Send a watching heartbeat (1 heartbeat = 1 minute watched)
|
|
288
|
+
*/
|
|
289
|
+
async sendHeartbeat() {
|
|
290
|
+
if (!this.currentChannel || !this.isWatching) return;
|
|
291
|
+
try {
|
|
292
|
+
const sessionId = this.client.session.getSessionId();
|
|
293
|
+
await this.client.request("/heartbeat", {
|
|
294
|
+
method: "POST",
|
|
295
|
+
body: JSON.stringify({
|
|
296
|
+
channelSlug: this.currentChannel,
|
|
297
|
+
walletAddress: getPlayerWallet(),
|
|
298
|
+
sessionId
|
|
299
|
+
})
|
|
300
|
+
});
|
|
301
|
+
this.client.log(`Heartbeat sent for ${this.currentChannel}`);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
this.client.log(`Heartbeat failed: ${error}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get the currently watched channel
|
|
308
|
+
*/
|
|
309
|
+
getCurrentChannel() {
|
|
310
|
+
return this.currentChannel;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Check if currently watching
|
|
314
|
+
*/
|
|
315
|
+
isCurrentlyWatching() {
|
|
316
|
+
return this.isWatching;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/modules/interactions.ts
|
|
321
|
+
var InteractionsModule = class {
|
|
322
|
+
constructor(client) {
|
|
323
|
+
this.client = client;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Like a channel
|
|
327
|
+
* Requires the user to be connected with a wallet
|
|
328
|
+
*
|
|
329
|
+
* @param channelSlug The slug of the channel to like
|
|
330
|
+
* @returns The interaction response or null if failed
|
|
331
|
+
*/
|
|
332
|
+
async like(channelSlug) {
|
|
333
|
+
const walletAddress = getPlayerWallet();
|
|
334
|
+
if (!walletAddress) {
|
|
335
|
+
this.client.log("Cannot like: wallet not connected");
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
try {
|
|
339
|
+
const response = await this.client.request("/interact", {
|
|
340
|
+
method: "POST",
|
|
341
|
+
body: JSON.stringify({
|
|
342
|
+
action: "like",
|
|
343
|
+
channelSlug,
|
|
344
|
+
walletAddress
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
if (response.alreadyExists) {
|
|
348
|
+
this.client.log(`Already liked ${channelSlug}`);
|
|
349
|
+
} else {
|
|
350
|
+
this.client.log(`Liked ${channelSlug}`);
|
|
351
|
+
}
|
|
352
|
+
return response;
|
|
353
|
+
} catch (error) {
|
|
354
|
+
this.client.log(`Failed to like ${channelSlug}: ${error}`);
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Follow a channel
|
|
360
|
+
* Requires the user to be connected with a wallet
|
|
361
|
+
*
|
|
362
|
+
* @param channelSlug The slug of the channel to follow
|
|
363
|
+
* @returns The interaction response or null if failed
|
|
364
|
+
*/
|
|
365
|
+
async follow(channelSlug) {
|
|
366
|
+
const walletAddress = getPlayerWallet();
|
|
367
|
+
if (!walletAddress) {
|
|
368
|
+
this.client.log("Cannot follow: wallet not connected");
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
const response = await this.client.request("/interact", {
|
|
373
|
+
method: "POST",
|
|
374
|
+
body: JSON.stringify({
|
|
375
|
+
action: "follow",
|
|
376
|
+
channelSlug,
|
|
377
|
+
walletAddress
|
|
378
|
+
})
|
|
379
|
+
});
|
|
380
|
+
if (response.alreadyExists) {
|
|
381
|
+
this.client.log(`Already following ${channelSlug}`);
|
|
382
|
+
} else {
|
|
383
|
+
this.client.log(`Followed ${channelSlug}`);
|
|
384
|
+
}
|
|
385
|
+
return response;
|
|
386
|
+
} catch (error) {
|
|
387
|
+
this.client.log(`Failed to follow ${channelSlug}: ${error}`);
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// src/StaticTVClient.ts
|
|
394
|
+
var DEFAULT_BASE_URL = "https://thestatic.tv/api/v1/dcl";
|
|
395
|
+
var KEY_TYPE_CHANNEL = "channel";
|
|
396
|
+
var KEY_TYPE_SCENE = "scene";
|
|
397
|
+
var StaticTVClient = class {
|
|
398
|
+
/**
|
|
399
|
+
* Create a new StaticTVClient
|
|
400
|
+
*
|
|
401
|
+
* @param config Configuration options
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* ```typescript
|
|
405
|
+
* // Full access with channel key
|
|
406
|
+
* const staticTV = new StaticTVClient({
|
|
407
|
+
* apiKey: 'dclk_your_channel_key_here',
|
|
408
|
+
* debug: true
|
|
409
|
+
* });
|
|
410
|
+
*
|
|
411
|
+
* // Lite mode with scene key (visitors only)
|
|
412
|
+
* const staticTV = new StaticTVClient({
|
|
413
|
+
* apiKey: 'dcls_your_scene_key_here'
|
|
414
|
+
* });
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
constructor(config) {
|
|
418
|
+
if (!config.apiKey) {
|
|
419
|
+
throw new Error("StaticTVClient: apiKey is required");
|
|
420
|
+
}
|
|
421
|
+
if (config.apiKey.startsWith("dclk_")) {
|
|
422
|
+
this._keyType = KEY_TYPE_CHANNEL;
|
|
423
|
+
} else if (config.apiKey.startsWith("dcls_")) {
|
|
424
|
+
this._keyType = KEY_TYPE_SCENE;
|
|
425
|
+
} else {
|
|
426
|
+
throw new Error("StaticTVClient: invalid apiKey format. Must start with dclk_ or dcls_");
|
|
427
|
+
}
|
|
428
|
+
this.config = {
|
|
429
|
+
autoStartSession: true,
|
|
430
|
+
sessionHeartbeatInterval: 3e4,
|
|
431
|
+
watchHeartbeatInterval: 6e4,
|
|
432
|
+
debug: false,
|
|
433
|
+
...config
|
|
434
|
+
};
|
|
435
|
+
this.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
|
|
436
|
+
this.session = new SessionModule(this);
|
|
437
|
+
if (this._keyType === KEY_TYPE_CHANNEL) {
|
|
438
|
+
this.guide = new GuideModule(this);
|
|
439
|
+
this.heartbeat = new HeartbeatModule(this);
|
|
440
|
+
this.interactions = new InteractionsModule(this);
|
|
441
|
+
} else {
|
|
442
|
+
this.guide = null;
|
|
443
|
+
this.heartbeat = null;
|
|
444
|
+
this.interactions = null;
|
|
445
|
+
}
|
|
446
|
+
if (this.config.autoStartSession) {
|
|
447
|
+
this.session.startSession().catch((err) => {
|
|
448
|
+
this.log(`Auto-start session failed: ${err}`);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
this.log(`StaticTVClient initialized (${this._keyType} mode)`);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Get the key type (channel or scene)
|
|
455
|
+
*/
|
|
456
|
+
get keyType() {
|
|
457
|
+
return this._keyType;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Check if this is a lite (scene-only) client
|
|
461
|
+
*/
|
|
462
|
+
get isLite() {
|
|
463
|
+
return this._keyType === KEY_TYPE_SCENE;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Make an authenticated API request
|
|
467
|
+
* @internal
|
|
468
|
+
*/
|
|
469
|
+
async request(endpoint, options = {}) {
|
|
470
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
471
|
+
return request(url, {
|
|
472
|
+
...options,
|
|
473
|
+
headers: {
|
|
474
|
+
"Content-Type": "application/json",
|
|
475
|
+
"x-dcl-api-key": this.config.apiKey,
|
|
476
|
+
...options.headers
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Log a message if debug is enabled
|
|
482
|
+
* @internal
|
|
483
|
+
*/
|
|
484
|
+
log(message, ...args) {
|
|
485
|
+
if (this.config.debug) {
|
|
486
|
+
console.log(`[StaticTV] ${message}`, ...args);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Get the current configuration
|
|
491
|
+
* @internal
|
|
492
|
+
*/
|
|
493
|
+
getConfig() {
|
|
494
|
+
return this.config;
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Cleanup when done (call before scene unload)
|
|
498
|
+
*/
|
|
499
|
+
async destroy() {
|
|
500
|
+
if (this.heartbeat) {
|
|
501
|
+
this.heartbeat.stopWatching();
|
|
502
|
+
}
|
|
503
|
+
await this.session.endSession();
|
|
504
|
+
this.log("StaticTVClient destroyed");
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
508
|
+
0 && (module.exports = {
|
|
509
|
+
GuideModule,
|
|
510
|
+
HeartbeatModule,
|
|
511
|
+
InteractionsModule,
|
|
512
|
+
KEY_TYPE_CHANNEL,
|
|
513
|
+
KEY_TYPE_SCENE,
|
|
514
|
+
SessionModule,
|
|
515
|
+
StaticTVClient
|
|
516
|
+
});
|