@virtualdisplay.io/client 3.7.0 → 4.0.0-alpha.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.
package/dist/index.d.ts CHANGED
@@ -1,193 +1,95 @@
1
- import { Logger } from '@virtualdisplay-io/logger';
1
+ import { CameraConfig } from '@virtualdisplay.io/messaging';
2
+ import { CameraParameter } from '@virtualdisplay.io/messaging';
3
+ import { CameraPositionMessage } from '@virtualdisplay.io/messaging';
4
+ import { MessageCallback } from '@virtualdisplay.io/messaging';
5
+ import { SnapshotResultMessage } from '@virtualdisplay.io/messaging';
6
+ import { UIConfig } from '@virtualdisplay.io/messaging';
2
7
 
3
8
  /**
4
- * Pure domain aggregate for managing attribute values
5
- * No side effects - only business logic and state management
9
+ * Represents a single attribute with its available values
10
+ * Flat API - no source/target translation, works with server values directly
6
11
  */
7
- declare class Attribute {
8
- private readonly attributeName;
9
- private readonly values;
10
- constructor(name: string);
11
- addValue(attributeValue: AttributeValue): void;
12
- getDefaultMutations(): Mutation[];
13
- getCurrentValue(): AttributeValue | undefined;
14
- getValue(valueName: string): AttributeValue | undefined;
15
- getAllValues(): AttributeValue[];
16
- hasValue(valueName: string): boolean;
17
- get name(): string;
18
- get currentSelection(): string | undefined;
19
- clear(): void;
20
- }
21
-
22
- /**
23
- * Configuration for a single attribute
24
- */
25
- export declare interface AttributeConfig {
12
+ export declare class Attribute {
26
13
  readonly name: string;
27
- readonly values: DynamicValue<AttributeValueConfig[]>;
28
- }
29
-
30
- /**
31
- * Public API for selecting attribute values
32
- * Provides fluent interface for client usage
33
- */
34
- export declare class AttributeSelector {
35
- private readonly attributeService;
36
- private readonly attributeName;
37
- constructor(attributeService: AttributeService, attributeName: string);
14
+ readonly defaultValue: string | undefined;
15
+ private readonly values;
16
+ private readonly onSelect;
17
+ private onChangeCallback?;
18
+ constructor(options: AttributeOptions);
38
19
  /**
39
20
  * Select a value for this attribute
40
- * Fire-and-forget: returns immediately, 3D updates asynchronously
41
- * @returns this AttributeSelector for method chaining
42
- * @throws {VirtualdisplayError} When value not found for attribute
43
- */
44
- select(value: string): AttributeSelector;
45
- get name(): string;
46
- get currentValue(): string | undefined;
47
- get availableValues(): string[];
48
- /**
49
- * Register a callback to be called when any value's selection state changes
50
- * This registers the callback on all AttributeValue objects for this attribute
51
- * @param callback Function to call when selection state changes
52
- * @returns this AttributeSelector for method chaining
53
- */
54
- onChange(callback: () => void): AttributeSelector;
55
- /**
56
- * Get all AttributeValue objects for direct property access
57
- * @returns Array of AttributeValue objects
21
+ * @throws {VirtualdisplayError} When value not found
58
22
  */
23
+ select(value: string): void;
59
24
  getValues(): AttributeValue[];
60
- /**
61
- * Get a specific AttributeValue object by value name
62
- * @param value The value name to find
63
- * @returns AttributeValue object or undefined if not found
64
- */
65
25
  getValue(value: string): AttributeValue | undefined;
66
- private getAttribute;
67
- }
68
-
69
- /**
70
- * Application service for managing attributes
71
- * Handles business logic and coordinates with other domains via events
72
- */
73
- declare class AttributeService {
74
- private attributes;
75
- private readonly eventBus;
76
- private isInitialized;
77
- private mappingConfig;
78
- private readonly selections;
79
- private readonly currentState;
80
- constructor(eventBus: EventBus);
81
- /**
82
- * Load mapping configuration and apply defaults
83
- * @throws {VirtualdisplayError} When mapping configuration is invalid
84
- */
85
- loadMapping(config: MappingConfiguration): void;
86
- selectAttributeValue(attributeName: string, value: string): void;
87
- getAttribute(name: string): Attribute | undefined;
88
- getAllAttributes(): Attribute[];
89
- get initialized(): boolean;
90
- private syncStateWithAttributes;
91
- clear(): void;
92
- /**
93
- * Create context for dynamic evaluation
94
- */
95
- private createContext;
96
- /**
97
- * Evaluate a property that might be static or dynamic
98
- */
99
- private evaluateProperty;
100
- /**
101
- * Evaluate the entire mapping with current context
102
- */
103
- private evaluateMapping;
104
- /**
105
- * Create a single attribute from configuration
106
- */
107
- private createAttributeFromConfig;
108
- /**
109
- * Initialize selections from default values
110
- */
111
- private initializeSelections;
112
- /**
113
- * Check if the mapping configuration contains dynamic elements
114
- */
115
- private hasDynamicMapping;
116
26
  /**
117
- * Update current state map with visible nodes per attribute
27
+ * Register callback that fires when selection changes
28
+ * Receives the newly selected AttributeValue
118
29
  */
119
- private updateCurrentState;
120
- private getVisibleNodesForAttribute;
30
+ onChange(callback: (selectedValue: AttributeValue) => void): void;
121
31
  /**
122
- * Get initial mutations for default selections
32
+ * Update selection state from server mutation result
33
+ * Direct value comparison - no source/target translation
123
34
  */
124
- private getInitialMutations;
125
- /**
126
- * Calculate mutations by comparing old and new state
127
- */
128
- private calculateMutations;
129
- /**
130
- * Check if a node is visible in the given state
131
- */
132
- private isNodeVisible;
35
+ handleResult(serverValue: string): void;
36
+ private createValues;
37
+ }
38
+
39
+ declare interface AttributeOptions {
40
+ readonly name: string;
41
+ readonly values: string[];
42
+ readonly onSelect: (name: string, value: string) => void;
43
+ readonly defaultValue?: string;
133
44
  }
134
45
 
135
46
  /**
136
47
  * Pure domain entity representing a single attribute value
137
- * No side effects - only business logic and data
48
+ * No side effects - only state
138
49
  */
139
- declare class AttributeValue {
140
- private readonly attributeValue;
141
- private readonly nodeIds;
142
- private selected;
143
- onChange?: () => void;
144
- constructor(value: string, nodeIds: string[], isSelected?: boolean);
145
- getMutations(): Mutation[];
146
- setSelected(selected: boolean): void;
147
- get value(): string;
148
- get nodeList(): string[];
149
- hasNode(nodeId: string): boolean;
50
+ export declare class AttributeValue {
51
+ readonly value: string;
52
+ readonly attribute: string;
53
+ private isSelectedValue;
54
+ constructor(value: string, attribute: string);
150
55
  get isSelected(): boolean;
151
- setOnChange(callback: () => void): void;
56
+ setSelected(selected: boolean): void;
152
57
  }
153
58
 
154
- /**
155
- * Configuration for a single attribute value
156
- * All properties can be static or dynamic
157
- */
158
- export declare interface AttributeValueConfig {
159
- readonly value: DynamicValue<string>;
160
- readonly nodeIds: DynamicValue<string[]>;
161
- readonly isSelected?: DynamicValue<boolean>;
162
- }
59
+ declare type Attrs = Record<string, unknown> | unknown;
163
60
 
164
61
  /**
165
62
  * Camera control API for positioning and zoom
166
63
  * Uses chaining pattern for building commands
167
64
  */
168
65
  export declare class Camera {
169
- private readonly eventBus;
66
+ private readonly send;
170
67
  private commands;
171
- constructor(eventBus: EventBus);
68
+ constructor(send: MessageCallback);
172
69
  /**
173
70
  * Rotate camera horizontally
174
71
  * @param degrees - Absolute rotation in degrees (0 = front view)
72
+ * @throws VirtualdisplayError if value is not a finite number
175
73
  */
176
74
  rotate(degrees: number): this;
177
75
  /**
178
76
  * Tilt camera vertically
179
77
  * @param degrees - Absolute tilt in degrees (0 = top view, 90 = horizontal)
78
+ * @throws VirtualdisplayError if value is not a finite number
180
79
  */
181
80
  tilt(degrees: number): this;
182
81
  /**
183
82
  * Zoom camera
184
83
  * @param percentage - Zoom percentage (100 = normal, >100 = zoom in, <100 = zoom out)
84
+ * @throws VirtualdisplayError if value is not a finite number
185
85
  */
186
86
  zoom(percentage: number): this;
187
87
  /**
188
88
  * Execute accumulated camera commands
89
+ * @throws VirtualdisplayError if no commands have been accumulated
189
90
  */
190
91
  set(): void;
92
+ private validateFiniteNumber;
191
93
  /**
192
94
  * Reset camera to initial position
193
95
  * This is not chainable and executes immediately
@@ -196,32 +98,46 @@ export declare class Camera {
196
98
  }
197
99
 
198
100
  /**
199
- * Camera command
101
+ * Camera position state
102
+ * Tracks current rotation, tilt, and zoom values from server updates
200
103
  */
201
- export declare interface CameraCommand {
202
- readonly action: 'rotate' | 'tilt' | 'zoom' | 'reset';
203
- readonly value?: number;
204
- }
205
-
206
- /**
207
- * Camera configuration options
208
- */
209
- export declare interface CameraConfig {
210
- readonly initialRotate?: number;
211
- readonly initialTilt?: number;
212
- readonly initialZoom?: number;
213
- readonly minZoom?: number;
214
- readonly maxZoom?: number;
215
- readonly minTilt?: number;
216
- readonly maxTilt?: number;
104
+ declare class CameraPosition {
105
+ private readonly state;
106
+ private readonly changeCallbacks;
107
+ constructor();
108
+ /**
109
+ * Get current rotation in degrees
110
+ */
111
+ get rotation(): number;
112
+ /**
113
+ * Get current tilt in degrees
114
+ */
115
+ get tilt(): number;
116
+ /**
117
+ * Get current zoom percentage
118
+ */
119
+ get zoom(): number;
120
+ /**
121
+ * Subscribe to camera position changes
122
+ */
123
+ onChange(callback: (position: CameraPositionState) => void): void;
124
+ /**
125
+ * Handle incoming camera position message from server
126
+ */
127
+ handlePositionUpdate(message: CameraPositionMessage): void;
128
+ /**
129
+ * Update camera position from server transforms
130
+ */
131
+ update(transforms: CameraParameter[]): void;
217
132
  }
218
133
 
219
134
  /**
220
- * Camera message sent to server
135
+ * Camera position state object
221
136
  */
222
- export declare interface CameraMessage {
223
- readonly type: typeof MESSAGE_TYPES.CAMERA;
224
- readonly commands: CameraCommand[];
137
+ declare interface CameraPositionState {
138
+ rotation: number;
139
+ tilt: number;
140
+ zoom: number;
225
141
  }
226
142
 
227
143
  /**
@@ -240,39 +156,6 @@ export declare interface ClientOptions {
240
156
  readonly camera?: CameraConfig;
241
157
  }
242
158
 
243
- /**
244
- * Configuration message sent to server
245
- */
246
- export declare interface ConfigMessage {
247
- readonly type: typeof MESSAGE_TYPES.CONFIG;
248
- readonly config: ViewerConfig;
249
- }
250
-
251
- declare interface CreateNodeParams {
252
- id: string;
253
- name: string;
254
- type: NodeType;
255
- visible: boolean;
256
- }
257
-
258
- /**
259
- * Central Event Registry
260
- */
261
- export declare interface DomainEvents extends Record<string, unknown> {
262
- [EVENT_NAMES.IFRAME_READY]: VoidEvent;
263
- [EVENT_NAMES.MUTATION_MESSAGE]: MessageEvent_2<MutationMessage>;
264
- [EVENT_NAMES.CONFIG_MESSAGE]: MessageEvent_2<ConfigMessage>;
265
- [EVENT_NAMES.CAMERA_MESSAGE]: MessageEvent_2<CameraMessage>;
266
- [EVENT_NAMES.MESSAGE_RECEIVED]: MessageEvent_2;
267
- [EVENT_NAMES.STATE_CHANGED]: StateChangedEvent;
268
- [EVENT_NAMES.INITIAL_STATE_RECEIVED]: VoidEvent;
269
- }
270
-
271
- /**
272
- * A value that can be static or dynamically computed
273
- */
274
- declare type DynamicValue<T> = T | ((context: MappingContext) => T);
275
-
276
159
  export declare function enableDebugMode(): void;
277
160
 
278
161
  /**
@@ -282,287 +165,37 @@ export declare const ERROR_CODES: {
282
165
  readonly NO_MAPPING: "NO_MAPPING";
283
166
  readonly ATTRIBUTE_NOT_FOUND: "ATTRIBUTE_NOT_FOUND";
284
167
  readonly VALUE_NOT_FOUND: "VALUE_NOT_FOUND";
285
- readonly INVALID_MAPPING: "INVALID_MAPPING";
286
168
  readonly PARENT_NOT_FOUND: "PARENT_NOT_FOUND";
287
- readonly INVALID_MUTATIONS: "INVALID_MUTATIONS";
288
169
  readonly INVALID_PARAMETER: "INVALID_PARAMETER";
170
+ readonly SNAPSHOT_FAILED: "SNAPSHOT_FAILED";
289
171
  };
290
172
 
291
173
  export declare type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];
292
174
 
293
- /**
294
- * Event name constants for type-safe event communication
295
- */
296
- export declare const EVENT_NAMES: {
297
- readonly IFRAME_READY: "iframe:ready";
298
- readonly MUTATION_MESSAGE: "mutation:message";
299
- readonly CONFIG_MESSAGE: "config:message";
300
- readonly CAMERA_MESSAGE: "camera:message";
301
- readonly MESSAGE_RECEIVED: "message:received";
302
- readonly STATE_CHANGED: "state:changed";
303
- readonly INITIAL_STATE_RECEIVED: "state:initial-received";
304
- readonly SNAPSHOT_MESSAGE: "snapshot:take";
305
- };
306
-
307
- /**
308
- * EventBus for domain coordination
309
- * Provides loose coupling between domains via events
310
- */
311
- declare class EventBus {
312
- private readonly listeners;
313
- on<K extends keyof DomainEvents>(event: K, listener: EventListener_2<DomainEvents[K]>): void;
314
- emit<K extends keyof DomainEvents>(event: K, payload: DomainEvents[K]): void;
315
- /**
316
- * Register a listener that will be called only once
317
- * The listener is automatically removed after the first call
318
- */
319
- once<K extends keyof DomainEvents>(event: K, listener: EventListener_2<DomainEvents[K]>): void;
320
- /**
321
- * Remove a specific listener for an event
322
- */
323
- off<K extends keyof DomainEvents>(event: K, listener: EventListener_2<DomainEvents[K]>): void;
324
- }
325
-
326
- declare type EventListener_2<T> = (payload: T) => void;
327
-
328
175
  export declare function isDebugMode(): boolean;
329
176
 
330
- export declare const logger: Logger;
331
-
332
- /**
333
- * Complete mapping configuration
334
- * Defines how product attributes map to 3D nodes
335
- */
336
- export declare interface MappingConfiguration {
337
- readonly attributes: AttributeConfig[];
338
- }
339
-
340
- /**
341
- * Context provided to dynamic value functions
342
- */
343
- declare interface MappingContext {
344
- getValue: (attributeName: string) => string | undefined;
345
- getAllValues: () => Map<string, string>;
346
- }
347
-
348
- export declare const mappingSchema: {
349
- "$schema": "http://json-schema.org/draft-07/schema#",
350
- "title": "Virtualdisplay mapping configuration",
351
- "description": "Schema for attribute-based 3D model configuration",
352
- "type": "object",
353
- "required": ["attributes"],
354
- "definitions": {
355
- "attribute": {
356
- "type": "object",
357
- "description": "A configurable attribute with multiple possible values",
358
- "required": ["name", "values"],
359
- "properties": {
360
- "name": {
361
- "type": "string",
362
- "description": "Unique attribute name (e.g., 'Color', 'Size')",
363
- "minLength": 1,
364
- "pattern": "^\\S.*\\S$|^\\S$"
365
- },
366
- "values": {
367
- "type": "array",
368
- "description": "Possible values for this attribute",
369
- "minItems": 1,
370
- "items": {
371
- "$ref": "#/definitions/attributeValue"
372
- }
373
- }
374
- }
375
- },
376
- "attributeValue": {
377
- "type": "object",
378
- "description": "A single value option for an attribute",
379
- "required": ["value", "nodeIds"],
380
- "properties": {
381
- "value": {
382
- "type": "string",
383
- "description": "Display value (e.g., 'Red', 'Large')",
384
- "minLength": 1,
385
- "pattern": "^\\S.*\\S$|^\\S$"
386
- },
387
- "nodeIds": {
388
- "type": "array",
389
- "description": "3D model node IDs controlled by this value",
390
- "items": {
391
- "type": "string",
392
- "description": "Node ID in the 3D model"
393
- }
394
- },
395
- "isSelected": {
396
- "type": "boolean",
397
- "description": "Whether this value is selected by default",
398
- "default": false
399
- }
400
- }
401
- }
402
- },
403
- "properties": {
404
- "attributes": {
405
- "type": "array",
406
- "description": "List of all configurable attributes",
407
- "minItems": 1,
408
- "items": {
409
- "$ref": "#/definitions/attribute"
410
- }
411
- }
412
- }
177
+ export declare let logger: {
178
+ debug: (msg: string, attrs?: Attrs) => void;
179
+ info: (msg: string, attrs?: Attrs) => void;
180
+ warn: (msg: string, attrs?: Attrs) => void;
181
+ error: (msg: string, attrs?: Attrs) => void;
413
182
  };
414
183
 
415
- /**
416
- * Validator for mapping configuration using AJV
417
- */
418
- export declare class MappingValidator {
419
- private static readonly ajv;
420
- private static readonly validateFn;
421
- /**
422
- * Validate complete mapping configuration
423
- * @throws {VirtualdisplayError} When mapping configuration is invalid
424
- */
425
- static validate(config: MappingConfiguration): void;
426
- /**
427
- * Check if configuration contains dynamic values (functions)
428
- */
429
- static containsDynamicValues(config: MappingConfiguration): boolean;
430
- /**
431
- * Basic structure validation for dynamic mappings
432
- */
433
- private static validateBasicStructure;
434
- }
435
-
436
- /**
437
- * Union of all possible messages
438
- */
439
- export declare type Message = MutationMessage | StateMessage | ConfigMessage | CameraMessage | SnapshotRequestMessage | SnapshotDevelopedMessage;
440
-
441
- /**
442
- * Types of messages exchanged between client and server
443
- * Using lowercase format to match server
444
- */
445
- export declare const MESSAGE_TYPES: {
446
- readonly MUTATION: "mutation";
447
- readonly STATE: "state";
448
- readonly CONFIG: "config";
449
- readonly CAMERA: "camera";
450
- readonly SNAPSHOT: "snapshot";
451
- };
452
-
453
- /**
454
- * Generic message event - used for all message passing
455
- */
456
- declare interface MessageEvent_2<T extends Message = Message> {
457
- message: T;
458
- }
459
-
460
- /**
461
- * Represents a 3D node in the scene
462
- * Live object that can be updated to reflect state changes
463
- */
464
- export declare class ModelNode {
465
- readonly id: string;
466
- readonly name: string;
467
- readonly type: NodeType;
468
- private visible;
469
- onChange?: () => void;
470
- constructor(params: CreateNodeParams);
471
- get isVisible(): boolean;
472
- show(): void;
473
- hide(): void;
474
- }
475
-
476
- /**
477
- * DTO for model node data received from server
478
- */
479
- export declare interface ModelNodeDto {
480
- readonly id: string;
481
- readonly name: string;
482
- readonly type: string;
483
- readonly visible: boolean;
484
- }
485
-
486
- /**
487
- * A mutation represents a change to be applied to a 3D node
488
- * This is a pure data class with no side effects
489
- */
490
- export declare class Mutation {
491
- readonly type: MutationType;
492
- readonly nodeId: string;
493
- constructor(type: MutationType, nodeId: string);
494
- static show(nodeId: string): Mutation;
495
- static hide(nodeId: string): Mutation;
496
- inverse(): Mutation;
497
- equals(other: Mutation): boolean;
498
- toDto(): MutationDto;
184
+ export declare interface MutationFailedEvent {
185
+ attribute: string;
186
+ value: string;
499
187
  }
500
188
 
501
- /**
502
- * Types of mutations that can be applied to 3D nodes
503
- */
504
- export declare const MUTATION_TYPES: {
505
- readonly SHOW: "show";
506
- readonly HIDE: "hide";
507
- };
508
-
509
- /**
510
- * Data Transfer Object for mutations
511
- * Plain object for client-server communication without methods
512
- */
513
- export declare interface MutationDto {
514
- readonly type: MutationType;
515
- readonly nodeId: string;
516
- }
517
-
518
- /**
519
- * Mutation message sent to server
520
- */
521
- export declare interface MutationMessage {
522
- readonly type: typeof MESSAGE_TYPES.MUTATION;
523
- readonly mutations: MutationDto[];
524
- }
525
-
526
- export declare type MutationType = typeof MUTATION_TYPES[keyof typeof MUTATION_TYPES];
527
-
528
- /**
529
- * Types of nodes in the 3D scene
530
- */
531
- export declare const NODE_TYPES: {
532
- readonly MESH: "mesh";
533
- readonly VARIANT: "variant";
534
- };
535
-
536
- /**
537
- * Public API for controlling individual nodes
538
- * Provides direct node manipulation without attribute mapping
539
- */
540
- export declare class NodeSelector {
541
- private readonly eventBus;
542
- private readonly stateService;
543
- private readonly nodeId;
544
- constructor(eventBus: EventBus, stateService: StateService, nodeId: string);
545
- show(): void;
546
- hide(): void;
547
- toggle(): void;
548
- get id(): string;
549
- get isVisible(): boolean;
550
- getNode(): ModelNode | undefined;
551
- get type(): string | undefined;
552
- get name(): string | undefined;
553
- private emitMutation;
554
- }
555
-
556
- declare type NodeType = typeof NODE_TYPES[keyof typeof NODE_TYPES];
557
-
558
189
  /**
559
190
  * Represents a photo being captured
560
191
  * Pure domain object that manages callbacks for when the photo is developed
561
192
  */
562
193
  export declare class Photo {
563
194
  private readonly filename;
564
- private readonly callbacks;
195
+ private readonly developedCallbacks;
196
+ private readonly errorCallbacks;
565
197
  private developed;
198
+ private failed;
566
199
  private photoData;
567
200
  constructor(filename: string);
568
201
  /**
@@ -573,15 +206,26 @@ export declare class Photo {
573
206
  * @returns This Photo instance for chaining
574
207
  */
575
208
  onDeveloped(callback: (photo: PhotoData) => void): this;
209
+ /**
210
+ * Register a callback for when the photo capture fails
211
+ *
212
+ * @param callback Function to call with error
213
+ * @returns This Photo instance for chaining
214
+ */
215
+ onError(callback: (error: VirtualdisplayError) => void): this;
576
216
  /**
577
217
  * Get the filename for this photo
578
218
  */
579
219
  getFilename(): string;
580
220
  /**
581
221
  * Mark the photo as developed and notify all callbacks
582
- * This method is called by the SnapshotMessageHandler when the photo data arrives
222
+ * This method is called by Snapshot when the photo data arrives from the server
583
223
  */
584
224
  develop(photoData: PhotoData): void;
225
+ /**
226
+ * Mark the photo as failed and notify error callbacks
227
+ */
228
+ fail(error: VirtualdisplayError): void;
585
229
  }
586
230
 
587
231
  export declare interface PhotoData {
@@ -594,10 +238,10 @@ export declare interface PhotoData {
594
238
  * Following the camera analogy: take() triggers capture, onDeveloped() gets result
595
239
  */
596
240
  export declare class Snapshot {
597
- private readonly eventBus;
241
+ private readonly send;
598
242
  private readonly validExtensions;
599
- private readonly messageHandler;
600
- constructor(eventBus: EventBus);
243
+ private readonly pendingPhotos;
244
+ constructor(send: MessageCallback);
601
245
  /**
602
246
  * Take a snapshot of the current 3D model view
603
247
  *
@@ -606,125 +250,74 @@ export declare class Snapshot {
606
250
  * @throws VirtualdisplayError if filename is invalid
607
251
  */
608
252
  take(filename: string): Photo;
253
+ /**
254
+ * Handle incoming snapshot result from server
255
+ * Matches the message to a pending photo by filename, then develops or fails it
256
+ */
257
+ handleSnapshotResult(message: SnapshotResultMessage): void;
609
258
  /**
610
259
  * Validate filename has a valid image extension
611
260
  */
612
261
  private validateFilename;
613
262
  }
614
263
 
615
- /**
616
- * Snapshot developed message received from server
617
- */
618
- export declare interface SnapshotDevelopedMessage {
619
- readonly type: typeof MESSAGE_TYPES.SNAPSHOT;
620
- readonly filename: string;
621
- readonly data: string;
622
- }
623
-
624
- /**
625
- * Snapshot request message sent to server
626
- */
627
- export declare interface SnapshotRequestMessage {
628
- readonly type: typeof MESSAGE_TYPES.SNAPSHOT;
629
- readonly filename: string;
630
- }
631
-
632
- declare interface StateChangedEvent {
633
- nodes: ModelNode[];
634
- }
635
-
636
- /**
637
- * State message received from server
638
- * Contains array of model node DTOs
639
- */
640
- export declare interface StateMessage {
641
- readonly type: typeof MESSAGE_TYPES.STATE;
642
- readonly nodes: ModelNodeDto[];
643
- readonly isInitial: boolean;
644
- }
645
-
646
- /**
647
- * Application service for managing node state
648
- * Handles state updates from server and emits node change events
649
- */
650
- declare class StateService {
651
- private readonly nodes;
652
- private readonly eventBus;
653
- private hasReceivedInitialSync;
654
- constructor(eventBus: EventBus);
655
- private handleMessage;
656
- private updateState;
657
- private updateOrCreateNode;
658
- private createNewNode;
659
- getNode(id: string): ModelNode | undefined;
660
- getAllNodes(): ModelNode[];
661
- get isReady(): boolean;
662
- get nodeCount(): number;
663
- clear(): void;
664
- }
665
-
666
- /**
667
- * UI configuration options
668
- */
669
- export declare interface UIConfig {
670
- readonly arEnabled?: boolean;
671
- readonly fullscreenEnabled?: boolean;
672
- readonly loadingIndicatorEnabled?: boolean;
673
- }
674
-
675
- /**
676
- * Viewer configuration
677
- */
678
- export declare interface ViewerConfig {
679
- readonly ui?: UIConfig;
680
- readonly camera?: CameraConfig;
681
- }
682
-
683
264
  /**
684
265
  * Main Virtualdisplay Client
685
266
  * Provides the public API for 3D product visualization
267
+ *
268
+ * Acts as the composition root: wires all services together with direct dependency injection
686
269
  */
687
270
  export declare class VirtualdisplayClient {
688
- private readonly eventBus;
689
- private readonly attributeService;
690
- private readonly stateService;
691
- private readonly messageHandler;
271
+ private readonly attributes;
272
+ private readonly readyStateTracker;
273
+ private readonly messenger;
692
274
  private readonly viewerService;
693
275
  private readonly cameraApi;
276
+ private readonly cameraPositionApi;
694
277
  private readonly snapshotApi;
695
278
  private readonly options;
696
279
  private iframe;
280
+ private readyCallbacks;
281
+ private readonly mutationFailedCallbacks;
697
282
  constructor(options: ClientOptions);
283
+ private registerHandlers;
698
284
  private initializeLogging;
699
285
  private createAndConnectIframe;
700
- private setupInitialConfig;
701
286
  /**
702
- * Load attribute mapping configuration
703
- * @throws {VirtualdisplayError} When mapping configuration is invalid
287
+ * Select a value for an attribute — sends mutation to server.
288
+ * Can be called immediately; the messenger's publisher queue holds
289
+ * the message until the iframe is ready.
290
+ */
291
+ select(name: string, value: string): void;
292
+ /**
293
+ * Get all available values for an attribute
704
294
  */
705
- setMapping(config: MappingConfiguration): void;
295
+ getValues(name: string): AttributeValue[];
706
296
  /**
707
- * Get attribute selector for fluent API
708
- * @throws {VirtualdisplayError} When no mapping is configured or attribute not found
297
+ * Get a specific value for an attribute
709
298
  */
710
- getAttribute(name: string): AttributeSelector;
299
+ getValue(name: string, value: string): AttributeValue | undefined;
711
300
  /**
712
- * Get node selector for direct node control
713
- * @param nodeId The node ID to control
714
- * @returns NodeSelector if node exists, undefined otherwise
301
+ * Register callback that fires when an attribute's selection changes
715
302
  */
716
- getNodeSelector(nodeId: string): NodeSelector | undefined;
717
- getNode(id: string): ModelNode | undefined;
718
- getNodes(): ModelNode[];
303
+ onChange(name: string, callback: (selectedValue: AttributeValue) => void): void;
304
+ /**
305
+ * Get the Attribute instance for advanced use cases
306
+ */
307
+ getAttribute(name: string): Attribute | undefined;
719
308
  /**
720
- * Check if the client has received initial state and is ready
309
+ * Check if the client has received initial mutations and is ready
721
310
  */
722
311
  get isReady(): boolean;
723
312
  /**
724
313
  * Register a callback to be called when the client is ready
725
314
  * If already ready, the callback is called immediately
726
315
  */
727
- onReady(callback: () => void): void;
316
+ onReady(callback: (client: VirtualdisplayClient) => void): void;
317
+ /**
318
+ * Register a callback for when a mutation fails on the server
319
+ */
320
+ onMutationFailed(callback: (event: MutationFailedEvent) => void): void;
728
321
  /**
729
322
  * Get the viewer service for UI configuration
730
323
  */
@@ -733,6 +326,10 @@ export declare class VirtualdisplayClient {
733
326
  * Get the camera control API
734
327
  */
735
328
  get camera(): Camera;
329
+ /**
330
+ * Get the camera position tracking API
331
+ */
332
+ get cameraPosition(): CameraPosition;
736
333
  /**
737
334
  * Get the snapshot API for taking screenshots
738
335
  */
@@ -749,9 +346,9 @@ export declare class VirtualdisplayError extends Error {
749
346
  static noMapping(): VirtualdisplayError;
750
347
  static attributeNotFound(attributeName: string): VirtualdisplayError;
751
348
  static valueNotFound(attributeName: string, valueName: string): VirtualdisplayError;
752
- static invalidMapping(reason?: string): VirtualdisplayError;
753
349
  static parentNotFound(selector: string): VirtualdisplayError;
754
- static invalidMutations(reason?: string): VirtualdisplayError;
350
+ static invalidParameter(reason: string): VirtualdisplayError;
351
+ static snapshotFailed(filename: string, reason: string): VirtualdisplayError;
755
352
  }
756
353
 
757
354
  /**
@@ -759,8 +356,8 @@ export declare class VirtualdisplayError extends Error {
759
356
  * Sends CONFIG messages to control AR button, fullscreen button, and loading indicator
760
357
  */
761
358
  export declare class VirtualdisplayViewerService {
762
- private readonly eventBus;
763
- constructor(eventBus: EventBus);
359
+ private readonly send;
360
+ constructor(send: MessageCallback);
764
361
  /**
765
362
  * Send initial configuration based on client options
766
363
  * Supports both individual properties and ui object
@@ -815,7 +412,4 @@ export declare class VirtualdisplayViewerService {
815
412
  private sendConfig;
816
413
  }
817
414
 
818
- declare interface VoidEvent {
819
- }
820
-
821
415
  export { }