@virtualdisplay.io/client 4.0.0-alpha.26 → 4.0.0-alpha.27

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 4.0.0-alpha.27
4
+
5
+ ### Minor Changes
6
+
7
+ Add the per-app annotation visibility modes to the `viewerSettings.annotations` override: `'hide'`, `'show'`, `'toggle-shown'` and `'toggle-hidden'`, besides the existing booleans (`true` maps to `'show'`, `false` to `'hide'`). Markers now follow the mode configured on the app, and an override only speaks up when it differs from that mode.
8
+
3
9
  ## 4.0.0-alpha.26
4
10
 
5
11
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -52,6 +52,29 @@ interface AppResolvedMessage {
52
52
  readonly slug?: string;
53
53
  readonly submit?: AppSubmitSettings$1;
54
54
  }
55
+ /** One mesh or material variant in a model, as reported by STATE. */
56
+ interface ModelNodeDto {
57
+ readonly id: string;
58
+ readonly name: string;
59
+ readonly type: string;
60
+ readonly visible: boolean;
61
+ }
62
+ /**
63
+ * State (viewer → client): the meshes and material variants of one instance,
64
+ * with their current visibility.
65
+ *
66
+ * Its shape used to live in server-core, marked "server-only", while its type
67
+ * value sat in the public MESSAGE_TYPES and the client read it: a public
68
+ * message whose shape only one side declared, which is how two shapes of one
69
+ * thing start to drift.
70
+ */
71
+ interface StateMessage {
72
+ readonly type: typeof MESSAGE_TYPES.STATE;
73
+ /** Whose meshes and variants these are. */
74
+ readonly instance: string;
75
+ readonly nodes: ModelNodeDto[];
76
+ readonly isInitial: boolean;
77
+ }
55
78
  interface MutationDto {
56
79
  readonly name: string;
57
80
  readonly value: string;
@@ -75,6 +98,8 @@ interface SyncStateSnapshot {
75
98
  }
76
99
  interface MutationMessage {
77
100
  readonly type: typeof MESSAGE_TYPES.MUTATION;
101
+ /** Which instance's attributes these mutations change. */
102
+ readonly instance: string;
78
103
  readonly mutations: MutationDto[];
79
104
  readonly isInitial: boolean;
80
105
  /**
@@ -117,9 +142,18 @@ interface SyncMessage {
117
142
  }
118
143
  interface MutationResultMessage {
119
144
  readonly type: typeof MESSAGE_TYPES.MUTATION;
145
+ /** Which instance these results are for; without it a failure cannot say whose. */
146
+ readonly instance: string;
120
147
  readonly results: MutationResult[];
121
148
  readonly isInitial: boolean;
122
149
  }
150
+ /**
151
+ * How a model's annotations present to the Shopper: never (hide), always
152
+ * (show), or under the Shopper's own control via a viewer toggle, starting
153
+ * visible (toggle-shown) or hidden (toggle-hidden). Resolved per app; the
154
+ * backend's `Resolve` owns the `hide` default.
155
+ */
156
+ type AnnotationVisibility$1 = 'hide' | 'show' | 'toggle-shown' | 'toggle-hidden';
123
157
  /**
124
158
  * Viewer settings from model metadata (server → client via MAPPING).
125
159
  * Customer-configured in the portal.
@@ -129,7 +163,12 @@ interface ViewerSettings$1 {
129
163
  readonly fullscreen?: boolean;
130
164
  readonly screenshot?: boolean;
131
165
  readonly cameraControls?: boolean;
132
- readonly annotations?: boolean;
166
+ /**
167
+ * The resolved per-app annotation mode. Present only when the model has
168
+ * annotations, so a control can never render with nothing to govern;
169
+ * absent means there is nothing to show or toggle.
170
+ */
171
+ readonly annotations?: AnnotationVisibility$1;
133
172
  readonly language?: string;
134
173
  /** Where the attribute controls sit: in-frame bottom-left (default) or a docked right panel. */
135
174
  readonly configuratorLayout?: 'inframe-bottom-left' | 'sidebar-right' | 'hidden';
@@ -194,6 +233,12 @@ interface AttributeDefinition {
194
233
  }
195
234
  interface MappingMessage {
196
235
  readonly type: typeof MESSAGE_TYPES.MAPPING;
236
+ /**
237
+ * Whose attributes these are. One MAPPING per instance, and an instance with
238
+ * no attributes sends an empty one rather than none: silence would leave the
239
+ * client unable to name it, click it or report its interactions.
240
+ */
241
+ readonly instance: string;
197
242
  readonly attributes: AttributeDefinition[];
198
243
  }
199
244
  /** Per selector, the values the buyer can still pick right now. */
@@ -218,11 +263,30 @@ interface SelectableAttribute {
218
263
  */
219
264
  interface SelectableMessage {
220
265
  readonly type: typeof MESSAGE_TYPES.SELECTABLE;
266
+ /** Whose attributes these are, mirroring the MAPPING it follows. */
267
+ readonly instance: string;
221
268
  readonly attributes: SelectableAttribute[];
222
269
  }
223
270
  /**
224
271
  * Loading indicator (server → client): progress percentage, phase label, or error.
225
272
  * Sent during model download and parse so the client loading indicator can update.
273
+ *
274
+ * This message concerns one model at five of its seven call sites (download
275
+ * progress, a load error, the rendering phase) and is fatal with no model to
276
+ * blame at the other two (no WebGL, the boot-failure path), so by the
277
+ * message-scope rule it takes an instance id optionally.
278
+ *
279
+ * It does not carry one yet, on purpose. `publishLoadingProgress` is the only
280
+ * publisher and knows no instance, so the field would be absent at all seven
281
+ * sites while its documented meaning is "absent means the viewer could not
282
+ * start". An integrator branching on that would read every progress update as
283
+ * a viewer failure, which is worse than no field at all.
284
+ *
285
+ * Nothing is lost by waiting: an optional field is additive, so unlike the
286
+ * required ids in this file it carries no alpha-window pressure. Composition
287
+ * task 10 brings a second model and with it the choice the spec parked, thread
288
+ * the id through the five model sites, or split the fatal case onto its own
289
+ * message. Decide it there, with a real second instance to test against.
226
290
  */
227
291
  interface LoadingIndicatorMessage {
228
292
  readonly type: typeof MESSAGE_TYPES.LOADING_INDICATOR;
@@ -284,6 +348,13 @@ interface SessionMessage {
284
348
  */
285
349
  interface AnnotationToggleMessage {
286
350
  readonly type: typeof MESSAGE_TYPES.ANNOTATION_TOGGLE;
351
+ /**
352
+ * Whose pins to show. This looks scene-wide because the client draws one
353
+ * button, and it is not: a pin's position is stored in its model's local
354
+ * space, so it means nothing without the root it belongs to. A client that
355
+ * wants one button loops over the instances, which is a UI decision.
356
+ */
357
+ readonly instance: string;
287
358
  readonly enabled: boolean;
288
359
  }
289
360
  /** Focus actions (client → server). */
@@ -306,6 +377,8 @@ type FocusStateValue = (typeof FOCUS_STATES)[keyof typeof FOCUS_STATES];
306
377
  */
307
378
  interface FocusMessage {
308
379
  readonly type: typeof MESSAGE_TYPES.FOCUS;
380
+ /** Which instance the component name resolves inside. */
381
+ readonly instance: string;
309
382
  readonly action: FocusAction;
310
383
  readonly component?: string;
311
384
  }
@@ -316,6 +389,8 @@ interface FocusMessage {
316
389
  */
317
390
  interface FocusStateMessage {
318
391
  readonly type: typeof MESSAGE_TYPES.FOCUS;
392
+ /** Which instance this state is about. */
393
+ readonly instance: string;
319
394
  readonly state: FocusStateValue;
320
395
  readonly component?: string;
321
396
  readonly attributes?: string[];
@@ -373,9 +448,16 @@ interface PricingDocument$1 {
373
448
  */
374
449
  interface PricingMessage {
375
450
  readonly type: typeof MESSAGE_TYPES.PRICING;
451
+ /**
452
+ * Which instance is priced. Only one is today, so the id has no alternative
453
+ * value to hold; it carries one anyway, because a rule with a "not needed
454
+ * yet" exception erodes, and a scene of separately priced products needs
455
+ * exactly this field.
456
+ */
457
+ readonly instance: string;
376
458
  readonly pricing: PricingDocument$1;
377
459
  }
378
- type Message = HandshakeMessage | SessionMessage | MutationMessage | MutationResultMessage | CameraCommandMessage | CameraPositionMessage | SnapshotRequestMessage | SnapshotResultMessage | MappingMessage | LoadingIndicatorMessage | ArActivateMessage | FullscreenMessage | ConfigMessage | AnnotationToggleMessage | FocusMessage | FocusStateMessage | PricingMessage | QrShownMessage | SyncMessage | SelectableMessage | AppResolvedMessage;
460
+ type Message = HandshakeMessage | SessionMessage | MutationMessage | MutationResultMessage | CameraCommandMessage | CameraPositionMessage | SnapshotRequestMessage | SnapshotResultMessage | MappingMessage | LoadingIndicatorMessage | ArActivateMessage | FullscreenMessage | ConfigMessage | AnnotationToggleMessage | FocusMessage | FocusStateMessage | PricingMessage | QrShownMessage | SyncMessage | SelectableMessage | AppResolvedMessage | StateMessage;
379
461
  type MessageCallback = (message: Message) => void | Promise<void>;
380
462
 
381
463
  /**
@@ -490,14 +572,6 @@ declare class IframeMessenger {
490
572
  * Stop listening and clean up all state
491
573
  */
492
574
  destroy(): void;
493
- /**
494
- * Whether the messenger is ready to send
495
- */
496
- get ready(): boolean;
497
- /**
498
- * Number of messages waiting in the outgoing queue
499
- */
500
- get pendingCount(): number;
501
575
  private post;
502
576
  private routeToHandler;
503
577
  }
@@ -511,7 +585,11 @@ type SendFn$1 = (message: Message) => void;
511
585
  */
512
586
  declare class Annotations {
513
587
  private readonly send;
514
- constructor(send: SendFn$1);
588
+ /** Whose pins this facade toggles: a pin lives in one model's local space. */
589
+ private readonly instance;
590
+ constructor(send: SendFn$1,
591
+ /** Whose pins this facade toggles: a pin lives in one model's local space. */
592
+ instance: string);
515
593
  setEnabled(enabled: boolean): void;
516
594
  }
517
595
 
@@ -743,10 +821,14 @@ type DispatchFn = (state: FocusChange) => void;
743
821
  declare class Focus {
744
822
  private readonly send;
745
823
  private readonly dispatch;
824
+ /** Which instance this facade addresses; every message it sends carries it. */
825
+ private readonly instance;
746
826
  private focused;
747
827
  private attributes;
748
828
  private readonly changeCallbacks;
749
- constructor(send: MessageCallback, dispatch: DispatchFn);
829
+ constructor(send: MessageCallback, dispatch: DispatchFn,
830
+ /** Which instance this facade addresses; every message it sends carries it. */
831
+ instance: string);
750
832
  /** The focused component name, or null in overview. */
751
833
  get current(): string | null;
752
834
  /**
@@ -920,6 +1002,15 @@ declare class Attribute {
920
1002
  private createValues;
921
1003
  }
922
1004
 
1005
+ /**
1006
+ * The integrator-facing viewer settings override. Identical to the wire
1007
+ * `ViewerSettings`, except `annotations` also accepts the legacy booleans:
1008
+ * they normalise before the merge (`true` → `show`, `false` → `hide`), so
1009
+ * existing mounts keep compiling while the package is in alpha.
1010
+ */
1011
+ type ViewerSettingsOverride = Omit<Partial<ViewerSettings$1>, 'annotations'> & {
1012
+ readonly annotations?: boolean | AnnotationVisibility$1;
1013
+ };
923
1014
  /**
924
1015
  * Options shared by both address forms.
925
1016
  */
@@ -940,7 +1031,7 @@ interface ClientOptionsBase {
940
1031
  * Override viewer settings from metadata. Omitted fields use the metadata value.
941
1032
  * A warning is logged when an override differs from the metadata value.
942
1033
  */
943
- readonly viewerSettings?: Partial<ViewerSettings$1>;
1034
+ readonly viewerSettings?: ViewerSettingsOverride;
944
1035
  }
945
1036
  /**
946
1037
  * How the client addresses what it shows, one of two forms:
@@ -1145,6 +1236,14 @@ declare class BaseClient {
1145
1236
  /** Dispatch a bubbling `vd:configuration-submit` event when the CTA is used. */
1146
1237
  private dispatchConfigurationSubmit;
1147
1238
  private handleConfig;
1239
+ /**
1240
+ * The difference echo: the viewer already applied the app-config mode
1241
+ * itself, so the client only speaks up when the merged mode (config plus
1242
+ * integrator override) differs from what CONFIG announced, in either
1243
+ * direction. Equal modes echo nothing, so a boot without overrides sends
1244
+ * no toggle at all.
1245
+ */
1246
+ private echoAnnotationsDifference;
1148
1247
  /** Tell the viewer the user entered fullscreen, so it records the engagement. */
1149
1248
  private trackFullscreen;
1150
1249
  private initializeLogging;
@@ -1241,6 +1340,13 @@ interface AppSubmitSettings {
1241
1340
  readonly ctaLabel?: string;
1242
1341
  readonly privacyUrl?: string;
1243
1342
  }
1343
+ /**
1344
+ * How a model's annotations present to the Shopper: never (hide), always
1345
+ * (show), or under the Shopper's own control via a viewer toggle, starting
1346
+ * visible (toggle-shown) or hidden (toggle-hidden). Resolved per app; the
1347
+ * backend's `Resolve` owns the `hide` default.
1348
+ */
1349
+ type AnnotationVisibility = 'hide' | 'show' | 'toggle-shown' | 'toggle-hidden';
1244
1350
  /**
1245
1351
  * Viewer settings from model metadata (server → client via MAPPING).
1246
1352
  * Customer-configured in the portal.
@@ -1250,7 +1356,12 @@ interface ViewerSettings {
1250
1356
  readonly fullscreen?: boolean;
1251
1357
  readonly screenshot?: boolean;
1252
1358
  readonly cameraControls?: boolean;
1253
- readonly annotations?: boolean;
1359
+ /**
1360
+ * The resolved per-app annotation mode. Present only when the model has
1361
+ * annotations, so a control can never render with nothing to govern;
1362
+ * absent means there is nothing to show or toggle.
1363
+ */
1364
+ readonly annotations?: AnnotationVisibility;
1254
1365
  readonly language?: string;
1255
1366
  /** Where the attribute controls sit: in-frame bottom-left (default) or a docked right panel. */
1256
1367
  readonly configuratorLayout?: 'inframe-bottom-left' | 'sidebar-right' | 'hidden';