@virtualdisplay.io/client 4.0.0-alpha.3 → 4.0.0-alpha.30

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +218 -1
  2. package/README.md +116 -155
  3. package/dist/browser-DfB_An57.cjs +8 -0
  4. package/dist/browser-ey6Iih3j.js +1540 -0
  5. package/dist/index.d.ts +660 -0
  6. package/dist/virtualdisplay.client.cjs.js +606 -1
  7. package/dist/virtualdisplay.client.es.js +4113 -794
  8. package/dist/virtualdisplay.client.umd.js +613 -1
  9. package/package.json +3 -3
  10. package/dist/src/attributes/attribute.d.ts +0 -38
  11. package/dist/src/attributes/attribute.d.ts.map +0 -1
  12. package/dist/src/attributes/attributes.d.ts +0 -43
  13. package/dist/src/attributes/attributes.d.ts.map +0 -1
  14. package/dist/src/attributes/selections.d.ts +0 -16
  15. package/dist/src/attributes/selections.d.ts.map +0 -1
  16. package/dist/src/attributes/value.d.ts +0 -13
  17. package/dist/src/attributes/value.d.ts.map +0 -1
  18. package/dist/src/camera/camera.d.ts +0 -40
  19. package/dist/src/camera/camera.d.ts.map +0 -1
  20. package/dist/src/camera/index.d.ts +0 -4
  21. package/dist/src/camera/index.d.ts.map +0 -1
  22. package/dist/src/camera/position.d.ts +0 -43
  23. package/dist/src/camera/position.d.ts.map +0 -1
  24. package/dist/src/client/client.d.ts +0 -83
  25. package/dist/src/client/client.d.ts.map +0 -1
  26. package/dist/src/client/error.d.ts +0 -26
  27. package/dist/src/client/error.d.ts.map +0 -1
  28. package/dist/src/client/iframe-builder.d.ts +0 -25
  29. package/dist/src/client/iframe-builder.d.ts.map +0 -1
  30. package/dist/src/client/options.d.ts +0 -17
  31. package/dist/src/client/options.d.ts.map +0 -1
  32. package/dist/src/client/ready-state-tracker.d.ts +0 -26
  33. package/dist/src/client/ready-state-tracker.d.ts.map +0 -1
  34. package/dist/src/client/types.d.ts +0 -5
  35. package/dist/src/client/types.d.ts.map +0 -1
  36. package/dist/src/index.d.ts +0 -11
  37. package/dist/src/index.d.ts.map +0 -1
  38. package/dist/src/snapshot/index.d.ts +0 -3
  39. package/dist/src/snapshot/index.d.ts.map +0 -1
  40. package/dist/src/snapshot/photo.d.ts +0 -47
  41. package/dist/src/snapshot/photo.d.ts.map +0 -1
  42. package/dist/src/snapshot/snapshot.d.ts +0 -30
  43. package/dist/src/snapshot/snapshot.d.ts.map +0 -1
  44. package/dist/src/ui/viewer-config.d.ts +0 -63
  45. package/dist/src/ui/viewer-config.d.ts.map +0 -1
  46. package/dist/src/utils/logger.d.ts +0 -11
  47. package/dist/src/utils/logger.d.ts.map +0 -1
