anear-js-api 2.1.1 → 2.2.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.
@@ -42,14 +42,12 @@ class AssetFileCollector {
42
42
  await this.walkDirectory(fullPath, filesData);
43
43
  } else if (entry.isFile()) {
44
44
  const relativePath = path.relative(this.baseDir, fullPath).replace(/\\/g, '/'); // Ensure forward slashes
45
- const stat = await fs.stat(fullPath)
46
45
  const contentHash = await this.computeFileHash(fullPath);
47
46
  const contentType = this.getContentType(fullPath);
48
47
  filesData.push({
49
48
  path: relativePath,
50
49
  content_hash: contentHash,
51
50
  content_type: contentType,
52
- mtime_ms: stat.mtimeMs,
53
51
  });
54
52
  }
55
53
  }
@@ -50,7 +50,7 @@ class DisplayEventProcessor {
50
50
  this.participantsActionTimeout = anearEventMachineContext.participantsActionTimeout
51
51
  this.pugTemplates = anearEventMachineContext.pugTemplates
52
52
  this.pugHelpers = anearEventMachineContext.pugHelpers
53
- this.participantMachines = anearEventMachineContext.participantMachines
53
+ this.participantPrivateChannels = anearEventMachineContext.participantPrivateChannels || {}
54
54
  this.participantsDisplayChannel = anearEventMachineContext.participantsDisplayChannel
55
55
  this.spectatorsDisplayChannel = anearEventMachineContext.spectatorsDisplayChannel
56
56
  this.participants = anearEventMachineContext.participants
@@ -329,32 +329,23 @@ class DisplayEventProcessor {
329
329
  }
330
330
 
331
331
  const hostId = hostEntry[0];
332
- const hostMachine = this.participantMachines[hostId]
333
-
334
- if (!hostMachine) {
335
- throw new Error(`[DisplayEventProcessor] Host participant machine not found for hostId: ${hostId}`)
332
+ const hostChannel = this.participantPrivateChannels[hostId]
333
+ if (!hostChannel) {
334
+ throw new Error(`[DisplayEventProcessor] Host private channel not found for hostId: ${hostId}`)
336
335
  }
337
- this._sendPrivateDisplay(hostMachine, hostId, template, templateRenderContext, timeoutFn, anchor, type, targetsArray, content, contentType)
338
- return Promise.resolve()
336
+ return this._sendPrivateDisplay(hostChannel, hostId, template, templateRenderContext, timeoutFn, anchor, type, targetsArray, content, contentType)
339
337
  }
340
338
 
341
339
  _processPrivateParticipantDisplays(template, templateRenderContext, timeoutFn, anchor = null, type = null, targetsArray = null, content = null, contentType = null) {
342
- Object.values(this.participantsIndex.all).forEach(
343
- participantStruct => {
344
- if (participantStruct.info.isHost) return;
345
- if (participantStruct.info.active === false) return;
346
-
340
+ return Promise.all(
341
+ Object.values(this.participantsIndex.all).map(participantStruct => {
342
+ if (participantStruct.info.isHost || participantStruct.info.active === false) return Promise.resolve()
347
343
  const participantId = participantStruct.info.id
348
- const participantMachine = this.participantMachines[participantId]
349
- if (!participantMachine) {
350
- logger.warn(`[DisplayEventProcessor] Participant machine not found for ${participantId}, skipping display`)
351
- return
352
- }
353
- this._sendPrivateDisplay(participantMachine, participantId, template, templateRenderContext, timeoutFn, anchor, type, targetsArray, content, contentType)
354
- }
344
+ const participantChannel = this.participantPrivateChannels[participantId]
345
+ if (!participantChannel) return Promise.resolve()
346
+ return this._sendPrivateDisplay(participantChannel, participantId, template, templateRenderContext, timeoutFn, anchor, type, targetsArray, content, contentType)
347
+ })
355
348
  )
356
-
357
- return Promise.resolve()
358
349
  }
359
350
 
360
351
  /**
@@ -380,9 +371,9 @@ class DisplayEventProcessor {
380
371
  return { promise: Promise.resolve(), displaySent: false }
381
372
  }
382
373
 
383
- const participantMachine = this.participantMachines[participantId]
384
- if (!participantMachine) {
385
- logger.debug(`[DisplayEventProcessor] Participant machine not found for ${participantId} (exited); treating as delivered`)
374
+ const participantChannel = this.participantPrivateChannels[participantId]
375
+ if (!participantChannel) {
376
+ logger.debug(`[DisplayEventProcessor] Participant private channel not found for ${participantId} (exited); treating as delivered`)
386
377
  return { promise: Promise.resolve(), displaySent: false }
387
378
  }
388
379
 
@@ -390,8 +381,8 @@ class DisplayEventProcessor {
390
381
  () => displayTimeout :
391
382
  timeoutFn
392
383
 
393
- this._sendPrivateDisplay(participantMachine, participantId, template, templateRenderContext, effectiveTimeoutFn, anchor, type, targetsArray, content, contentType)
394
- return { promise: Promise.resolve(), displaySent: true }
384
+ const promise = this._sendPrivateDisplay(participantChannel, participantId, template, templateRenderContext, effectiveTimeoutFn, anchor, type, targetsArray, content, contentType)
385
+ return { promise, displaySent: true }
395
386
  }
396
387
 
397
388
  _processSelectiveParticipantDisplay(template, templateRenderContext, timeoutFn, participantId, displayTimeout = null, anchor = null, type = null, targetsArray = null, content = null, contentType = null) {
@@ -399,7 +390,7 @@ class DisplayEventProcessor {
399
390
  return promise
400
391
  }
401
392
 
402
- _sendPrivateDisplay(participantMachine, participantId, template, templateRenderContext, timeoutFn, anchor = null, type = null, targetsArray = null, content = null, contentType = null) {
393
+ _sendPrivateDisplay(participantChannel, participantId, template, templateRenderContext, timeoutFn, anchor = null, type = null, targetsArray = null, content = null, contentType = null) {
403
394
  let timeout = null
404
395
 
405
396
  const participantStruct = this.participantsIndex.get(participantId)
@@ -435,18 +426,7 @@ class DisplayEventProcessor {
435
426
  const remainingMsecs = Math.max(0, pat.msecs - (now - start))
436
427
  visualTimeout = { msecs: pat.msecs, remainingMsecs }
437
428
  } else {
438
- const state = participantMachine?.state
439
- const ctx = state?.context
440
- if (ctx && ctx.actionTimeoutStart && ctx.actionTimeoutMsecs != null && ctx.actionTimeoutMsecs > 0) {
441
- const now = Date.now()
442
- const elapsed = now - ctx.actionTimeoutStart
443
- const remaining = ctx.actionTimeoutMsecs - elapsed
444
- const remainingMsecs = remaining > 0 ? remaining : 0
445
- visualTimeout = {
446
- msecs: ctx.actionTimeoutMsecs,
447
- remainingMsecs
448
- }
449
- } else if (timeout !== null) {
429
+ if (timeout !== null) {
450
430
  visualTimeout = { msecs: timeout, remainingMsecs: timeout }
451
431
  }
452
432
  }
@@ -493,7 +473,8 @@ class DisplayEventProcessor {
493
473
  renderMessage.timeout = timeout
494
474
  }
495
475
 
496
- participantMachine.send({ type: 'RENDER_DISPLAY', ...renderMessage })
476
+ EventStats.recordPublish(this.eventStats, participantChannel, 'PRIVATE_DISPLAY', renderMessage)
477
+ return RealtimeMessaging.publish(participantChannel, 'PRIVATE_DISPLAY', renderMessage)
497
478
  }
498
479
 
499
480
  _normalizeAnchorUpdateType(type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anear-js-api",
3
- "version": "2.1.1",
3
+ "version": "2.2.1",
4
4
  "description": "Javascript Developer API for Anear Apps",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -1,13 +1,17 @@
1
1
  const DisplayEventProcessor = require('../lib/utils/DisplayEventProcessor')
2
+ const RealtimeMessaging = require('../lib/utils/RealtimeMessaging')
3
+
4
+ jest.mock('../lib/utils/RealtimeMessaging', () => ({
5
+ publish: jest.fn(() => Promise.resolve())
6
+ }))
2
7
 
3
8
  const makeProcessor = (overrides = {}) => {
4
- const participantMachine = { send: jest.fn(), state: { context: {} } }
5
9
  const baseContext = {
6
10
  anearEvent: {},
7
11
  participantsActionTimeout: null,
8
12
  pugTemplates: {},
9
13
  pugHelpers: {},
10
- participantMachines: { p1: participantMachine },
14
+ participantPrivateChannels: { p1: 'private-channel-p1' },
11
15
  participantsDisplayChannel: 'participants-channel',
12
16
  spectatorsDisplayChannel: null,
13
17
  participants: {
@@ -18,14 +22,17 @@ const makeProcessor = (overrides = {}) => {
18
22
  }
19
23
 
20
24
  return {
21
- processor: new DisplayEventProcessor(baseContext),
22
- participantMachine
25
+ processor: new DisplayEventProcessor(baseContext)
23
26
  }
24
27
  }
25
28
 
26
29
  describe('DisplayEventProcessor anchor updates', () => {
30
+ beforeEach(() => {
31
+ jest.clearAllMocks()
32
+ })
33
+
27
34
  test('sends direct text content to an anchor for eachParticipant', () => {
28
- const { processor, participantMachine } = makeProcessor()
35
+ const { processor } = makeProcessor()
29
36
 
30
37
  processor._processSingle({
31
38
  appRenderContext: { app: { score: 98 }, meta: { viewer: 'eachParticipant', timeoutFn: null } },
@@ -38,20 +45,23 @@ describe('DisplayEventProcessor anchor updates', () => {
38
45
  props: {}
39
46
  })
40
47
 
41
- expect(participantMachine.send).toHaveBeenCalledWith({
42
- type: 'RENDER_DISPLAY',
43
- targets: {
44
- seat_p1_score: {
45
- content: '98',
46
- contentType: 'text',
47
- type: 'replace'
48
+ expect(RealtimeMessaging.publish).toHaveBeenCalledWith(
49
+ 'private-channel-p1',
50
+ 'PRIVATE_DISPLAY',
51
+ {
52
+ targets: {
53
+ seat_p1_score: {
54
+ content: '98',
55
+ contentType: 'text',
56
+ type: 'replace'
57
+ }
48
58
  }
49
59
  }
50
- })
60
+ )
51
61
  })
52
62
 
53
63
  test('supports multi-target participant updates mixing text and html', () => {
54
- const { processor, participantMachine } = makeProcessor({
64
+ const { processor } = makeProcessor({
55
65
  pugTemplates: {
56
66
  'seat_label.pug': () => '<span>Seat A</span>'
57
67
  }
@@ -68,20 +78,23 @@ describe('DisplayEventProcessor anchor updates', () => {
68
78
  props: {}
69
79
  })
70
80
 
71
- expect(participantMachine.send).toHaveBeenCalledWith({
72
- type: 'RENDER_DISPLAY',
73
- targets: {
74
- seat_p1_score: {
75
- content: '12',
76
- contentType: 'text',
77
- type: 'replace'
78
- },
79
- seat_p1_label: {
80
- content: '<span>Seat A</span>',
81
- type: 'replace'
81
+ expect(RealtimeMessaging.publish).toHaveBeenCalledWith(
82
+ 'private-channel-p1',
83
+ 'PRIVATE_DISPLAY',
84
+ {
85
+ targets: {
86
+ seat_p1_score: {
87
+ content: '12',
88
+ contentType: 'text',
89
+ type: 'replace'
90
+ },
91
+ seat_p1_label: {
92
+ content: '<span>Seat A</span>',
93
+ type: 'replace'
94
+ }
82
95
  }
83
96
  }
84
- })
97
+ )
85
98
  })
86
99
  })
87
100