dmx-api 4.0.0 → 4.0.2

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 CHANGED
@@ -2,9 +2,21 @@
2
2
 
3
3
  ## Version History
4
4
 
5
+ **4.0.2** -- Jan 31, 2026
6
+
7
+ * Fix:
8
+ - Log proper dmx-api version in browser console
9
+
10
+ **4.0.1** -- Jan 31, 2026
11
+
12
+ * Improvement:
13
+ - No alert box appears when WebSocket connection is dropped. Reopens when browser is "foregrounded".
14
+ * Fix:
15
+ - Topic positioning for `Topicmap` instances hold as reactive Vue 3 state.
16
+
5
17
  **4.0** -- Oct 16, 2024
6
18
 
7
- * BREAKING CHANGES
19
+ * BREAKING CHANGE
8
20
  - requires Vue 3 (instead Vue 2)
9
21
 
10
22
  **3.1** -- Oct 16, 2024
@@ -331,4 +343,4 @@ library's `init()` function.
331
343
 
332
344
  ------------
333
345
  Jörg Richter
334
- Oct 16, 2024
346
+ Jan 31, 2026
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dmx-api",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "API and utilities for DMX 5 based frontends",
5
5
  "author": "Jörg Richter <jri@dmx.berlin>",
6
6
  "license": "AGPL-3.0",
package/src/index.js CHANGED
@@ -6,7 +6,7 @@ import icons from './icons'
6
6
  import DMXWebSocket from './websocket'
7
7
  import {default as typeCache, init as initTypeCache, storeModule} from './type-cache'
8
8
 
9
- console.log('[DMX-API] 4.0')
9
+ console.log('[DMX-API] 4.0.2')
10
10
 
11
11
  let adminWorkspaceId // promise
12
12
 
package/src/model.js CHANGED
@@ -901,7 +901,11 @@ class Topicmap extends Topic {
901
901
  viewTopic.children = topic.children // ### TODO, see comment in newViewTopic() above
902
902
  this.addTopic(viewTopic)
903
903
  op.type = 'add'
904
- op.viewTopic = viewTopic
904
+ op.viewTopic = this.getTopic(topic.id)
905
+ // Note: we don't assign plain "viewTopic" to op.viewTopic but must re-access it by this.getTopic(). In case of a
906
+ // Vue 3 application both are not the same as addTopic() implicitly wraps viewTopic into a JS Proxy object
907
+ // (provided this Topicmap instance is reactive state). All subsequent modifications of viewTopic (in particular
908
+ // the initialization of its position) must be applied to the Proxy object then, not the original viewTopic.
905
909
  } else {
906
910
  if (!viewTopic.isVisible()) {
907
911
  viewTopic.setVisibility(true)
package/src/rpc.js CHANGED
@@ -536,7 +536,7 @@ export default {
536
536
  },
537
537
 
538
538
  /**
539
- * @param password expected to be SHA256 encoded
539
+ * @param password plain text
540
540
  *
541
541
  * @return a promise for a Username topic
542
542
  */
package/src/websocket.js CHANGED
@@ -1,4 +1,4 @@
1
- const IDLE_INTERVAL = 60 * 1000 // 60s
1
+ const HEARTBEAT_INTERVAL = 25 * 1000 // 25s
2
2
 
3
3
  /**
4
4
  * A WebSocket connection to the DMX server.
@@ -13,6 +13,8 @@ const IDLE_INTERVAL = 60 * 1000 // 60s
13
13
  export default class DMXWebSocket {
14
14
 
15
15
  /**
16
+ * @param config
17
+ * a promise for an object having a `dmx.websockets.url` property.
16
18
  * @param messageHandler
17
19
  * the function that processes incoming messages.
18
20
  * One argument is passed: the message pushed by the server (a deserialzed JSON object).
@@ -20,8 +22,8 @@ export default class DMXWebSocket {
20
22
  constructor (config, messageHandler) {
21
23
  this.messageHandler = messageHandler
22
24
  config.then(config => {
25
+ document.addEventListener('visibilitychange', this._handleVisibilityChange.bind(this))
23
26
  this.url = config['dmx.websockets.url']
24
- // DEV && console.log('[DMX] CONFIG: WebSocket server is reachable at', this.url)
25
27
  this._connect()
26
28
  })
27
29
  }
@@ -35,11 +37,21 @@ export default class DMXWebSocket {
35
37
  this.ws.send(JSON.stringify(message))
36
38
  }
37
39
 
40
+ _handleVisibilityChange () {
41
+ DEV && console.log('[DMX] Document visibility:', document.visibilityState, new Date())
42
+ if (document.visibilityState === "hidden") {
43
+ // mobile browsers often kill background sockets anyway
44
+ this._close()
45
+ } else {
46
+ this._connect()
47
+ }
48
+ }
49
+
38
50
  _connect () {
39
- DEV && console.log('[DMX] Opening WebSocket connection to', this.url)
51
+ DEV && console.log('[DMX] Connecting', this.url)
40
52
  this.ws = new WebSocket(this.url)
41
53
  this.ws.onopen = e => {
42
- this._startIdling()
54
+ this._startHeartbeat()
43
55
  }
44
56
  this.ws.onmessage = e => {
45
57
  const message = JSON.parse(e.data)
@@ -47,33 +59,32 @@ export default class DMXWebSocket {
47
59
  this.messageHandler(message)
48
60
  }
49
61
  this.ws.onclose = e => {
50
- DEV && console.log('[DMX] WebSocket connection closed (' + e.reason + ')')
51
- this._stopIdling()
52
- this._reload() // a closed ws connection is regarded an (backend/network) error which requires page reloading
62
+ DEV && console.log('[DMX] WebSocket closed', e.reason)
63
+ this._cleanup()
53
64
  }
54
65
  this.ws.onerror = e => {
55
66
  DEV && console.warn('[DMX] WebSocket error')
56
67
  }
57
68
  }
58
69
 
59
- _startIdling () {
60
- this.idleId = setInterval(this._idle.bind(this), IDLE_INTERVAL)
70
+ _startHeartbeat () {
71
+ this.heartbeatTimer = setInterval(this._ping.bind(this), HEARTBEAT_INTERVAL)
72
+ }
73
+
74
+ _stopHeartbeat () {
75
+ clearInterval(this.heartbeatTimer)
61
76
  }
62
77
 
63
- _stopIdling () {
64
- clearInterval(this.idleId)
78
+ _ping () {
79
+ DEV && console.log('[DMX] WebSocket ping')
80
+ this.send({type: 'ping'})
65
81
  }
66
82
 
67
- _idle () {
68
- DEV && console.log('[DMX] WebSocket connection idle')
69
- this.send({type: 'idle'})
83
+ _close () {
84
+ this.ws.close()
70
85
  }
71
86
 
72
- _reload () {
73
- setTimeout(() => {
74
- alert('There is a problem with the server or network.\n\nPlease press OK to reload page.\n' +
75
- 'If it fails try manual page reload.')
76
- location.reload()
77
- }, 1000) // timeout to not interfere with interactive page reload (which also closes websocket connection)
87
+ _cleanup () {
88
+ this._stopHeartbeat()
78
89
  }
79
90
  }