@thestatic-tv/dcl-sdk 1.0.2 → 1.0.4

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/dist/index.d.mts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Player identity data from DCL
3
+ */
4
+ interface PlayerData {
5
+ /** Player's wallet address (userId from DCL) */
6
+ wallet?: string;
7
+ /** Player's display name */
8
+ name?: string;
9
+ }
1
10
  /**
2
11
  * Configuration options for StaticTVClient
3
12
  */
@@ -14,6 +23,17 @@ interface StaticTVConfig {
14
23
  debug?: boolean;
15
24
  /** Custom API base URL (default: https://thestatic.tv/api/v1/dcl) */
16
25
  baseUrl?: string;
26
+ /**
27
+ * Player data from DCL - pass from your scene's getPlayer() call
28
+ * @example
29
+ * import { getPlayer } from '@dcl/sdk/players'
30
+ * const player = getPlayer()
31
+ * new StaticTVClient({
32
+ * apiKey: 'dcls_...',
33
+ * player: { wallet: player?.userId, name: player?.name }
34
+ * })
35
+ */
36
+ player?: PlayerData;
17
37
  }
18
38
  /**
19
39
  * Channel information from the guide
@@ -148,20 +168,28 @@ declare class GuideModule {
148
168
  declare class SessionModule {
149
169
  private client;
150
170
  private sessionId;
151
- private heartbeatInterval;
171
+ private heartbeatTimerId;
152
172
  private isActive;
153
173
  constructor(client: StaticTVClient);
154
174
  /**
155
175
  * Get the appropriate session endpoint based on key type
156
176
  */
157
177
  private getEndpoint;
178
+ /**
179
+ * Get player wallet - prioritize config, fallback to runtime detection
180
+ */
181
+ private getWallet;
182
+ /**
183
+ * Get player display name - prioritize config, fallback to runtime detection
184
+ */
185
+ private getDisplayName;
158
186
  /**
159
187
  * Start a new session
160
188
  * Called automatically if autoStartSession is true
161
189
  */
162
190
  startSession(metadata?: Record<string, unknown>): Promise<string | null>;
163
191
  /**
164
- * Start the heartbeat interval
192
+ * Start the heartbeat interval using DCL-compatible timer
165
193
  */
166
194
  private startHeartbeat;
167
195
  /**
@@ -193,7 +221,7 @@ declare class SessionModule {
193
221
 
194
222
  declare class HeartbeatModule {
195
223
  private client;
196
- private watchInterval;
224
+ private watchTimerId;
197
225
  private currentChannel;
198
226
  private isWatching;
199
227
  constructor(client: StaticTVClient);
@@ -208,6 +236,10 @@ declare class HeartbeatModule {
208
236
  * Stop tracking video watching
209
237
  */
210
238
  stopWatching(): void;
239
+ /**
240
+ * Get player wallet - prioritize config, fallback to runtime detection
241
+ */
242
+ private getWallet;
211
243
  /**
212
244
  * Send a watching heartbeat (1 heartbeat = 1 minute watched)
213
245
  */
package/dist/index.d.ts CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Player identity data from DCL
3
+ */
4
+ interface PlayerData {
5
+ /** Player's wallet address (userId from DCL) */
6
+ wallet?: string;
7
+ /** Player's display name */
8
+ name?: string;
9
+ }
1
10
  /**
2
11
  * Configuration options for StaticTVClient
3
12
  */
@@ -14,6 +23,17 @@ interface StaticTVConfig {
14
23
  debug?: boolean;
15
24
  /** Custom API base URL (default: https://thestatic.tv/api/v1/dcl) */
16
25
  baseUrl?: string;
26
+ /**
27
+ * Player data from DCL - pass from your scene's getPlayer() call
28
+ * @example
29
+ * import { getPlayer } from '@dcl/sdk/players'
30
+ * const player = getPlayer()
31
+ * new StaticTVClient({
32
+ * apiKey: 'dcls_...',
33
+ * player: { wallet: player?.userId, name: player?.name }
34
+ * })
35
+ */
36
+ player?: PlayerData;
17
37
  }