@@ -0,0 +1,660 @@
1
+ /** The app types this protocol version knows. The wire field stays a plain
2
+ * string on purpose: a newer viewer may report a type this bundle predates,
3
+ * and the host must receive it to fail visibly (never a quiet downgrade). */
4
+ type AppType = 'viewer' | 'configurator';
5
+ /** What a configurator app's submit form renders. Any field may be absent; an
6
+ * absent field means the form's own default. */
7
+ interface AppSubmitSettings {
8
+ readonly fields?: string[];
9
+ readonly ctaLabel?: string;
10
+ readonly privacyUrl?: string;
11
+ }
12
+ /**
13
+ * How a model's annotations present to the visitor: never (hide), always
14
+ * (show), or under their own control via a viewer toggle, starting visible
15
+ * (toggle-shown) or hidden (toggle-hidden). Resolved per app, defaulting to
16
+ * hide.
17
+ */
18
+ type AnnotationVisibility = 'hide' | 'show' | 'toggle-shown' | 'toggle-hidden';
19
+ /**
20
+ * Which viewer controls the model shows, as configured for it. Sent with the
21
+ * mapping; every field is optional and an absent field means the viewer's own
22
+ * default.
23
+ */
24
+ interface ViewerSettings {
25
+ readonly ar?: boolean;
26
+ readonly fullscreen?: boolean;
27
+ readonly screenshot?: boolean;
28
+ readonly cameraControls?: boolean;
29
+ /**
30
+ * The resolved per-app annotation mode. Present only when the model has
31
+ * annotations, so a control can never render with nothing to govern;
32
+ * absent means there is nothing to show or toggle.
33
+ */
34
+ readonly annotations?: AnnotationVisibility;
35
+ readonly language?: string;
36
+ /** Where the attribute controls sit: in-frame bottom-left (default) or a docked right panel. */
37
+ readonly configuratorLayout?: 'inframe-bottom-left' | 'sidebar-right' | 'hidden';
38
+ }
39
+ /**
40
+ * Camera movement limits sent to the client via CONFIG.
41
+ * Used to disable camera control buttons when a limit is reached.
42
+ * Units match the camera position: zoom = percentage (0–200), tilt/rotate = degrees.
43
+ */
44
+ interface CameraLimits {
45
+ readonly minZoom?: number;
46
+ readonly maxZoom?: number;
47
+ readonly minTilt?: number;
48
+ readonly maxTilt?: number;
49
+ readonly minRotate?: number;
50
+ readonly maxRotate?: number;
51
+ }
52
+ /** Per selector, the values the buyer can still pick right now. */
53
+ interface SelectableAttribute {
54
+ readonly name: string;
55
+ readonly selectable: string[];
56
+ /**
57
+ * The control should not render at all: a dimension whose component is
58
+ * currently hidden by its show-when conditions (parametric dimensions).
59
+ * Different from an empty `selectable`, which greys values out but keeps
60
+ * the control visible. Absent means visible.
61
+ */
62
+ readonly hidden?: boolean;
63
+ }
64
+ /**
65
+ * What the configurator does with a matched configuration.
66
+ */
67
+ declare const AVAILABILITY: {
68
+ /** Price and submit button both shown (default). */
69
+ readonly AVAILABLE: "available";
70
+ /** Price shown, submit hidden (sold out / coming soon). */
71
+ readonly VIEW_ONLY: "view_only";
72
+ /** Behaves exactly like an unpriced combination: no price, no button. */
73
+ readonly HIDDEN: "hidden";
74
+ };
75
+ type Availability = (typeof AVAILABILITY)[keyof typeof AVAILABILITY];
76
+ /**
77
+ * One pricing rule: a subset of attribute values mapped to a reference and a
78
+ * price.
79
+ */
80
+ interface PricingRule {
81
+ /**
82
+ * The attribute name→value pairs this rule names. `{}` is a catch-all;
83
+ * omitted names are wildcards. A rule matches when every pair equals the
84
+ * current selection; the rule naming the most attributes wins.
85
+ */
86
+ readonly attributes: Record<string, string>;
87
+ /** The customer's own identifier (SKU, EAN, artikelnummer, name code). */
88
+ readonly reference: string;
89
+ /** Price in minor units (cents), exactly as the source displays it. */
90
+ readonly priceCents: number;
91
+ readonly availability: Availability;
92
+ /** Provenance (manual | imported); audit-only, unused by the resolver. */
93
+ readonly source: 'manual' | 'imported';
94
+ }
95
+ /**
96
+ * A model's pricing document. The viewer's fetcher merges it into the model
97
+ * metadata and the server forwards it to the client via {@link PricingMessage}.
98
+ */
99
+ interface PricingDocument {
100
+ /** Optimistic-concurrency version from the editor; unused by the viewer. */
101
+ readonly version: number;
102
+ /** Customer-authored CTA label; null when the adapter's defaultLabel fills in. */
103
+ readonly buttonLabel: string | null;
104
+ /** ISO 4217 currency code for price formatting. */
105
+ readonly currency: string;
106
+ /** VAT label for bare embeds, e.g. "incl. btw". */
107
+ readonly vatDisplay: string;
108
+ readonly rules: PricingRule[];
109
+ }
110
+
111
+ /**
112
+ * Annotation display: show or hide the model's existing markers.
113
+ */
114
+ declare class Annotations {
115
+ private readonly send;
116
+ /** Whose pins this facade toggles: a pin lives in one model's local space. */
117
+ private readonly instance;
118
+ setEnabled(enabled: boolean): void;
119
+ }
120
+
121
+ type SelectableSnapshot = readonly SelectableAttribute[];
122
+
123
+ /**
124
+ * Camera control API for positioning and zoom
125
+ * Uses chaining pattern for building commands
126
+ */
127
+ declare class Camera {
128
+ private readonly send;
129
+ private commands;
130
+ /**
131
+ * Rotate camera horizontally
132
+ * @param degrees - Absolute rotation in degrees (0 = front view)
133
+ * @throws VirtualdisplayError if value is not a finite number
134
+ */
135
+ rotate(degrees: number): this;
136
+ /**
137
+ * Tilt camera vertically
138
+ * @param degrees - Absolute tilt in degrees (0 = top view, 90 = horizontal)
139
+ * @throws VirtualdisplayError if value is not a finite number
140
+ */
141
+ tilt(degrees: number): this;
142
+ /**
143
+ * Zoom camera
144
+ * @param percentage - Zoom percentage (100 = normal, >100 = zoom in, <100 = zoom out)
145
+ * @throws VirtualdisplayError if value is not a finite number
146
+ */
147
+ zoom(percentage: number): this;
148
+ /**
149
+ * Execute accumulated camera commands
150
+ * @throws VirtualdisplayError if no commands have been accumulated
151
+ */
152
+ set(): void;
153
+ private validateFiniteNumber;
154
+ /**
155
+ * Reset camera to initial position
156
+ * This is not chainable and executes immediately
157
+ */
158
+ reset(): void;
159
+ }
160
+
161
+ /**
162
+ * Camera position state object
163
+ */
164
+ interface CameraPositionState {
165
+ rotation: number;
166
+ tilt: number;
167
+ zoom: number;
168
+ }
169
+ /**
170
+ * Camera position state
171
+ * Tracks current rotation, tilt, zoom, and movement limits from server updates.
172
+ */
173
+ declare class CameraPosition {
174
+ private readonly state;
175
+ private limitsState;
176
+ private readonly changeCallbacks;
177
+ /**
178
+ * Get current rotation in degrees
179
+ */
180
+ get rotation(): number;
181
+ /**
182
+ * Get current tilt in degrees
183
+ */
184
+ get tilt(): number;
185
+ /**
186
+ * Get current zoom percentage
187
+ */
188
+ get zoom(): number;
189
+ /**
190
+ * Subscribe to camera position changes. Also fires when the viewer reports new
191
+ * movement limits, so controls can re-evaluate their disabled state without a
192
+ * second callback.
193
+ */
194
+ onChange(callback: (position: CameraPositionState) => void): void;
195
+ /**
196
+ * Current camera movement limits (set from CONFIG message).
197
+ * Undefined until the server sends limits in its CONFIG payload.
198
+ */
199
+ get limits(): CameraLimits | undefined;
200
+ }
201
+
202
+ /**
203
+ * The buyer's current configuration once it resolves to a price. `availability`
204
+ * is `available` (price + submit) or `view_only` (price, no submit); a matched
205
+ * `hidden` rule and a no-match both surface as `undefined` instead.
206
+ */
207
+ interface ResolvedConfiguration {
208
+ readonly attributes: Record<string, string>;
209
+ readonly reference: string;
210
+ /** Price in minor units (cents), exactly as the source displays it. */
211
+ readonly price: number;
212
+ readonly currency: string;
213
+ readonly availability: 'available' | 'view_only';
214
+ }
215
+ /**
216
+ * What submit hands to the host: the buyer's selection and the reference to act
217
+ * on. Deliberately carries no price — the shop's checkout price is binding and
218
+ * ours is display-only, so handing it into the cart hand-off would only invite a
219
+ * wrong-price error. Price stays on the display side (`current`, `onChange`).
220
+ */
221
+ interface SubmittedConfiguration {
222
+ readonly attributes: Record<string, string>;
223
+ readonly reference: string;
224
+ }
225
+ /** Options for {@link Configuration.onSubmit}. */
226
+ interface SubmitOptions {
227
+ /** Fallback button label when the customer authored none (the adapter brings it). */
228
+ readonly defaultLabel?: string;
229
+ }
230
+ /**
231
+ * Resolves the current selection to a reference and a price, and carries it to
232
+ * the host page. `onChange` fires with the resolved configuration, or
233
+ * `undefined` when nothing matches; `onSubmit` registers the handler the CTA
234
+ * hands that configuration to.
235
+ */
236
+ declare class Configuration {
237
+ private readonly dispatchChange;
238
+ private readonly dispatchSubmit;
239
+ private pricing;
240
+ private selection;
241
+ private resolved;
242
+ private readonly changeCallbacks;
243
+ private readonly renderCallbacks;
244
+ private submitCallback;
245
+ private submitDefaultLabel;
246
+ /** The resolved configuration, or undefined when nothing matches. */
247
+ get current(): ResolvedConfiguration | undefined;
248
+ /** The VAT label for bare embeds (e.g. "incl. btw"), or undefined without pricing. */
249
+ get vatDisplay(): string | undefined;
250
+ /**
251
+ * The CTA label: the customer's `button_label`, or the adapter's `defaultLabel`
252
+ * when that is empty. Undefined when neither is set — a button must know what
253
+ * it says, so the CTA does not render.
254
+ */
255
+ get buttonLabel(): string | undefined;
256
+ /**
257
+ * Whether the current configuration may be submitted: a handler is registered
258
+ * and the configuration is either price-less or an `available` priced one. The
259
+ * CTA's visibility ({@link submitEnabled}) layers a label requirement on top of
260
+ * this; a programmatic `submit()` does not need a label.
261
+ */
262
+ private get submittable();
263
+ /**
264
+ * Whether the CTA should render: the configuration is submittable and a label
265
+ * exists. A button must say something, so an empty label hides the CTA rather
266
+ * than rendering blank.
267
+ */
268
+ get submitEnabled(): boolean;
269
+ /**
270
+ * Subscribe to configuration changes. Fires after every selection change with
271
+ * the resolved configuration, including undefined when nothing matches.
272
+ */
273
+ onChange(callback: (configuration: ResolvedConfiguration | undefined) => void): void;
274
+ /**
275
+ * Register the submit handler the CTA hands the configuration to. Registering
276
+ * one is what switches the button on (capability driven). `defaultLabel` fills
277
+ * in when the customer authored no button label.
278
+ */
279
+ onSubmit(callback: (configuration: SubmittedConfiguration) => void | Promise<unknown>, options?: SubmitOptions): void;
280
+ /**
281
+ * Hand the current configuration to the registered handler and fire the
282
+ * bubbling `vd:configuration-submit` event. No-op without a handler or a
283
+ * resolved configuration. Returns the handler's promise so the caller can
284
+ * reflect the result (bezig / gelukt / mislukt).
285
+ */
286
+ submit(): Promise<void>;
287
+ private recompute;
288
+ private notifyRender;
289
+ private resolve;
290
+ }
291
+
292
+ /** The focus state reported to `onChange` and the `vd:focus-change` event. */
293
+ interface FocusState {
294
+ readonly component: string;
295
+ readonly attributes: string[];
296
+ }
297
+ /**
298
+ * Isolate and frame one component, or return to the overview. Alongside
299
+ * `onChange` the container dispatches a bubbling `vd:focus-change` event, so a
300
+ * page can react without registering a callback.
301
+ */
302
+ declare class Focus {
303
+ private readonly send;
304
+ private readonly dispatch;
305
+ /** Which instance this facade addresses; every message it sends carries it. */
306
+ private readonly instance;
307
+ private focused;
308
+ private attributes;
309
+ private readonly changeCallbacks;
310
+ /** The focused component name, or null in overview. */
311
+ get current(): string | null;
312
+ /**
313
+ * Focus a component by name. Sends a focus message to the viewer.
314
+ * @throws VirtualdisplayError if component is not a non-empty string
315
+ */
316
+ set(component: string): void;
317
+ /** Return to the overview — unfocus the current component. */
318
+ clear(): void;
319
+ /**
320
+ * Subscribe to focus changes. The callback fires with the focus state when a
321
+ * component is focused, and with null when returning to overview.
322
+ */
323
+ onChange(callback: (state: FocusState | null) => void): void;
324
+ }
325
+
326
+ /**
327
+ * Error codes for Virtualdisplay client errors
328
+ */
329
+ declare const ERROR_CODES: {
330
+ readonly NO_MAPPING: "NO_MAPPING";
331
+ readonly ATTRIBUTE_NOT_FOUND: "ATTRIBUTE_NOT_FOUND";
332
+ readonly VALUE_NOT_FOUND: "VALUE_NOT_FOUND";
333
+ readonly PARENT_NOT_FOUND: "PARENT_NOT_FOUND";
334
+ readonly INVALID_PARAMETER: "INVALID_PARAMETER";
335
+ readonly SNAPSHOT_FAILED: "SNAPSHOT_FAILED";
336
+ };
337
+ type ErrorCode = typeof ERROR_CODES[keyof typeof ERROR_CODES];
338
+ /**
339
+ * Custom error class for Virtualdisplay client errors
340
+ */
341
+ declare class VirtualdisplayError extends Error {
342
+ readonly code: ErrorCode;
343
+ constructor(message: string, code: ErrorCode);
344
+ static valueNotFound(attributeName: string, valueName: string): VirtualdisplayError;
345
+ static parentNotFound(selector: string): VirtualdisplayError;
346
+ static invalidParameter(reason: string): VirtualdisplayError;
347
+ }
348
+
349
+ interface PhotoData {
350
+ readonly filename: string;
351
+ readonly data: string;
352
+ }
353
+ /**
354
+ * Represents a photo being captured
355
+ * Pure domain object that manages callbacks for when the photo is developed
356
+ */
357
+ declare class Photo {
358
+ private readonly filename;
359
+ private readonly developedCallbacks;
360
+ private readonly errorCallbacks;
361
+ private developed;
362
+ private failed;
363
+ private photoData;
364
+ /**
365
+ * Register a callback for when the photo is developed
366
+ * If the photo is already developed, the callback is called immediately
367
+ *
368
+ * @param callback Function to call with photo data
369
+ * @returns This Photo instance for chaining
370
+ */
371
+ onDeveloped(callback: (photo: PhotoData) => void): this;
372
+ /**
373
+ * Register a callback for when the photo capture fails
374
+ *
375
+ * @param callback Function to call with error
376
+ * @returns This Photo instance for chaining
377
+ */
378
+ onError(callback: (error: VirtualdisplayError) => void): this;
379
+ /**
380
+ * Get the filename for this photo
381
+ */
382
+ getFilename(): string;
383
+ }
384
+
385
+ /**
386
+ * API for taking screenshots of the 3D model
387
+ * Following the camera analogy: take() triggers capture, onDeveloped() gets result
388
+ */
389
+ declare class Snapshot {
390
+ private readonly send;
391
+ private readonly validExtensions;
392
+ private readonly pendingPhotos;
393
+ /**
394
+ * Take a snapshot of the current 3D model view
395
+ *
396
+ * @param filename The filename for the snapshot (must include valid extension)
397
+ * @returns Photo object for registering callbacks
398
+ * @throws VirtualdisplayError if filename is invalid
399
+ */
400
+ take(filename: string): Photo;
401
+ /**
402
+ * Fail any pending photos and forget them. Called from client destroy
403
+ * so callers awaiting onError() see a deterministic outcome instead of
404
+ * leaking captures whose results will never arrive.
405
+ */
406
+ clear(): void;
407
+ /**
408
+ * Validate filename has a valid image extension
409
+ */
410
+ private validateFilename;
411
+ }
412
+
413
+ /**
414
+ * Pure domain entity representing a single attribute value
415
+ * No side effects - only state
416
+ */
417
+ declare class AttributeValue {
418
+ readonly value: string;
419
+ readonly attribute: string;
420
+ private isSelectedValue;
421
+ get isSelected(): boolean;
422
+ }
423
+
424
+ /**
425
+ * Represents a single attribute with its available values
426
+ * Flat API - no source/target translation, works with server values directly
427
+ */
428
+ declare class Attribute {
429
+ readonly name: string;
430
+ readonly defaultValue: string | undefined;
431
+ private readonly values;
432
+ private readonly onSelect;
433
+ private onChangeCallback?;
434
+ /**
435
+ * Select a value for this attribute
436
+ * @throws {VirtualdisplayError} When value not found
437
+ */
438
+ select(value: string): void;
439
+ getValues(): AttributeValue[];
440
+ getValue(value: string): AttributeValue | undefined;
441
+ /** The currently selected value, or undefined before any selection lands. */
442
+ get selected(): string | undefined;
443
+ /**
444
+ * Register callback that fires when selection changes
445
+ * Receives the newly selected AttributeValue
446
+ */
447
+ onChange(callback: (selectedValue: AttributeValue) => void): void;
448
+ private createValues;
449
+ }
450
+
451
+ /**
452
+ * The client's DOM event names, in one registry. The two selection events are
453
+ * what `client.on(...)` subscribes to; the other three bubble out of the
454
+ * container, so the host page can reach them with `addEventListener`.
455
+ */
456
+ declare const VD_EVENTS: {
457
+ /** Attribute selection requested (cancelable, does not bubble). `detail`: `{ attribute, value }`. */
458
+ readonly SELECT: "vd:select";
459
+ /** Attribute selection applied (does not bubble). `detail`: `{ attribute, value }`. */
460
+ readonly SELECTED: "vd:selected";
461
+ /** Focus changed (bubbles). `detail`: `{ component, attributes }`, or `null` for the overview. */
462
+ readonly FOCUS_CHANGE: "vd:focus-change";
463
+ /** Resolved configuration changed (bubbles). `detail`: the resolved configuration, or `null` when nothing matches. */
464
+ readonly CONFIGURATION_CHANGE: "vd:configuration-change";
465
+ /** Configuration submitted (bubbles). `detail`: the resolved configuration handed to the host. */
466
+ readonly CONFIGURATION_SUBMIT: "vd:configuration-submit";
467
+ };
468
+ type VdEvent = typeof VD_EVENTS[keyof typeof VD_EVENTS];
469
+
470
+ interface MutationFailedEvent {
471
+ readonly attribute: string;
472
+ readonly value: string;
473
+ }
474
+ /**
475
+ * Which app the viewer resolved, as handed to an `onAppResolved` callback.
476
+ */
477
+ interface ResolvedAppInfo {
478
+ /** Known values: `AppType`. An unknown value means a newer server; report it, never downgrade to a viewer. */
479
+ readonly appType: string;
480
+ readonly name: string;
481
+ /** The app's public slug (the address a submit POSTs to). Absent from a pre-slug server. */
482
+ readonly slug?: string;
483
+ readonly submit?: AppSubmitSettings;
484
+ }
485
+ interface VirtualdisplaySelectEvent {
486
+ readonly attribute: string;
487
+ readonly value: string;
488
+ preventDefault(): void;
489
+ }
490
+ interface VirtualdisplaySelectedEvent {
491
+ readonly attribute: string;
492
+ readonly value: string;
493
+ }
494
+ type VirtualdisplayUiEventMap = {
495
+ [VD_EVENTS.SELECT]: VirtualdisplaySelectEvent;
496
+ [VD_EVENTS.SELECTED]: VirtualdisplaySelectedEvent;
497
+ };
498
+ type VirtualdisplayUiEventType = keyof VirtualdisplayUiEventMap;
499
+
500
+ /**
501
+ * The shared client composition root: wires the transport, facades and UI, and
502
+ * exposes the integrator-facing API.
503
+ */
504
+ declare class BaseClient {
505
+ private readonly attributes;
506
+ private readonly selectableState;
507
+ private readonly readyStateTracker;
508
+ private readonly messenger;
509
+ private readonly cameraApi;
510
+ private readonly cameraPositionApi;
511
+ private readonly focusApi;
512
+ private readonly configurationApi;
513
+ private readonly snapshotApi;
514
+ private readonly annotationsApi;
515
+ private readonly eventBus;
516
+ private readonly ui;
517
+ private readonly options;
518
+ private readonly serverHost;
519
+ private readonly iframeParams;
520
+ private readonly arActivation;
521
+ private readonly syncTracker;
522
+ private iframe;
523
+ private container;
524
+ private readyCallbacks;
525
+ private readonly mutationFailedCallbacks;
526
+ private viewerSessionId;
527
+ private resolvedApp;
528
+ private readonly appResolvedCallbacks;
529
+ private createStandardInterface;
530
+ private sendControlAnnotationToggle;
531
+ private wireIncomingMessages;
532
+ private handleAppResolved;
533
+ private handleSession;
534
+ private notifyMutationFailed;
535
+ private notifyReady;
536
+ private dispatchFocusChange;
537
+ private dispatchConfigurationChange;
538
+ private dispatchConfigurationSubmit;
539
+ private handleConfig;
540
+ private echoAnnotationsDifference;
541
+ private trackFullscreen;
542
+ private initializeLogging;
543
+ private createAndConnectIframe;
544
+ select(name: string, value: string): void;
545
+ getValues(name: string): AttributeValue[];
546
+ getValue(name: string, value: string): AttributeValue | undefined;
547
+ onChange(name: string, callback: (selectedValue: AttributeValue) => void): void;
548
+ getAttribute(name: string): Attribute | undefined;
549
+ get isReady(): boolean;
550
+ onReady(callback: (client: this) => void): void;
551
+ onMutationFailed(callback: (event: MutationFailedEvent) => void): void;
552
+ /**
553
+ * Subscribe to which values can be picked right now, per attribute. Fires
554
+ * immediately when a snapshot already arrived. A model with no exclusions
555
+ * never sends one, so this never fires and everything stays selectable.
556
+ */
557
+ onSelectableChange(callback: (snapshot: SelectableSnapshot) => void): void;
558
+ /**
559
+ * Subscribe to which app this viewer resolved (type, name, public submit
560
+ * settings). Reported once by the viewer after its resolve; fires immediately
561
+ * when the report already arrived, so registration order does not matter.
562
+ */
563
+ onAppResolved(callback: (app: ResolvedAppInfo) => void): void;
564
+ /** The selectable values for one attribute right now, or null when unrestricted. */
565
+ getSelectable(name: string): readonly string[] | null;
566
+ /**
567
+ * Start the AR flow directly, as the built-in AR button would. Does nothing
568
+ * when `viewerSettings.ar` is off or the build composes no AR flow.
569
+ */
570
+ activateAr(): void;
571
+ on<T extends VirtualdisplayUiEventType>(type: T, callback: (event: VirtualdisplayUiEventMap[T]) => void): void;
572
+ get annotations(): Annotations;
573
+ get camera(): Camera;
574
+ get focus(): Focus;
575
+ get configuration(): Configuration;
576
+ get cameraPosition(): CameraPosition;
577
+ get snapshot(): Snapshot;
578
+ /** The viewer's tracking session id, for a host page to correlate its own actions. */
579
+ get sessionId(): string | undefined;
580
+ get viewerSettings(): ViewerSettings;
581
+ destroy(): void;
582
+ }
583
+
584
+ /**
585
+ * The integrator-facing viewer settings override. Identical to the wire
586
+ * `ViewerSettings`, except `annotations` also accepts the legacy booleans:
587
+ * they normalise before the merge (`true` → `show`, `false` → `hide`), so
588
+ * existing mounts keep compiling while the package is in alpha.
589
+ */
590
+ type ViewerSettingsOverride = Omit<Partial<ViewerSettings>, 'annotations'> & {
591
+ readonly annotations?: boolean | AnnotationVisibility;
592
+ };
593
+ /**
594
+ * Options shared by both address forms.
595
+ */
596
+ interface ClientOptionsBase {
597
+ readonly parent: string | HTMLElement;
598
+ readonly debug?: boolean | undefined;
599
+ readonly language?: string | undefined;
600
+ /** W3C traceparent string to propagate to the viewer iframe for end-to-end tracing. */
601
+ readonly traceparent?: string | undefined;
602
+ /**
603
+ * A source viewer session id to restore into this mount (ar-session-handoff): the
604
+ * iframe's metadata fetch merges that session's latest configuration into the
605
+ * attribute defaults, so the viewer boots straight into it. Internal option, used
606
+ * by the AR landing, not a customer-facing setting.
607
+ */
608
+ readonly session?: string | undefined;
609
+ /**
610
+ * Override viewer settings from metadata. Omitted fields use the metadata value.
611
+ * A warning is logged when an override differs from the metadata value.
612
+ */
613
+ readonly viewerSettings?: ViewerSettingsOverride;
614
+ }
615
+ /**
616
+ * What the client shows, given either way of naming it: `{ app }`, an app's
617
+ * public link key, or `{ license, model }`, which resolves to that model's
618
+ * default app. Given both, `app` wins and the pair is ignored with a warning.
619
+ */
620
+ type ClientAddress = {
621
+ readonly app: string;
622
+ readonly license?: string | undefined;
623
+ readonly model?: string | undefined;
624
+ } | {
625
+ readonly license: string;
626
+ readonly model: string;
627
+ readonly app?: undefined;
628
+ };
629
+ /**
630
+ * Configuration options for VirtualdisplayClient
631
+ */
632
+ type ClientOptions = ClientOptionsBase & ClientAddress;
633
+
634
+ /**
635
+ * The logger the client exposes: the same four levels as the base logger, but
636
+ * accepting any value as attributes so callers can pass an Error or a bare value.
637
+ */
638
+ interface ClientLogger {
639
+ debug: (msg: string, attrs?: unknown) => void;
640
+ info: (msg: string, attrs?: unknown) => void;
641
+ warn: (msg: string, attrs?: unknown) => void;
642
+ error: (msg: string, attrs?: unknown) => void;
643
+ }
644
+ declare let logger: ClientLogger;
645
+ declare function enableDebugMode(): void;
646
+ declare function isDebugMode(): boolean;
647
+
648
+ /**
649
+ * The Virtualdisplay client: point it at a container and an app or model, and it
650
+ * renders the viewer with the standard interface, the configurator and AR.
651
+ */
652
+ declare class VirtualdisplayClient extends BaseClient {
653
+ private readonly syncStatusTracker;
654
+ constructor(options: ClientOptions);
655
+ /** Subscribe to the live sync channel's connection state (ar-session-handoff). Latest-wins, no buffering. */
656
+ onSyncChange(callback: (connected: boolean) => void): void;
657
+ }
658
+
659
+ export { AVAILABILITY, Annotations, Attribute, AttributeValue, Camera, CameraPosition, Configuration, ERROR_CODES, Focus, Photo, Snapshot, VD_EVENTS, VirtualdisplayClient, VirtualdisplayError, enableDebugMode, isDebugMode, logger };
660
+ export type { AnnotationVisibility, AppSubmitSettings, AppType, Availability, CameraLimits, CameraPositionState, ClientAddress, ClientLogger, ClientOptions, ClientOptionsBase, ErrorCode, FocusState, MutationFailedEvent, PhotoData, PricingDocument, PricingRule, ResolvedAppInfo, ResolvedConfiguration, SelectableAttribute, SelectableSnapshot, SubmitOptions, SubmittedConfiguration, VdEvent, ViewerSettings, ViewerSettingsOverride, VirtualdisplaySelectEvent, VirtualdisplaySelectedEvent, VirtualdisplayUiEventMap, VirtualdisplayUiEventType };