@thestatic-tv/dcl-sdk 2.2.9 → 2.3.0-beta.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 +220 -68
- package/dist/index.d.mts +450 -38
- package/dist/index.d.ts +450 -38
- package/dist/index.js +1671 -142
- package/dist/index.mjs +1667 -141
- package/package.json +8 -3
package/README.md
CHANGED
|
@@ -14,11 +14,14 @@ This SDK allows DCL scene builders to:
|
|
|
14
14
|
|
|
15
15
|
## Pricing
|
|
16
16
|
|
|
17
|
-
|
|
|
18
|
-
|
|
19
|
-
| **
|
|
20
|
-
| **
|
|
17
|
+
| Tier | Price | Features |
|
|
18
|
+
|------|-------|----------|
|
|
19
|
+
| **Free** | $5/mo | Session/visitor tracking only |
|
|
20
|
+
| **Standard** | $10/mo | Free + Guide UI, Chat UI, Heartbeat, Interactions |
|
|
21
|
+
| **Pro** | $15/mo | Standard + Admin Panel (Video tab, Mod tab, Custom scene tabs) |
|
|
21
22
|
|
|
23
|
+
> **All keys use `dcls_` prefix** - the server determines your subscription level.
|
|
24
|
+
>
|
|
22
25
|
> **Free Trial**: All new scene keys include a 7-day free trial!
|
|
23
26
|
>
|
|
24
27
|
> **Expiry Warnings**: You'll receive dashboard notifications at 7, 3, and 1 days before your subscription expires.
|
|
@@ -35,16 +38,16 @@ If you need to rotate your API key (e.g., if compromised), you can do so from th
|
|
|
35
38
|
|
|
36
39
|
## Example Scene
|
|
37
40
|
|
|
38
|
-
Clone our
|
|
41
|
+
Clone our example scene to get started quickly:
|
|
39
42
|
|
|
40
43
|
```bash
|
|
41
|
-
git clone https://github.com/thestatic-tv/thestatic-dcl-
|
|
42
|
-
cd thestatic-dcl-
|
|
44
|
+
git clone https://github.com/thestatic-tv/thestatic-dcl-example.git
|
|
45
|
+
cd thestatic-dcl-example
|
|
43
46
|
npm install
|
|
44
47
|
npm start
|
|
45
48
|
```
|
|
46
49
|
|
|
47
|
-
See the [
|
|
50
|
+
See the [example repo](https://github.com/thestatic-tv/thestatic-dcl-example) for a complete working scene with video player integration.
|
|
48
51
|
|
|
49
52
|
## Installation
|
|
50
53
|
|
|
@@ -56,18 +59,24 @@ npm install @thestatic-tv/dcl-sdk
|
|
|
56
59
|
|
|
57
60
|
1. Get your API key from [thestatic.tv/dashboard](https://thestatic.tv/dashboard) (DCL Scenes tab)
|
|
58
61
|
|
|
59
|
-
2. Initialize the client in your scene:
|
|
62
|
+
2. Initialize the client in your scene's `main()` function:
|
|
60
63
|
|
|
61
64
|
```typescript
|
|
65
|
+
import {} from '@dcl/sdk/math'
|
|
66
|
+
import { engine } from '@dcl/sdk/ecs'
|
|
62
67
|
import { StaticTVClient } from '@thestatic-tv/dcl-sdk'
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
let staticTV: StaticTVClient
|
|
70
|
+
|
|
71
|
+
export function main() {
|
|
72
|
+
staticTV = new StaticTVClient({
|
|
73
|
+
apiKey: 'dcls_your_api_key_here'
|
|
74
|
+
})
|
|
75
|
+
// Session tracking starts automatically!
|
|
76
|
+
}
|
|
68
77
|
```
|
|
69
78
|
|
|
70
|
-
3. Fetch channels and display them:
|
|
79
|
+
3. Fetch channels and display them (Full mode only):
|
|
71
80
|
|
|
72
81
|
```typescript
|
|
73
82
|
// Get all channels
|
|
@@ -106,33 +115,40 @@ await staticTV.interactions.follow('channel-slug')
|
|
|
106
115
|
await staticTV.destroy()
|
|
107
116
|
```
|
|
108
117
|
|
|
109
|
-
##
|
|
118
|
+
## Free Tier (Visitor Tracking Only)
|
|
110
119
|
|
|
111
120
|
If you don't have a channel but want to track visitors to your scene:
|
|
112
121
|
|
|
113
122
|
1. Get a scene key from [thestatic.tv/dashboard](https://thestatic.tv/dashboard) (DCL Scenes tab)
|
|
114
123
|
|
|
115
|
-
2. Initialize with your scene key
|
|
124
|
+
2. Initialize with your scene key in `main()`:
|
|
116
125
|
|
|
117
126
|
```typescript
|
|
127
|
+
import {} from '@dcl/sdk/math'
|
|
128
|
+
import { engine } from '@dcl/sdk/ecs'
|
|
118
129
|
import { StaticTVClient } from '@thestatic-tv/dcl-sdk'
|
|
119
130
|
|
|
120
|
-
|
|
121
|
-
apiKey: 'dcls_your_scene_key_here'
|
|
122
|
-
})
|
|
131
|
+
let staticTV: StaticTVClient
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
|
|
133
|
+
export function main() {
|
|
134
|
+
staticTV = new StaticTVClient({
|
|
135
|
+
apiKey: 'dcls_your_scene_key_here'
|
|
136
|
+
})
|
|
137
|
+
// Session tracking starts automatically!
|
|
138
|
+
}
|
|
126
139
|
```
|
|
127
140
|
|
|
128
|
-
3. Check
|
|
141
|
+
3. Check the current tier:
|
|
129
142
|
|
|
130
143
|
```typescript
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
// Check tier (free, standard, or pro)
|
|
145
|
+
console.log('Current tier:', staticTV.tier)
|
|
146
|
+
|
|
147
|
+
if (staticTV.isFree) {
|
|
148
|
+
console.log('Running in free tier - session tracking only')
|
|
133
149
|
}
|
|
134
150
|
|
|
135
|
-
// guide, heartbeat, and interactions are null in
|
|
151
|
+
// guide, heartbeat, and interactions are null in free tier
|
|
136
152
|
if (staticTV.guide) {
|
|
137
153
|
const channels = await staticTV.guide.getChannels()
|
|
138
154
|
}
|
|
@@ -148,7 +164,7 @@ Main client class for interacting with thestatic.tv.
|
|
|
148
164
|
|
|
149
165
|
| Option | Type | Default | Description |
|
|
150
166
|
|--------|------|---------|-------------|
|
|
151
|
-
| `apiKey` | `string` | required | Your API key (
|
|
167
|
+
| `apiKey` | `string` | required | Your API key (all keys use `dcls_` prefix) |
|
|
152
168
|
| `autoStartSession` | `boolean` | `true` | Automatically start session tracking |
|
|
153
169
|
| `sessionHeartbeatInterval` | `number` | `30000` | Session heartbeat interval (ms) |
|
|
154
170
|
| `watchHeartbeatInterval` | `number` | `60000` | Watch heartbeat interval (ms) |
|
|
@@ -159,15 +175,28 @@ Main client class for interacting with thestatic.tv.
|
|
|
159
175
|
| Property | Type | Description |
|
|
160
176
|
|----------|------|-------------|
|
|
161
177
|
| `keyType` | `'channel' \| 'scene'` | The detected key type |
|
|
162
|
-
| `
|
|
163
|
-
| `
|
|
178
|
+
| `tier` | `'free' \| 'standard' \| 'pro'` | Current subscription tier |
|
|
179
|
+
| `isFree` | `boolean` | `true` if free tier (session tracking only) |
|
|
180
|
+
| `hasStandardFeatures` | `boolean` | `true` if standard features enabled |
|
|
181
|
+
| `hasProFeatures` | `boolean` | `true` if pro features enabled |
|
|
182
|
+
| `guide` | `GuideModule \| null` | Guide module (null in free tier) |
|
|
164
183
|
| `session` | `SessionModule` | Session module (always available) |
|
|
165
|
-
| `heartbeat` | `HeartbeatModule \| null` | Heartbeat module (null in
|
|
166
|
-
| `interactions` | `InteractionsModule \| null` | Interactions module (null in
|
|
167
|
-
| `guideUI` | `GuideUIModule \| null` | Guide UI module (null in
|
|
168
|
-
| `chatUI` | `ChatUIModule \| null` | Chat UI module (null in
|
|
184
|
+
| `heartbeat` | `HeartbeatModule \| null` | Heartbeat module (null in free tier) |
|
|
185
|
+
| `interactions` | `InteractionsModule \| null` | Interactions module (null in free tier) |
|
|
186
|
+
| `guideUI` | `GuideUIModule \| null` | Guide UI module (null in free tier) |
|
|
187
|
+
| `chatUI` | `ChatUIModule \| null` | Chat UI module (null in free tier) |
|
|
188
|
+
| `adminPanel` | `AdminPanelUIModule \| null` | Admin panel (null until enableProFeatures() called) |
|
|
189
|
+
| `isLite` | `boolean` | **Deprecated**: Use `isFree` instead |
|
|
169
190
|
|
|
170
|
-
|
|
191
|
+
#### Methods
|
|
192
|
+
|
|
193
|
+
| Method | Description |
|
|
194
|
+
|--------|-------------|
|
|
195
|
+
| `enableProFeatures(config)` | Enable Pro tier admin panel |
|
|
196
|
+
| `registerSceneTab(tab)` | Add custom scene tab (Pro tier) |
|
|
197
|
+
| `destroy()` | Cleanup before scene unload |
|
|
198
|
+
|
|
199
|
+
### Guide Module (Standard/Pro Tier)
|
|
171
200
|
|
|
172
201
|
```typescript
|
|
173
202
|
staticTV.guide.getChannels() // Get all channels (cached 30s)
|
|
@@ -186,9 +215,18 @@ staticTV.session.startSession() // Manually start session
|
|
|
186
215
|
staticTV.session.endSession() // End session
|
|
187
216
|
staticTV.session.getSessionId() // Get current session ID
|
|
188
217
|
staticTV.session.isSessionActive() // Check if session is active
|
|
218
|
+
|
|
219
|
+
// Get scene stats (visitors, sessions, etc.)
|
|
220
|
+
const stats = await staticTV.session.getStats()
|
|
221
|
+
if (stats) {
|
|
222
|
+
console.log('Total sessions today:', stats.totalSessions)
|
|
223
|
+
console.log('Unique visitors:', stats.uniqueVisitors)
|
|
224
|
+
console.log('Total minutes watched:', stats.totalMinutes)
|
|
225
|
+
console.log('You are visitor #', stats.visitorNumber)
|
|
226
|
+
}
|
|
189
227
|
```
|
|
190
228
|
|
|
191
|
-
### Heartbeat Module (
|
|
229
|
+
### Heartbeat Module (Standard/Pro Tier)
|
|
192
230
|
|
|
193
231
|
Track video watching. Each heartbeat represents 1 minute watched.
|
|
194
232
|
|
|
@@ -199,7 +237,7 @@ staticTV.heartbeat.getCurrentChannel() // Get currently watched channel
|
|
|
199
237
|
staticTV.heartbeat.isCurrentlyWatching() // Check if watching
|
|
200
238
|
```
|
|
201
239
|
|
|
202
|
-
### Interactions Module (
|
|
240
|
+
### Interactions Module (Standard/Pro Tier)
|
|
203
241
|
|
|
204
242
|
Like and follow channels. Requires wallet connection.
|
|
205
243
|
|
|
@@ -208,24 +246,27 @@ staticTV.interactions.like(channelSlug) // Like a channel
|
|
|
208
246
|
staticTV.interactions.follow(channelSlug) // Follow a channel
|
|
209
247
|
```
|
|
210
248
|
|
|
211
|
-
### Guide UI Module (
|
|
249
|
+
### Guide UI Module (Standard/Pro Tier)
|
|
212
250
|
|
|
213
251
|
Built-in channel browser UI. You provide a callback to handle video selection.
|
|
214
252
|
|
|
215
253
|
```typescript
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
254
|
+
let staticTV: StaticTVClient
|
|
255
|
+
|
|
256
|
+
export function main() {
|
|
257
|
+
staticTV = new StaticTVClient({
|
|
258
|
+
apiKey: 'dcls_your_api_key',
|
|
259
|
+
guideUI: {
|
|
260
|
+
onVideoSelect: (video) => {
|
|
261
|
+
// Handle video playback in your scene
|
|
262
|
+
console.log('Playing:', video.name, video.src)
|
|
263
|
+
}
|
|
223
264
|
}
|
|
224
|
-
}
|
|
225
|
-
})
|
|
265
|
+
})
|
|
226
266
|
|
|
227
|
-
// Initialize the UI (call once after client is created)
|
|
228
|
-
|
|
267
|
+
// Initialize the UI (call once after client is created)
|
|
268
|
+
staticTV.guideUI.init()
|
|
269
|
+
}
|
|
229
270
|
|
|
230
271
|
// Show/hide the guide
|
|
231
272
|
staticTV.guideUI.show()
|
|
@@ -242,22 +283,25 @@ staticTV.guideUI.currentVideoId = 'video-id'
|
|
|
242
283
|
await staticTV.guideUI.refresh()
|
|
243
284
|
```
|
|
244
285
|
|
|
245
|
-
### Chat UI Module (
|
|
286
|
+
### Chat UI Module (Standard/Pro Tier)
|
|
246
287
|
|
|
247
288
|
Real-time chat with Firebase authentication.
|
|
248
289
|
|
|
249
290
|
```typescript
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
291
|
+
let staticTV: StaticTVClient
|
|
292
|
+
|
|
293
|
+
export function main() {
|
|
294
|
+
staticTV = new StaticTVClient({
|
|
295
|
+
apiKey: 'dcls_your_api_key',
|
|
296
|
+
chatUI: {
|
|
297
|
+
position: 'right', // 'left', 'center', or 'right'
|
|
298
|
+
fontScale: 1.0
|
|
299
|
+
}
|
|
300
|
+
})
|
|
258
301
|
|
|
259
|
-
// Initialize the chat (call once after client is created)
|
|
260
|
-
|
|
302
|
+
// Initialize the chat (call once after client is created)
|
|
303
|
+
staticTV.chatUI.init()
|
|
304
|
+
}
|
|
261
305
|
|
|
262
306
|
// Show/hide the chat
|
|
263
307
|
staticTV.chatUI.show()
|
|
@@ -274,23 +318,131 @@ const unread = staticTV.chatUI.unreadCount
|
|
|
274
318
|
staticTV.chatUI.setChannel('channel-slug')
|
|
275
319
|
```
|
|
276
320
|
|
|
277
|
-
###
|
|
321
|
+
### Admin Panel Module (Pro Tier)
|
|
278
322
|
|
|
279
|
-
|
|
323
|
+
In-scene admin panel with Video and Mod tabs. Allows scene owners/admins to:
|
|
324
|
+
- Control live streaming (start/stop, rotate keys)
|
|
325
|
+
- Play videos from URL or predefined slots
|
|
326
|
+
- Manage scene admins and banned wallets
|
|
327
|
+
- Send broadcast messages to all players
|
|
280
328
|
|
|
281
329
|
```typescript
|
|
282
|
-
import {
|
|
330
|
+
import { StaticTVClient } from '@thestatic-tv/dcl-sdk'
|
|
331
|
+
import ReactEcs, { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
|
|
332
|
+
|
|
333
|
+
let staticTV: StaticTVClient
|
|
334
|
+
|
|
335
|
+
export function main() {
|
|
336
|
+
staticTV = new StaticTVClient({
|
|
337
|
+
apiKey: 'dcls_your_api_key'
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
// Enable admin panel (Pro tier)
|
|
341
|
+
staticTV.enableProFeatures({
|
|
342
|
+
// sceneId is optional - defaults to your API key ID
|
|
343
|
+
title: 'MY SCENE ADMIN', // Panel header title
|
|
344
|
+
onVideoPlay: (url) => {
|
|
345
|
+
// Handle video playback in your scene
|
|
346
|
+
videoPlayer.play(url)
|
|
347
|
+
},
|
|
348
|
+
onVideoStop: () => {
|
|
349
|
+
videoPlayer.stop()
|
|
350
|
+
},
|
|
351
|
+
onVideoSlotPlay: (slot) => {
|
|
352
|
+
// Play a predefined video slot (slot1-slot5)
|
|
353
|
+
fetchAndPlaySlot(slot)
|
|
354
|
+
},
|
|
355
|
+
onBroadcast: (text) => {
|
|
356
|
+
// Show notification to all players
|
|
357
|
+
showNotification(text)
|
|
358
|
+
},
|
|
359
|
+
onCommand: (type, payload) => {
|
|
360
|
+
// Handle custom commands (kickAll, kickBanned, etc.)
|
|
361
|
+
handleCommand(type, payload)
|
|
362
|
+
}
|
|
363
|
+
})
|
|
364
|
+
}
|
|
283
365
|
|
|
284
|
-
//
|
|
366
|
+
// Render the admin panel
|
|
285
367
|
ReactEcsRenderer.setUiRenderer(() => {
|
|
286
|
-
return (
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
368
|
+
return staticTV.adminPanel?.getComponent()
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
// Toggle panel visibility
|
|
372
|
+
staticTV.adminPanel.toggle()
|
|
373
|
+
|
|
374
|
+
// Check if user has admin access
|
|
375
|
+
if (staticTV.adminPanel.hasAccess) { ... }
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### Admin Panel Configuration Options
|
|
379
|
+
|
|
380
|
+
| Option | Type | Default | Description |
|
|
381
|
+
|--------|------|---------|-------------|
|
|
382
|
+
| `sceneId` | `string` | API key ID | Scene ID for API calls (optional - defaults to your API key ID) |
|
|
383
|
+
| `title` | `string` | `'ADMIN PANEL'` | Header title |
|
|
384
|
+
| `headerColor` | `{r,g,b,a}` | red | Header background color |
|
|
385
|
+
| `showVideoTab` | `boolean` | `true` | Show Video tab |
|
|
386
|
+
| `showModTab` | `boolean` | `true` | Show Mod tab (owners only) |
|
|
387
|
+
| `onVideoPlay` | `(url) => void` | - | Called when video should play |
|
|
388
|
+
| `onVideoStop` | `() => void` | - | Called when video should stop |
|
|
389
|
+
| `onVideoSlotPlay` | `(slot) => void` | - | Called when slot is selected |
|
|
390
|
+
| `onBroadcast` | `(text) => void` | - | Called for broadcast messages |
|
|
391
|
+
| `onCommand` | `(type, payload) => void` | - | Called for custom commands |
|
|
392
|
+
| `footerLink` | `string` | scene page | Link shown in footer |
|
|
393
|
+
| `debug` | `boolean` | `false` | Enable debug logging |
|
|
394
|
+
|
|
395
|
+
### Custom Scene Tabs (Pro Tier)
|
|
396
|
+
|
|
397
|
+
Add your own scene-specific control tabs to the admin panel:
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
import ReactEcs, { UiEntity, Button, Label } from '@dcl/sdk/react-ecs'
|
|
401
|
+
|
|
402
|
+
// Enable pro features first
|
|
403
|
+
staticTV.enableProFeatures({ sceneId: 'my-scene', ... })
|
|
404
|
+
|
|
405
|
+
// Register custom tabs
|
|
406
|
+
staticTV.registerSceneTab({
|
|
407
|
+
label: 'LIGHTS',
|
|
408
|
+
id: 'lights',
|
|
409
|
+
render: () => (
|
|
410
|
+
<UiEntity uiTransform={{ flexDirection: 'column', padding: 8 }}>
|
|
411
|
+
<Label value="Light Controls" fontSize={14} />
|
|
412
|
+
<Button value="Disco Mode" onMouseDown={() => setDiscoLights()} />
|
|
413
|
+
<Button value="Ambient" onMouseDown={() => setAmbientLights()} />
|
|
414
|
+
<Button value="Off" onMouseDown={() => turnOffLights()} />
|
|
415
|
+
</UiEntity>
|
|
292
416
|
)
|
|
293
417
|
})
|
|
418
|
+
|
|
419
|
+
staticTV.registerSceneTab({
|
|
420
|
+
label: 'DOORS',
|
|
421
|
+
id: 'doors',
|
|
422
|
+
render: () => <MyDoorsControls />
|
|
423
|
+
})
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Custom tabs appear before the Video and Mod tabs in the tab bar.
|
|
427
|
+
|
|
428
|
+
### Rendering UI Components
|
|
429
|
+
|
|
430
|
+
The UI modules provide `getComponent()` methods that return React-ECS elements. Add the renderer **outside** your `main()` function:
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
import ReactEcs, { ReactEcsRenderer, UiEntity } from '@dcl/sdk/react-ecs'
|
|
434
|
+
|
|
435
|
+
// Outside main() - required by DCL
|
|
436
|
+
ReactEcsRenderer.setUiRenderer(() => {
|
|
437
|
+
if (!staticTV) return null
|
|
438
|
+
return ReactEcs.createElement(UiEntity, {
|
|
439
|
+
uiTransform: { width: '100%', height: '100%', positionType: 'absolute' },
|
|
440
|
+
children: [
|
|
441
|
+
staticTV.guideUI?.getComponent(),
|
|
442
|
+
staticTV.chatUI?.getComponent()
|
|
443
|
+
].filter(Boolean)
|
|
444
|
+
})
|
|
445
|
+
})
|
|
294
446
|
```
|
|
295
447
|
|
|
296
448
|
## Metrics Attribution
|