18
38
  /**
19
39
  * Channel information from the guide
@@ -148,20 +168,28 @@ declare class GuideModule {
148
168
  declare class SessionModule {
149
169
  private client;
150
170
  private sessionId;
151
- private heartbeatInterval;
171
+ private heartbeatTimerId;
152
172
  private isActive;
153
173
  constructor(client: StaticTVClient);
154
174
  /**
155
175
  * Get the appropriate session endpoint based on key type
156
176
  */
157
177
  private getEndpoint;
178
+ /**
179
+ * Get player wallet - prioritize config, fallback to runtime detection
180
+ */
181
+ private getWallet;
182
+ /**
183
+ * Get player display name - prioritize config, fallback to runtime detection
184
+ */
185
+ private getDisplayName;
158
186
  /**
159
187
  * Start a new session
160
188
  * Called automatically if autoStartSession is true
161
189
  */
162
190
  startSession(metadata?: Record<string, unknown>): Promise<string | null>;
163
191
  /**
164
- * Start the heartbeat interval
192
+ * Start the heartbeat interval using DCL-compatible timer
165
193
  */
166
194
  private startHeartbeat;
167
195
  /**
@@ -193,7 +221,7 @@ declare class SessionModule {
193
221
 
194
222
  declare class HeartbeatModule {
195
223
  private client;
196
- private watchInterval;
224
+ private watchTimerId;
197
225
  private currentChannel;
198
226
  private isWatching;
199
227
  constructor(client: StaticTVClient);
@@ -208,6 +236,10 @@ declare class HeartbeatModule {
208
236
  * Stop tracking video watching
209
237
  */
210
238
  stopWatching(): void;
239
+ /**
240
+ * Get player wallet - prioritize config, fallback to runtime detection
241
+ */
242
+ private getWallet;
211
243
  /**
212
244
  * Send a watching heartbeat (1 heartbeat = 1 minute watched)
213
245
  */
package/dist/index.js CHANGED
@@ -116,11 +116,54 @@ function getPlayerDisplayName() {
116
116
  }
117
117
  }
118
118
 
119
+ // src/utils/timer.ts
120
+ var import_ecs = require("@dcl/sdk/ecs");
121
+ var nextTimerId = 1;
122
+ var timers = /* @__PURE__ */ new Map();
123
+ var systemAdded = false;
124
+ function ensureTimerSystem() {
125
+ if (systemAdded) return;
126
+ import_ecs.engine.addSystem((dt) => {
127
+ for (const timer of timers.values()) {
128
+ if (!timer.active) continue;
129
+ timer.elapsedTime += dt;
130
+ if (timer.elapsedTime >= timer.intervalSeconds) {
131
+ timer.elapsedTime = 0;
132
+ try {
133
+ timer.callback();
134
+ } catch (e) {
135
+ console.error("[StaticTV Timer] Callback error:", e);
136
+ }
137
+ }
138
+ }
139
+ });
140
+ systemAdded = true;
141
+ }
142
+ function dclSetInterval(callback, intervalMs) {
143
+ ensureTimerSystem();
144
+ const id = nextTimerId++;
145
+ timers.set(id, {
146
+ id,
147
+ callback,
148
+ intervalSeconds: intervalMs / 1e3,
149
+ elapsedTime: 0,
150
+ active: true
151
+ });
152
+ return id;
153
+ }
154
+ function dclClearInterval(timerId) {
155
+ const timer = timers.get(timerId);
156
+ if (timer) {
157
+ timer.active = false;
158
+ timers.delete(timerId);
159
+ }
160
+ }
161
+
119
162
  // src/modules/session.ts
