@virtualdisplay.io/client 3.2.2 → 3.4.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/CHANGELOG.md +12 -0
- package/dist/index.d.ts +100 -25
- package/dist/virtualdisplay.client.cjs.js +3 -3
- package/dist/virtualdisplay.client.cjs.js.map +1 -1
- package/dist/virtualdisplay.client.es.js +162 -17
- package/dist/virtualdisplay.client.es.js.map +1 -1
- package/dist/virtualdisplay.client.umd.js +3 -3
- package/dist/virtualdisplay.client.umd.js.map +1 -1
- package/package.json +8 -8
|
@@ -54,9 +54,12 @@ const EVENT_NAMES = {
|
|
|
54
54
|
IFRAME_READY: "iframe:ready",
|
|
55
55
|
// Mutation flow (Client → Server)
|
|
56
56
|
MUTATION_MESSAGE: "mutation:message",
|
|
57
|
+
// Config flow (Client → Server)
|
|
58
|
+
CONFIG_MESSAGE: "config:message",
|
|
57
59
|
// State flow (Server → Client)
|
|
58
60
|
MESSAGE_RECEIVED: "message:received",
|
|
59
|
-
STATE_CHANGED: "state:changed"
|
|
61
|
+
STATE_CHANGED: "state:changed",
|
|
62
|
+
INITIAL_STATE_RECEIVED: "state:initial-received"
|
|
60
63
|
};
|
|
61
64
|
const g = Object.freeze({
|
|
62
65
|
debug: 0,
|
|
@@ -6925,7 +6928,8 @@ class MappingValidator {
|
|
|
6925
6928
|
}
|
|
6926
6929
|
const MESSAGE_TYPES = {
|
|
6927
6930
|
MUTATION: "mutation",
|
|
6928
|
-
STATE: "state"
|
|
6931
|
+
STATE: "state",
|
|
6932
|
+
CONFIG: "config"
|
|
6929
6933
|
};
|
|
6930
6934
|
function createMutationMessage(mutations) {
|
|
6931
6935
|
if (!Array.isArray(mutations)) {
|
|
@@ -6937,7 +6941,7 @@ function createMutationMessage(mutations) {
|
|
|
6937
6941
|
};
|
|
6938
6942
|
}
|
|
6939
6943
|
function isValidMessage(data) {
|
|
6940
|
-
return isMutationMessage(data) || isStateMessage(data);
|
|
6944
|
+
return isMutationMessage(data) || isStateMessage(data) || isConfigMessage(data);
|
|
6941
6945
|
}
|
|
6942
6946
|
function isMutationMessage(data) {
|
|
6943
6947
|
if (typeof data !== "object" || data === null) {
|
|
@@ -6953,6 +6957,13 @@ function isStateMessage(data) {
|
|
|
6953
6957
|
const obj = data;
|
|
6954
6958
|
return obj.type === MESSAGE_TYPES.STATE && Array.isArray(obj.nodes);
|
|
6955
6959
|
}
|
|
6960
|
+
function isConfigMessage(data) {
|
|
6961
|
+
if (typeof data !== "object" || data === null) {
|
|
6962
|
+
return false;
|
|
6963
|
+
}
|
|
6964
|
+
const obj = data;
|
|
6965
|
+
return obj.type === MESSAGE_TYPES.CONFIG && typeof obj.config === "object" && obj.config !== null;
|
|
6966
|
+
}
|
|
6956
6967
|
class AttributeService {
|
|
6957
6968
|
attributes = /* @__PURE__ */ new Map();
|
|
6958
6969
|
eventBus;
|
|
@@ -7148,8 +7159,14 @@ class MessageHandler {
|
|
|
7148
7159
|
logger.debug("Message handler started listening");
|
|
7149
7160
|
}
|
|
7150
7161
|
setupOutgoingMessages() {
|
|
7151
|
-
|
|
7152
|
-
|
|
7162
|
+
const outgoingEvents = [
|
|
7163
|
+
EVENT_NAMES.MUTATION_MESSAGE,
|
|
7164
|
+
EVENT_NAMES.CONFIG_MESSAGE
|
|
7165
|
+
];
|
|
7166
|
+
outgoingEvents.forEach((eventName) => {
|
|
7167
|
+
this.eventBus.on(eventName, (event) => {
|
|
7168
|
+
this.queueOrSend(event.message);
|
|
7169
|
+
});
|
|
7153
7170
|
});
|
|
7154
7171
|
}
|
|
7155
7172
|
setupReadyListener() {
|
|
@@ -7186,7 +7203,7 @@ class NodeSelector {
|
|
|
7186
7203
|
logger.warn(`Cannot toggle node ${this.nodeId}: node not found`);
|
|
7187
7204
|
return;
|
|
7188
7205
|
}
|
|
7189
|
-
if (node.isVisible
|
|
7206
|
+
if (node.isVisible) {
|
|
7190
7207
|
this.hide();
|
|
7191
7208
|
return;
|
|
7192
7209
|
}
|
|
@@ -7224,6 +7241,7 @@ class ModelNode {
|
|
|
7224
7241
|
name;
|
|
7225
7242
|
type;
|
|
7226
7243
|
visible;
|
|
7244
|
+
onChange;
|
|
7227
7245
|
constructor(params) {
|
|
7228
7246
|
this.id = params.id;
|
|
7229
7247
|
this.name = params.name;
|
|
@@ -7243,6 +7261,7 @@ class ModelNode {
|
|
|
7243
7261
|
class StateService {
|
|
7244
7262
|
nodes = /* @__PURE__ */ new Map();
|
|
7245
7263
|
eventBus;
|
|
7264
|
+
hasReceivedInitialSync = false;
|
|
7246
7265
|
constructor(eventBus) {
|
|
7247
7266
|
this.eventBus = eventBus;
|
|
7248
7267
|
this.eventBus.on(EVENT_NAMES.MESSAGE_RECEIVED, (event) => {
|
|
@@ -7255,28 +7274,32 @@ class StateService {
|
|
|
7255
7274
|
currentNodeCount: this.nodeCount
|
|
7256
7275
|
});
|
|
7257
7276
|
if (isStateMessage(message)) {
|
|
7258
|
-
this.updateState(message.nodes);
|
|
7277
|
+
this.updateState(message.nodes, message.isInitial);
|
|
7259
7278
|
}
|
|
7260
7279
|
}
|
|
7261
|
-
updateState(newNodes) {
|
|
7262
|
-
const wasInitial = !this.hasInitialState;
|
|
7280
|
+
updateState(newNodes, isInitial) {
|
|
7263
7281
|
logger.debug("Updating state with nodes from server", {
|
|
7264
7282
|
incomingNodes: newNodes.length,
|
|
7265
|
-
isInitialState:
|
|
7283
|
+
isInitialState: isInitial,
|
|
7266
7284
|
currentNodes: this.nodeCount
|
|
7267
7285
|
});
|
|
7268
7286
|
for (const nodeData of newNodes) {
|
|
7269
|
-
this.
|
|
7287
|
+
const shouldProcessNode = !isInitial || !this.nodes.has(nodeData.id);
|
|
7288
|
+
if (shouldProcessNode) {
|
|
7289
|
+
this.updateOrCreateNode(nodeData);
|
|
7290
|
+
}
|
|
7270
7291
|
}
|
|
7271
7292
|
this.eventBus.emit(EVENT_NAMES.STATE_CHANGED, {
|
|
7272
7293
|
nodes: this.getAllNodes()
|
|
7273
7294
|
});
|
|
7274
7295
|
logger.info("State updated", {
|
|
7275
7296
|
totalNodes: this.nodeCount,
|
|
7276
|
-
wasInitialState:
|
|
7297
|
+
wasInitialState: isInitial
|
|
7277
7298
|
});
|
|
7278
|
-
if (
|
|
7299
|
+
if (isInitial && !this.hasReceivedInitialSync) {
|
|
7300
|
+
this.hasReceivedInitialSync = true;
|
|
7279
7301
|
logger.info("Initial state received - client is now ready");
|
|
7302
|
+
this.eventBus.emit(EVENT_NAMES.INITIAL_STATE_RECEIVED, {});
|
|
7280
7303
|
}
|
|
7281
7304
|
}
|
|
7282
7305
|
updateOrCreateNode(newNodeData) {
|
|
@@ -7285,8 +7308,12 @@ class StateService {
|
|
|
7285
7308
|
this.createNewNode(newNodeData);
|
|
7286
7309
|
return;
|
|
7287
7310
|
}
|
|
7311
|
+
const previousVisibility = existingNode.isVisible;
|
|
7288
7312
|
const visibilityMethod = newNodeData.visible ? "show" : "hide";
|
|
7289
7313
|
existingNode[visibilityMethod]();
|
|
7314
|
+
if (previousVisibility !== existingNode.isVisible && existingNode.onChange !== void 0) {
|
|
7315
|
+
existingNode.onChange();
|
|
7316
|
+
}
|
|
7290
7317
|
logger.debug("Updated existing node", {
|
|
7291
7318
|
id: existingNode.id,
|
|
7292
7319
|
name: existingNode.name,
|
|
@@ -7316,16 +7343,102 @@ class StateService {
|
|
|
7316
7343
|
return Array.from(this.nodes.values());
|
|
7317
7344
|
}
|
|
7318
7345
|
get isReady() {
|
|
7319
|
-
return this.
|
|
7346
|
+
return this.hasReceivedInitialSync;
|
|
7320
7347
|
}
|
|
7321
7348
|
get nodeCount() {
|
|
7322
7349
|
return this.nodes.size;
|
|
7323
7350
|
}
|
|
7324
|
-
get hasInitialState() {
|
|
7325
|
-
return this.nodeCount > 0;
|
|
7326
|
-
}
|
|
7327
7351
|
clear() {
|
|
7328
7352
|
this.nodes.clear();
|
|
7353
|
+
this.hasReceivedInitialSync = false;
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
class VirtualdisplayViewerService {
|
|
7357
|
+
eventBus;
|
|
7358
|
+
constructor(eventBus) {
|
|
7359
|
+
this.eventBus = eventBus;
|
|
7360
|
+
}
|
|
7361
|
+
/**
|
|
7362
|
+
* Send initial configuration based on client options
|
|
7363
|
+
* Only sends config when values are false (server defaults to true)
|
|
7364
|
+
*/
|
|
7365
|
+
sendInitialConfig(options) {
|
|
7366
|
+
const config = {};
|
|
7367
|
+
if (options.arEnabled === false) {
|
|
7368
|
+
config.arEnabled = false;
|
|
7369
|
+
}
|
|
7370
|
+
if (options.fullscreenEnabled === false) {
|
|
7371
|
+
config.fullscreenEnabled = false;
|
|
7372
|
+
}
|
|
7373
|
+
if (options.loadingIndicatorEnabled === false) {
|
|
7374
|
+
config.loadingIndicatorEnabled = false;
|
|
7375
|
+
}
|
|
7376
|
+
if (Object.keys(config).length > 0) {
|
|
7377
|
+
logger.debug("Sending initial UI configuration", config);
|
|
7378
|
+
this.sendUIConfig(config);
|
|
7379
|
+
}
|
|
7380
|
+
}
|
|
7381
|
+
/**
|
|
7382
|
+
* Update AR button visibility
|
|
7383
|
+
*/
|
|
7384
|
+
setArEnabled(enabled) {
|
|
7385
|
+
logger.debug(`Setting AR button enabled: ${enabled}`);
|
|
7386
|
+
this.sendUIConfig({ arEnabled: enabled });
|
|
7387
|
+
}
|
|
7388
|
+
/**
|
|
7389
|
+
* Update fullscreen button visibility
|
|
7390
|
+
*/
|
|
7391
|
+
setFullscreenEnabled(enabled) {
|
|
7392
|
+
logger.debug(`Setting fullscreen button enabled: ${enabled}`);
|
|
7393
|
+
this.sendUIConfig({ fullscreenEnabled: enabled });
|
|
7394
|
+
}
|
|
7395
|
+
/**
|
|
7396
|
+
* Update loading indicator visibility
|
|
7397
|
+
*/
|
|
7398
|
+
setLoadingIndicatorEnabled(enabled) {
|
|
7399
|
+
logger.debug(`Setting loading indicator enabled: ${enabled}`);
|
|
7400
|
+
this.sendUIConfig({ loadingIndicatorEnabled: enabled });
|
|
7401
|
+
}
|
|
7402
|
+
/**
|
|
7403
|
+
* Update multiple UI settings at once
|
|
7404
|
+
*/
|
|
7405
|
+
updateUIConfig(config) {
|
|
7406
|
+
logger.debug("Updating UI configuration", config);
|
|
7407
|
+
this.sendUIConfig(config);
|
|
7408
|
+
}
|
|
7409
|
+
/**
|
|
7410
|
+
* Hide all UI elements
|
|
7411
|
+
*/
|
|
7412
|
+
hideAllUI() {
|
|
7413
|
+
logger.debug("Hiding all UI elements");
|
|
7414
|
+
this.sendUIConfig({
|
|
7415
|
+
arEnabled: false,
|
|
7416
|
+
fullscreenEnabled: false,
|
|
7417
|
+
loadingIndicatorEnabled: false
|
|
7418
|
+
});
|
|
7419
|
+
}
|
|
7420
|
+
/**
|
|
7421
|
+
* Show all UI elements
|
|
7422
|
+
*/
|
|
7423
|
+
showAllUI() {
|
|
7424
|
+
logger.debug("Showing all UI elements");
|
|
7425
|
+
this.sendUIConfig({
|
|
7426
|
+
arEnabled: true,
|
|
7427
|
+
fullscreenEnabled: true,
|
|
7428
|
+
loadingIndicatorEnabled: true
|
|
7429
|
+
});
|
|
7430
|
+
}
|
|
7431
|
+
/**
|
|
7432
|
+
* Send UI configuration to server
|
|
7433
|
+
*/
|
|
7434
|
+
sendUIConfig(uiConfig) {
|
|
7435
|
+
const config = { ui: uiConfig };
|
|
7436
|
+
const message = {
|
|
7437
|
+
type: MESSAGE_TYPES.CONFIG,
|
|
7438
|
+
config
|
|
7439
|
+
};
|
|
7440
|
+
logger.debug("Emitting CONFIG message", message);
|
|
7441
|
+
this.eventBus.emit(EVENT_NAMES.CONFIG_MESSAGE, { message });
|
|
7329
7442
|
}
|
|
7330
7443
|
}
|
|
7331
7444
|
class VirtualdisplayClient {
|
|
@@ -7333,6 +7446,7 @@ class VirtualdisplayClient {
|
|
|
7333
7446
|
attributeService;
|
|
7334
7447
|
stateService;
|
|
7335
7448
|
messageHandler;
|
|
7449
|
+
viewerService;
|
|
7336
7450
|
options;
|
|
7337
7451
|
iframe;
|
|
7338
7452
|
constructor(options) {
|
|
@@ -7341,8 +7455,10 @@ class VirtualdisplayClient {
|
|
|
7341
7455
|
this.attributeService = new AttributeService(this.eventBus);
|
|
7342
7456
|
this.stateService = new StateService(this.eventBus);
|
|
7343
7457
|
this.messageHandler = new MessageHandler(this.eventBus);
|
|
7458
|
+
this.viewerService = new VirtualdisplayViewerService(this.eventBus);
|
|
7344
7459
|
this.initializeLogging();
|
|
7345
7460
|
this.createAndConnectIframe();
|
|
7461
|
+
this.setupInitialConfig();
|
|
7346
7462
|
}
|
|
7347
7463
|
initializeLogging() {
|
|
7348
7464
|
if (this.options.debug === true) {
|
|
@@ -7361,6 +7477,11 @@ class VirtualdisplayClient {
|
|
|
7361
7477
|
logger.debug("Iframe created, setting up messaging");
|
|
7362
7478
|
this.messageHandler.setIframe(this.iframe);
|
|
7363
7479
|
}
|
|
7480
|
+
setupInitialConfig() {
|
|
7481
|
+
this.eventBus.once(EVENT_NAMES.IFRAME_READY, () => {
|
|
7482
|
+
this.viewerService.sendInitialConfig(this.options);
|
|
7483
|
+
});
|
|
7484
|
+
}
|
|
7364
7485
|
/**
|
|
7365
7486
|
* Load attribute mapping configuration
|
|
7366
7487
|
* @throws {VirtualdisplayError} When mapping configuration is invalid
|
|
@@ -7405,6 +7526,29 @@ class VirtualdisplayClient {
|
|
|
7405
7526
|
getNodes() {
|
|
7406
7527
|
return this.stateService.getAllNodes();
|
|
7407
7528
|
}
|
|
7529
|
+
/**
|
|
7530
|
+
* Check if the client has received initial state and is ready
|
|
7531
|
+
*/
|
|
7532
|
+
get isReady() {
|
|
7533
|
+
return this.stateService.isReady;
|
|
7534
|
+
}
|
|
7535
|
+
/**
|
|
7536
|
+
* Register a callback to be called when the client is ready
|
|
7537
|
+
* If already ready, the callback is called immediately
|
|
7538
|
+
*/
|
|
7539
|
+
onReady(callback) {
|
|
7540
|
+
if (this.stateService.isReady) {
|
|
7541
|
+
callback();
|
|
7542
|
+
return;
|
|
7543
|
+
}
|
|
7544
|
+
this.eventBus.once(EVENT_NAMES.INITIAL_STATE_RECEIVED, callback);
|
|
7545
|
+
}
|
|
7546
|
+
/**
|
|
7547
|
+
* Get the viewer service for UI configuration
|
|
7548
|
+
*/
|
|
7549
|
+
get viewer() {
|
|
7550
|
+
return this.viewerService;
|
|
7551
|
+
}
|
|
7408
7552
|
destroy() {
|
|
7409
7553
|
logger.info("Destroying Virtualdisplay client");
|
|
7410
7554
|
this.attributeService.clear();
|
|
@@ -7430,6 +7574,7 @@ export {
|
|
|
7430
7574
|
NodeSelector,
|
|
7431
7575
|
VirtualdisplayClient,
|
|
7432
7576
|
VirtualdisplayError,
|
|
7577
|
+
VirtualdisplayViewerService,
|
|
7433
7578
|
enableDebugMode,
|
|
7434
7579
|
isDebugMode,
|
|
7435
7580
|
logger,
|