@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 ADDED
@@ -0,0 +1,241 @@
1
+ # @thestatic/dcl-sdk
2
+
3
+ Connect your Decentraland scene to [thestatic.tv](https://thestatic.tv) - the decentralized streaming platform.
4
+
5
+ This SDK allows DCL scene builders to:
6
+ - Display the full thestatic.tv channel lineup in their scenes
7
+ - Track video watching metrics
8
+ - Enable likes/follows from within DCL
9
+ - Get referral credit for driving traffic to channels
10
+
11
+ ## Two Modes
12
+
13
+ | Mode | Key Prefix | Features | Get Key From |
14
+ |------|------------|----------|--------------|
15
+ | **Full** | `dclk_` | Guide, Heartbeat, Sessions, Interactions | Studio (channel owners) |
16
+ | **Lite** | `dcls_` | Sessions only (visitor tracking) | Profile (all users) |
17
+
18
+ The SDK auto-detects your key type and enables/disables features accordingly.
19
+
20
+ > **Free Trial**: New accounts get 7 days of free visitor tracking!
21
+
22
+ ## Example Scene
23
+
24
+ Clone our example scene to get started quickly:
25
+
26
+ ```bash
27
+ git clone https://github.com/thestatic-tv/dcl-example.git
28
+ cd dcl-example
29
+ npm install
30
+ npm start
31
+ ```
32
+
33
+ See the [example repo](https://github.com/thestatic-tv/dcl-example) for a complete working scene.
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ npm install @thestatic/dcl-sdk
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ 1. Get your API key from [thestatic.tv/studio](https://thestatic.tv/studio) (DCL Integration tab)
44
+
45
+ 2. Initialize the client in your scene:
46
+
47
+ ```typescript
48
+ import { StaticTVClient } from '@thestatic/dcl-sdk'
49
+
50
+ const staticTV = new StaticTVClient({
51
+ apiKey: 'dclk_your_api_key_here',
52
+ debug: true // Enable for development
53
+ })
54
+ ```
55
+
56
+ 3. Fetch channels and display them:
57
+
58
+ ```typescript
59
+ // Get all channels
60
+ const channels = await staticTV.guide.getChannels()
61
+
62
+ // Get only live channels
63
+ const liveChannels = await staticTV.guide.getLiveChannels()
64
+
65
+ // Get a specific channel
66
+ const channel = await staticTV.guide.getChannel('channel-slug')
67
+ ```
68
+
69
+ 4. Track video watching:
70
+
71
+ ```typescript
72
+ // When user enters video viewing area
73
+ staticTV.heartbeat.startWatching('channel-slug')
74
+
75
+ // When user leaves video viewing area
76
+ staticTV.heartbeat.stopWatching()
77
+ ```
78
+
79
+ 5. Enable interactions:
80
+
81
+ ```typescript
82
+ // Like a channel (requires wallet connection)
83
+ await staticTV.interactions.like('channel-slug')
84
+
85
+ // Follow a channel
86
+ await staticTV.interactions.follow('channel-slug')
87
+ ```
88
+
89
+ 6. Cleanup before scene unload:
90
+
91
+ ```typescript
92
+ await staticTV.destroy()
93
+ ```
94
+
95
+ ## Lite Mode (Visitor Tracking Only)
96
+
97
+ If you don't have a channel but want to track visitors to your scene:
98
+
99
+ 1. Get a scene key from [thestatic.tv/profile](https://thestatic.tv/profile) (DCL Scenes tab)
100
+
101
+ 2. Initialize with your scene key:
102
+
103
+ ```typescript
104
+ import { StaticTVClient } from '@thestatic/dcl-sdk'
105
+
106
+ const staticTV = new StaticTVClient({
107
+ apiKey: 'dcls_your_scene_key_here'
108
+ })
109
+
110
+ // Session tracking starts automatically
111
+ // Visitors are tracked when they enter your scene
112
+ ```
113
+
114
+ 3. Check if running in lite mode:
115
+
116
+ ```typescript
117
+ if (staticTV.isLite) {
118
+ console.log('Running in lite mode - session tracking only')
119
+ }
120
+
121
+ // guide, heartbeat, and interactions are null in lite mode
122
+ if (staticTV.guide) {
123
+ const channels = await staticTV.guide.getChannels()
124
+ }
125
+ ```
126
+
127
+ ## API Reference
128
+
129
+ ### StaticTVClient
130
+
131
+ Main client class for interacting with thestatic.tv.
132
+
133
+ #### Constructor Options
134
+
135
+ | Option | Type | Default | Description |
136
+ |--------|------|---------|-------------|
137
+ | `apiKey` | `string` | required | Your API key (`dclk_` for full, `dcls_` for lite) |
138
+ | `autoStartSession` | `boolean` | `true` | Automatically start session tracking |
139
+ | `sessionHeartbeatInterval` | `number` | `30000` | Session heartbeat interval (ms) |
140
+ | `watchHeartbeatInterval` | `number` | `60000` | Watch heartbeat interval (ms) |
141
+ | `debug` | `boolean` | `false` | Enable debug logging |
142
+
143
+ #### Properties
144
+
145
+ | Property | Type | Description |
146
+ |----------|------|-------------|
147
+ | `keyType` | `'channel' \| 'scene'` | The detected key type |
148
+ | `isLite` | `boolean` | `true` if using a scene key (lite mode) |
149
+ | `guide` | `GuideModule \| null` | Guide module (null in lite mode) |
150
+ | `session` | `SessionModule` | Session module (always available) |
151
+ | `heartbeat` | `HeartbeatModule \| null` | Heartbeat module (null in lite mode) |
152
+ | `interactions` | `InteractionsModule \| null` | Interactions module (null in lite mode) |
153
+
154
+ ### Guide Module (Full Mode Only)
155
+
156
+ ```typescript
157
+ staticTV.guide.getChannels() // Get all channels (cached 30s)
158
+ staticTV.guide.getLiveChannels() // Get only live channels
159
+ staticTV.guide.getChannel(slug) // Get a specific channel
160
+ staticTV.guide.getVods() // Get VODs
161
+ staticTV.guide.clearCache() // Clear the channel cache
162
+ ```
163
+
164
+ ### Session Module
165
+
166
+ Session tracking starts automatically by default.
167
+
168
+ ```typescript
169
+ staticTV.session.startSession() // Manually start session
170
+ staticTV.session.endSession() // End session
171
+ staticTV.session.getSessionId() // Get current session ID
172
+ staticTV.session.isSessionActive() // Check if session is active
173
+ ```
174
+
175
+ ### Heartbeat Module (Full Mode Only)
176
+
177
+ Track video watching. Each heartbeat represents 1 minute watched.
178
+
179
+ ```typescript
180
+ staticTV.heartbeat.startWatching(channelSlug) // Start tracking
181
+ staticTV.heartbeat.stopWatching() // Stop tracking
182
+ staticTV.heartbeat.getCurrentChannel() // Get currently watched channel
183
+ staticTV.heartbeat.isCurrentlyWatching() // Check if watching
184
+ ```
185
+
186
+ ### Interactions Module (Full Mode Only)
187
+
188
+ Like and follow channels. Requires wallet connection.
189
+
190
+ ```typescript
191
+ staticTV.interactions.like(channelSlug) // Like a channel
192
+ staticTV.interactions.follow(channelSlug) // Follow a channel
193
+ ```
194
+
195
+ ## Metrics Attribution
196
+
197
+ This SDK implements dual attribution:
198
+
199
+ - **Watched Channel**: Gets view metrics (minutes watched, likes, follows)
200
+ - **Scene Owner**: Gets referral metrics (unique visitors, traffic driven)
201
+
202
+ Your channel (linked to your API key) receives credit for all traffic your scene drives to thestatic.tv channels.
203
+
204
+ ## Types
205
+
206
+ ```typescript
207
+ interface Channel {
208
+ id: string
209
+ slug: string
210
+ name: string
211
+ streamUrl: string
212
+ isLive: boolean
213
+ currentViewers: number
214
+ poster: string | null
215
+ logo: string | null
216
+ description: string
217
+ }
218
+
219
+ interface Vod {
220
+ id: string
221
+ title: string
222
+ url: string
223
+ thumbnail: string | null
224
+ channelId: string
225
+ }
226
+ ```
227
+
228
+ ## Requirements
229
+
230
+ - Decentraland SDK 7.0.0 or higher
231
+ - API key from thestatic.tv
232
+
233
+ ## Support
234
+
235
+ - Documentation: [thestatic.tv/info](https://thestatic.tv/info)
236
+ - Issues: [GitHub Issues](https://github.com/thestatic-tv/dcl-sdk/issues)
237
+ - Discord: [thestatic.tv Discord](https://discord.gg/thestatic)
238
+
239
+ ## License
240
+
241
+ MIT
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Configuration options for StaticTVClient
3
+ */
4
+ interface StaticTVConfig {
5
+ /** Your channel's API key from thestatic.tv studio */
6
+ apiKey: string;
7
+ /** Automatically start session tracking on init (default: true) */
8
+ autoStartSession?: boolean;
9
+ /** Interval for session heartbeats in ms (default: 30000) */
10
+ sessionHeartbeatInterval?: number;
11
+ /** Interval for video watching heartbeats in ms (default: 60000) */
12
+ watchHeartbeatInterval?: number;
13
+ /** Enable debug logging (default: false) */
14
+ debug?: boolean;
15
+ /** Custom API base URL (default: https://thestatic.tv/api/v1/dcl) */
16
+ baseUrl?: string;
17
+ }
18
+ /**
19
+ * Channel information from the guide
20
+ */
21
+ interface Channel {
22
+ id: string;
23
+ slug: string;
24
+ name: string;
25
+ streamUrl: string;
26
+ isLive: boolean;
27
+ currentViewers: number;
28
+ poster: string | null;
29
+ logo: string | null;
30
+ description: string;
31
+ socials: string | null;
32
+ }
33
+ /**
34
+ * VOD (Video on Demand) information
35
+ */
36
+ interface Vod {
37
+ id: string;
38
+ title: string;
39
+ url: string;
40
+ thumbnail: string | null;
41
+ channelId: string;
42
+ createdAt: string;
43
+ }
44
+ /**
45
+ * Guide response from the API
46
+ */
47
+ interface GuideResponse {
48
+ version: string;
49
+ sceneOwnerChannel: string;
50
+ channels: Channel[];
51
+ liveChannels: Channel[];
52
+ vods: Vod[];
53
+ meta: {
54
+ generatedAt: string;
55
+ totalChannels: number;
56
+ liveCount: number;
57
+ vodCount: number;
58
+ };
59
+ }
60
+ /**
61
+ * Session response from the API
62
+ */
63
+ interface SessionResponse {
64
+ success: boolean;
65
+ sessionId?: string;
66
+ version: string;
67
+ }
68
+ /**
69
+ * Heartbeat response from the API
70
+ */
71
+ interface HeartbeatResponse {
72
+ success: boolean;
73
+ channelSlug: string;
74
+ sceneOwnerChannel: string;
75
+ version: string;
76
+ }
77
+ /**
78
+ * Interaction response from the API
79
+ */
80
+ interface InteractionResponse {
81
+ success: boolean;
82
+ action: 'like' | 'follow';
83
+ channelSlug: string;
84
+ alreadyExists: boolean;
85
+ version: string;
86
+ }
87
+
88
+ /**
89
+ * Guide module - fetch channel lineup from thestatic.tv
90
+ */
91
+
92
+ declare class GuideModule {
93
+ private client;
94
+ private cachedChannels;
95
+ private cacheTimestamp;
96
+ private readonly cacheDuration;
97
+ constructor(client: StaticTVClient);
98
+ /**
99
+ * Get all channels from thestatic.tv
100
+ * Results are cached for 30 seconds
101
+ */
102
+ getChannels(forceRefresh?: boolean): Promise<Channel[]>;
103
+ /**
104
+ * Get only live channels
105
+ */
106
+ getLiveChannels(forceRefresh?: boolean): Promise<Channel[]>;
107
+ /**
108
+ * Get a specific channel by slug
109
+ */
110
+ getChannel(slug: string): Promise<Channel | undefined>;
111
+ /**
112
+ * Get VODs (videos on demand)
113
+ */
114
+ getVods(): Promise<Vod[]>;
115
+ /**
116
+ * Clear the channel cache
117
+ */
118
+ clearCache(): void;
119
+ }
120
+
121
+ /**
122
+ * Session module - track visitor sessions in DCL scenes
123
+ *
124
+ * Works with both channel keys (dclk_) and scene keys (dcls_).
125
+ * Scene keys use /scene-session endpoint, channel keys use /session.
126
+ */
127
+
128
+ declare class SessionModule {
129
+ private client;
130
+ private sessionId;
131
+ private heartbeatInterval;
132
+ private isActive;
133
+ constructor(client: StaticTVClient);
134
+ /**
135
+ * Get the appropriate session endpoint based on key type
136
+ */
137
+ private getEndpoint;
138
+ /**
139
+ * Start a new session
140
+ * Called automatically if autoStartSession is true
141
+ */
142
+ startSession(metadata?: Record<string, unknown>): Promise<string | null>;
143
+ /**
144
+ * Start the heartbeat interval
145
+ */
146
+ private startHeartbeat;
147
+ /**
148
+ * Send a session heartbeat
149
+ */
150
+ private sendHeartbeat;
151
+ /**
152
+ * End the current session
153
+ */
154
+ endSession(): Promise<void>;
155
+ /**
156
+ * Get the current session ID
157
+ */
158
+ getSessionId(): string | null;
159
+ /**
160
+ * Check if a session is currently active
161
+ */
162
+ isSessionActive(): boolean;
163
+ }
164
+
165
+ /**
166
+ * Heartbeat module - track video watching metrics
167
+ */
168
+
169
+ declare class HeartbeatModule {
170
+ private client;
171
+ private watchInterval;
172
+ private currentChannel;
173
+ private isWatching;
174
+ constructor(client: StaticTVClient);
175
+ /**
176
+ * Start tracking video watching for a channel
177
+ * Sends heartbeats every minute while watching
178
+ *
179
+ * @param channelSlug The slug of the channel being watched
180
+ */
181
+ startWatching(channelSlug: string): void;
182
+ /**
183
+ * Stop tracking video watching
184
+ */
185
+ stopWatching(): void;
186
+ /**
187
+ * Send a watching heartbeat (1 heartbeat = 1 minute watched)
188
+ */
189
+ private sendHeartbeat;
190
+ /**
191
+ * Get the currently watched channel
192
+ */
193
+ getCurrentChannel(): string | null;
194
+ /**
195
+ * Check if currently watching
196
+ */
197
+ isCurrentlyWatching(): boolean;
198
+ }
199
+
200
+ /**
201
+ * Interactions module - like/follow channels from DCL scenes
202
+ */
203
+
204
+ declare class InteractionsModule {
205
+ private client;
206
+ constructor(client: StaticTVClient);
207
+ /**
208
+ * Like a channel
209
+ * Requires the user to be connected with a wallet
210
+ *
211
+ * @param channelSlug The slug of the channel to like
212
+ * @returns The interaction response or null if failed
213
+ */
214
+ like(channelSlug: string): Promise<InteractionResponse | null>;
215
+ /**
216
+ * Follow a channel
217
+ * Requires the user to be connected with a wallet
218
+ *
219
+ * @param channelSlug The slug of the channel to follow
220
+ * @returns The interaction response or null if failed
221
+ */
222
+ follow(channelSlug: string): Promise<InteractionResponse | null>;
223
+ }
224
+
225
+ /**
226
+ * StaticTVClient - Main client for connecting DCL scenes to thestatic.tv
227
+ *
228
+ * Supports two key types:
229
+ * - dclk_* : Channel keys (full access - guide, heartbeat, interactions)
230
+ * - dcls_* : Scene-only keys (lite - session tracking only)
231
+ */
232
+
233
+ /** Key type constants */
234
+ declare const KEY_TYPE_CHANNEL = "channel";
235
+ declare const KEY_TYPE_SCENE = "scene";
236
+ declare class StaticTVClient {
237
+ private config;
238
+ private baseUrl;
239
+ private _keyType;
240
+ /** Guide module - fetch channel lineup (channel keys only) */
241
+ readonly guide: GuideModule | null;
242
+ /** Session module - track visitor sessions (all keys) */
243
+ readonly session: SessionModule;
244
+ /** Heartbeat module - track video watching (channel keys only) */
245
+ readonly heartbeat: HeartbeatModule | null;
246
+ /** Interactions module - like/follow channels (channel keys only) */
247
+ readonly interactions: InteractionsModule | null;
248
+ /**
249
+ * Create a new StaticTVClient
250
+ *
251
+ * @param config Configuration options
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * // Full access with channel key
256
+ * const staticTV = new StaticTVClient({
257
+ * apiKey: 'dclk_your_channel_key_here',
258
+ * debug: true
259
+ * });
260
+ *
261
+ * // Lite mode with scene key (visitors only)
262
+ * const staticTV = new StaticTVClient({
263
+ * apiKey: 'dcls_your_scene_key_here'
264
+ * });
265
+ * ```
266
+ */
267
+ constructor(config: StaticTVConfig);
268
+ /**
269
+ * Get the key type (channel or scene)
270
+ */
271
+ get keyType(): 'channel' | 'scene';
272
+ /**
273
+ * Check if this is a lite (scene-only) client
274
+ */
275
+ get isLite(): boolean;
276
+ /**
277
+ * Make an authenticated API request
278
+ * @internal
279
+ */
280
+ request<T>(endpoint: string, options?: RequestInit): Promise<T>;
281
+ /**
282
+ * Log a message if debug is enabled
283
+ * @internal
284
+ */
285
+ log(message: string, ...args: unknown[]): void;
286
+ /**
287
+ * Get the current configuration
288
+ * @internal
289
+ */
290
+ getConfig(): StaticTVConfig;
291
+ /**
292
+ * Cleanup when done (call before scene unload)
293
+ */
294
+ destroy(): Promise<void>;
295
+ }
296
+
297
+ export { type Channel, GuideModule, type GuideResponse, HeartbeatModule, type HeartbeatResponse, type InteractionResponse, InteractionsModule, KEY_TYPE_CHANNEL, KEY_TYPE_SCENE, SessionModule, type SessionResponse, StaticTVClient, type StaticTVConfig, type Vod };