120
163
  var SessionModule = class {
121
164
  constructor(client) {
122
165
  this.sessionId = null;
123
- this.heartbeatInterval = null;
166
+ this.heartbeatTimerId = null;
124
167
  this.isActive = false;
125
168
  this.client = client;
126
169
  }
@@ -130,6 +173,20 @@ var SessionModule = class {
130
173
  getEndpoint() {
131
174
  return this.client.isLite ? "/scene-session" : "/session";
132
175
  }
176
+ /**
177
+ * Get player wallet - prioritize config, fallback to runtime detection
178
+ */
179
+ getWallet() {
180
+ const config = this.client.getConfig();
181
+ return config.player?.wallet || getPlayerWallet();
182
+ }
183
+ /**
184
+ * Get player display name - prioritize config, fallback to runtime detection
185
+ */
186
+ getDisplayName() {
187
+ const config = this.client.getConfig();
188
+ return config.player?.name || getPlayerDisplayName();
189
+ }
133
190
  /**
134
191
  * Start a new session
135
192
  * Called automatically if autoStartSession is true
@@ -140,12 +197,15 @@ var SessionModule = class {
140
197
  return this.sessionId;
141
198
  }
142
199
  try {
200
+ const walletAddress = this.getWallet();
201
+ const dclDisplayName = this.getDisplayName();
202
+ this.client.log(`Starting session with wallet: ${walletAddress}, name: ${dclDisplayName}`);
143
203
  const response = await this.client.request(this.getEndpoint(), {
144
204
  method: "POST",
145
205
  body: JSON.stringify({
146
206
  action: "enter",
147
- walletAddress: getPlayerWallet(),
148
- dclDisplayName: getPlayerDisplayName(),
207
+ walletAddress,
208
+ dclDisplayName,
149
209
  metadata
150
210
  })
151
211
  });
@@ -163,12 +223,12 @@ var SessionModule = class {
163
223
  }
164
224
  }
165
225
  /**
166
- * Start the heartbeat interval
226
+ * Start the heartbeat interval using DCL-compatible timer
167
227
  */
168
228
  startHeartbeat() {
169
- if (this.heartbeatInterval) return;
229
+ if (this.heartbeatTimerId !== null) return;
170
230
  const interval = this.client.getConfig().sessionHeartbeatInterval || 3e4;
171
- this.heartbeatInterval = setInterval(() => {
231
+ this.heartbeatTimerId = dclSetInterval(() => {
172
232
  this.sendHeartbeat();
173
233
  }, interval);
174
234
  }
@@ -195,9 +255,9 @@ var SessionModule = class {
195
255
  */
196
256
  async endSession() {
197
257
  if (!this.isActive) return;
198
- if (this.heartbeatInterval) {
199
- clearInterval(this.heartbeatInterval);
200
- this.heartbeatInterval = null;
258
+ if (this.heartbeatTimerId !== null) {
259
+ dclClearInterval(this.heartbeatTimerId);
260
+ this.heartbeatTimerId = null;
201
261
  }
202
262
  if (this.sessionId) {
203
263
  try {
@@ -234,7 +294,7 @@ var SessionModule = class {
234
294
  */
235
295
  async getStats() {
236
296
  try {
237
- const wallet = getPlayerWallet();
297
+ const wallet = this.getWallet();
238
298
  const queryParam = wallet ? `?wallet=${wallet}` : "";
239
299
  const response = await this.client.request(
240
300
  `/scene-stats${queryParam}`,
@@ -255,7 +315,7 @@ var SessionModule = class {
255
315
  // src/modules/heartbeat.ts
256
316
  var HeartbeatModule = class {
257
317
  constructor(client) {
258
- this.watchInterval = null;
318
+ this.watchTimerId = null;
259
319
  this.currentChannel = null;
260
320
  this.isWatching = false;
261
321
  this.client = client;
@@ -278,7 +338,7 @@ var HeartbeatModule = class {
278
338
  this.isWatching = true;
279
339
  this.sendHeartbeat();
280
340
  const interval = this.client.getConfig().watchHeartbeatInterval || 6e4;
281
- this.watchInterval = setInterval(() => {
341
+ this.watchTimerId = dclSetInterval(() => {
282
342
  this.sendHeartbeat();
283
343
  }, interval);
284
344
  this.client.log(`Started watching ${channelSlug}`);
@@ -288,14 +348,21 @@ var HeartbeatModule = class {
288
348
  */
289
349
  stopWatching() {
290
350
  if (!this.isWatching) return;
291
- if (this.watchInterval) {
292
- clearInterval(this.watchInterval);
293
- this.watchInterval = null;
351
+ if (this.watchTimerId !== null) {
352
+ dclClearInterval(this.watchTimerId);
353
+ this.watchTimerId = null;
294
354
  }
295
355
  this.client.log(`Stopped watching ${this.currentChannel}`);
296
356
  this.currentChannel = null;
297
357
  this.isWatching = false;
298
358
  }
359
+ /**
360
+ * Get player wallet - prioritize config, fallback to runtime detection
361
+ */
362
+ getWallet() {
363
+ const config = this.client.getConfig();
364
+ return config.player?.wallet || getPlayerWallet();
365
+ }
299
366
  /**
300
367
  * Send a watching heartbeat (1 heartbeat = 1 minute watched)
301
368
  */
@@ -307,7 +374,7 @@ var HeartbeatModule = class {
307
374
  method: "POST",
308
375
  body: JSON.stringify({
309
376
  channelSlug: this.currentChannel,
310
- walletAddress: getPlayerWallet(),
377
+ walletAddress: this.getWallet(),
311
378
  sessionId
312
379
  })
313
380
  });
package/dist/index.mjs CHANGED
@@ -91,11 +91,54 @@ function getPlayerDisplayName() {
91
91
  }
92
92
  }
93
93
 
94
+ // src/utils/timer.ts
95
+ import { engine } from "@dcl/sdk/ecs";
96
+ var nextTimerId = 1;
97
+ var timers = /* @__PURE__ */ new Map();
98
+ var systemAdded = false;
99
+ function ensureTimerSystem() {
100
+ if (systemAdded) return;
101
+ engine.addSystem((dt) => {
102
+ for (const timer of timers.values()) {
103
+ if (!timer.active) continue;
104
+ timer.elapsedTime += dt;
105
+ if (timer.elapsedTime >= timer.intervalSeconds) {
106
+ timer.elapsedTime = 0;
107
+ try {
108
+ timer.callback();
109
+ } catch (e) {
110
+ console.error("[StaticTV Timer] Callback error:", e);
111
+ }
112
+ }
113
+ }
114
+ });
115
+ systemAdded = true;
116
+ }
117
+ function dclSetInterval(callback, intervalMs) {
118
+ ensureTimerSystem();
119
+ const id = nextTimerId++;
120
+ timers.set(id, {
121
+ id,
122
+ callback,
123
+ intervalSeconds: intervalMs / 1e3,
124
+ elapsedTime: 0,
125
+ active: true
126
+ });
127
+ return id;
128
+ }
129
+ function dclClearInterval(timerId) {
130
+ const timer = timers.get(timerId);
131
+ if (timer) {
132
+ timer.active = false;
133
+ timers.delete(timerId);
134
+ }
135
+ }
136
+
94
137
  // src/modules/session.ts
95
138
  var SessionModule = class {
96
139
  constructor(client) {
97
140
  this.sessionId = null;
98
- this.heartbeatInterval = null;
141
+ this.heartbeatTimerId = null;
99
142
  this.isActive = false;
100
143
  this.client = client;
101
144
  }
@@ -105,6 +148,20 @@ var SessionModule = class {
105
148
  getEndpoint() {
106
149
  return this.client.isLite ? "/scene-session" : "/session";
107
150
  }
151
+ /**
152
+ * Get player wallet - prioritize config, fallback to runtime detection
153
+ */
154
+ getWallet() {
155
+ const config = this.client.getConfig();
156
+ return config.player?.wallet || getPlayerWallet();
157
+ }
158
+ /**
159
+ * Get player display name - prioritize config, fallback to runtime detection
160
+ */
161
+ getDisplayName() {
162
+ const config = this.client.getConfig();
163
+ return config.player?.name || getPlayerDisplayName();
164
+ }
108
165
  /**
109
166
  * Start a new session
110
167
  * Called automatically if autoStartSession is true
@@ -115,12 +172,15 @@ var SessionModule = class {
115
172
  return this.sessionId;
116
173
  }
117
174
  try {
175
+ const walletAddress = this.getWallet();
176
+ const dclDisplayName = this.getDisplayName();
177
+ this.client.log(`Starting session with wallet: ${walletAddress}, name: ${dclDisplayName}`);
118
178
  const response = await this.client.request(this.getEndpoint(), {
119
179
  method: "POST",
120
180
  body: JSON.stringify({
121
181
  action: "enter",
122
- walletAddress: getPlayerWallet(),
123
- dclDisplayName: getPlayerDisplayName(),
182
+ walletAddress,
183
+ dclDisplayName,
124
184
  metadata
125
185
  })
126
186
  });
@@ -138,12 +198,12 @@ var SessionModule = class {
138
198
  }
139
199
  }
140
200
  /**
141
- * Start the heartbeat interval
201
+ * Start the heartbeat interval using DCL-compatible timer
142
202
  */
143
203
  startHeartbeat() {
144
- if (this.heartbeatInterval) return;
204
+ if (this.heartbeatTimerId !== null) return;
145
205
  const interval = this.client.getConfig().sessionHeartbeatInterval || 3e4;
146
- this.heartbeatInterval = setInterval(() => {
206
+ this.heartbeatTimerId = dclSetInterval(() => {
147
207
  this.sendHeartbeat();
148
208
  }, interval);
149
209
  }
@@ -170,9 +230,9 @@ var SessionModule = class {
170
230
  */
171
231
  async endSession() {
172
232
  if (!this.isActive) return;
173
- if (this.heartbeatInterval) {
174
- clearInterval(this.heartbeatInterval);
175
- this.heartbeatInterval = null;
233
+ if (this.heartbeatTimerId !== null) {
234
+ dclClearInterval(this.heartbeatTimerId);
235
+ this.heartbeatTimerId = null;
176
236
  }
177
237
  if (this.sessionId) {
178
238
  try {
@@ -209,7 +269,7 @@ var SessionModule = class {
209
269
  */
210
270
  async getStats() {
211
271
  try {
212
- const wallet = getPlayerWallet();
272
+ const wallet = this.getWallet();
213
273
  const queryParam = wallet ? `?wallet=${wallet}` : "";
214
274
  const response = await this.client.request(
215
275
  `/scene-stats${queryParam}`,
@@ -230,7 +290,7 @@ var SessionModule = class {
230
290
  // src/modules/heartbeat.ts
231
291
  var HeartbeatModule = class {
232
292
  constructor(client) {
233
- this.watchInterval = null;
293
+ this.watchTimerId = null;
234
294
  this.currentChannel = null;
235
295
  this.isWatching = false;
236
296
  this.client = client;
@@ -253,7 +313,7 @@ var HeartbeatModule = class {
253
313
  this.isWatching = true;
254
314
  this.sendHeartbeat();
255
315
  const interval = this.client.getConfig().watchHeartbeatInterval || 6e4;
256
- this.watchInterval = setInterval(() => {
316
+ this.watchTimerId = dclSetInterval(() => {
257
317
  this.sendHeartbeat();
258
318
  }, interval);
259
319
  this.client.log(`Started watching ${channelSlug}`);
@@ -263,14 +323,21 @@ var HeartbeatModule = class {
263
323
  */
264
324
  stopWatching() {
265
325
  if (!this.isWatching) return;
266
- if (this.watchInterval) {
267
- clearInterval(this.watchInterval);
268
- this.watchInterval = null;
326
+ if (this.watchTimerId !== null) {
327
+ dclClearInterval(this.watchTimerId);
328
+ this.watchTimerId = null;
269
329
  }
270
330
  this.client.log(`Stopped watching ${this.currentChannel}`);
271
331
  this.currentChannel = null;
272
332
  this.isWatching = false;
273
333
  }
334
+ /**
335
+ * Get player wallet - prioritize config, fallback to runtime detection
336
+ */
337
+ getWallet() {
338
+ const config = this.client.getConfig();
339
+ return config.player?.wallet || getPlayerWallet();
340
+ }
274
341
  /**
275
342
  * Send a watching heartbeat (1 heartbeat = 1 minute watched)
276
343
  */
@@ -282,7 +349,7 @@ var HeartbeatModule = class {
282
349
  method: "POST",
283
350
  body: JSON.stringify({
284
351
  channelSlug: this.currentChannel,
285
- walletAddress: getPlayerWallet(),
352
+ walletAddress: this.getWallet(),
286
353
  sessionId
287
354
  })
288
355
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thestatic-tv/dcl-sdk",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Connect your Decentraland scene to thestatic.tv - full channel lineup, metrics tracking, and interactions",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",