@virtualdisplay.io/client 3.2.1 → 3.3.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.
@@ -56,7 +56,8 @@ const EVENT_NAMES = {
56
56
  MUTATION_MESSAGE: "mutation:message",
57
57
  // State flow (Server → Client)
58
58
  MESSAGE_RECEIVED: "message:received",
59
- STATE_CHANGED: "state:changed"
59
+ STATE_CHANGED: "state:changed",
60
+ INITIAL_STATE_RECEIVED: "state:initial-received"
60
61
  };
61
62
  const g = Object.freeze({
62
63
  debug: 0,
@@ -359,8 +360,8 @@ o.getInstance();
359
360
  o.enableMemoryLogging.bind(o);
360
361
  const logger = o.getInstance().child({
361
362
  prefix: "Client",
362
- level: "info"
363
- // Default level, can be changed via enableDebugMode
363
+ level: "warn"
364
+ // Show warnings and errors by default
364
365
  });
365
366
  function enableDebugMode() {
366
367
  logger.setLevel("debug");
@@ -7224,6 +7225,7 @@ class ModelNode {
7224
7225
  name;
7225
7226
  type;
7226
7227
  visible;
7228
+ onChange;
7227
7229
  constructor(params) {
7228
7230
  this.id = params.id;
7229
7231
  this.name = params.name;
@@ -7243,6 +7245,7 @@ class ModelNode {
7243
7245
  class StateService {
7244
7246
  nodes = /* @__PURE__ */ new Map();
7245
7247
  eventBus;
7248
+ hasReceivedInitialSync = false;
7246
7249
  constructor(eventBus) {
7247
7250
  this.eventBus = eventBus;
7248
7251
  this.eventBus.on(EVENT_NAMES.MESSAGE_RECEIVED, (event) => {
@@ -7255,28 +7258,32 @@ class StateService {
7255
7258
  currentNodeCount: this.nodeCount
7256
7259
  });
7257
7260
  if (isStateMessage(message)) {
7258
- this.updateState(message.nodes);
7261
+ this.updateState(message.nodes, message.isInitial);
7259
7262
  }
7260
7263
  }
7261
- updateState(newNodes) {
7262
- const wasInitial = !this.hasInitialState;
7264
+ updateState(newNodes, isInitial) {
7263
7265
  logger.debug("Updating state with nodes from server", {
7264
7266
  incomingNodes: newNodes.length,
7265
- isInitialState: wasInitial,
7267
+ isInitialState: isInitial,
7266
7268
  currentNodes: this.nodeCount
7267
7269
  });
7268
7270
  for (const nodeData of newNodes) {
7269
- this.updateOrCreateNode(nodeData);
7271
+ const shouldProcessNode = !isInitial || !this.nodes.has(nodeData.id);
7272
+ if (shouldProcessNode) {
7273
+ this.updateOrCreateNode(nodeData);
7274
+ }
7270
7275
  }
7271
7276
  this.eventBus.emit(EVENT_NAMES.STATE_CHANGED, {
7272
7277
  nodes: this.getAllNodes()
7273
7278
  });
7274
7279
  logger.info("State updated", {
7275
7280
  totalNodes: this.nodeCount,
7276
- wasInitialState: wasInitial
7281
+ wasInitialState: isInitial
7277
7282
  });
7278
- if (wasInitial) {
7283
+ if (isInitial && !this.hasReceivedInitialSync) {
7284
+ this.hasReceivedInitialSync = true;
7279
7285
  logger.info("Initial state received - client is now ready");
7286
+ this.eventBus.emit(EVENT_NAMES.INITIAL_STATE_RECEIVED, {});
7280
7287
  }
7281
7288
  }
7282
7289
  updateOrCreateNode(newNodeData) {
@@ -7285,8 +7292,12 @@ class StateService {
7285
7292
  this.createNewNode(newNodeData);
7286
7293
  return;
7287
7294
  }
7295
+ const previousVisibility = existingNode.isVisible;
7288
7296
  const visibilityMethod = newNodeData.visible ? "show" : "hide";
7289
7297
  existingNode[visibilityMethod]();
7298
+ if (previousVisibility !== existingNode.isVisible && existingNode.onChange !== void 0) {
7299
+ existingNode.onChange();
7300
+ }
7290
7301
  logger.debug("Updated existing node", {
7291
7302
  id: existingNode.id,
7292
7303
  name: existingNode.name,
@@ -7316,16 +7327,14 @@ class StateService {
7316
7327
  return Array.from(this.nodes.values());
7317
7328
  }
7318
7329
  get isReady() {
7319
- return this.hasInitialState;
7330
+ return this.hasReceivedInitialSync;
7320
7331
  }
7321
7332
  get nodeCount() {
7322
7333
  return this.nodes.size;
7323
7334
  }
7324
- get hasInitialState() {
7325
- return this.nodeCount > 0;
7326
- }
7327
7335
  clear() {
7328
7336
  this.nodes.clear();
7337
+ this.hasReceivedInitialSync = false;
7329
7338
  }
7330
7339
  }
7331
7340
  class VirtualdisplayClient {
@@ -7405,6 +7414,23 @@ class VirtualdisplayClient {
7405
7414
  getNodes() {
7406
7415
  return this.stateService.getAllNodes();
7407
7416
  }
7417
+ /**
7418
+ * Check if the client has received initial state and is ready
7419
+ */
7420
+ get isReady() {
7421
+ return this.stateService.isReady;
7422
+ }
7423
+ /**
7424
+ * Register a callback to be called when the client is ready
7425
+ * If already ready, the callback is called immediately
7426
+ */
7427
+ onReady(callback) {
7428
+ if (this.stateService.isReady) {
7429
+ callback();
7430
+ return;
7431
+ }
7432
+ this.eventBus.once(EVENT_NAMES.INITIAL_STATE_RECEIVED, callback);
7433
+ }
7408
7434
  destroy() {
7409
7435
  logger.info("Destroying Virtualdisplay client");
7410
7436
  this.attributeService.clear();