@alliumcloud/configurator-service 1.0.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/README.md ADDED
@@ -0,0 +1,1134 @@
1
+ # @alliumcloud/configurator-service
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@alliumcloud/configurator-service)](https://www.npmjs.com/package/@alliumcloud/configurator-service)
4
+ [![npm downloads](https://img.shields.io/npm/dt/@alliumcloud/configurator-service)](https://www.npmjs.com/package/@alliumcloud/configurator-service)
5
+
6
+ Official TypeScript SDK for the Allium Configurator backend. Provides a fully typed, modular HTTP client for all space configuration operations — media screens, 3D objects, transforms, layers, and configurator items.
7
+
8
+ ---
9
+
10
+ ## Table of Contents
11
+
12
+ - [Installation](#installation)
13
+ - [Quick Start](#quick-start)
14
+ - [Architecture](#architecture)
15
+ - [Configuration](#configuration)
16
+ - [Error Handling](#error-handling)
17
+ - [Debug Logging](#debug-logging)
18
+ - [API Reference](#api-reference)
19
+ - [Media](#media)
20
+ - [Sketchfab](#sketchfab)
21
+ - [Transform](#transform)
22
+ - [Layer](#layer)
23
+ - [Configurator Items](#configurator-items)
24
+ - [Configurator Objects](#configurator-objects)
25
+ - [Types Reference](#types-reference)
26
+ - [Config](#config)
27
+ - [Common](#common)
28
+ - [Media Types](#media-types)
29
+ - [Sketchfab Types](#sketchfab-types)
30
+ - [Transform Types](#transform-types)
31
+ - [Layer Types](#layer-types)
32
+ - [Configurator Item Types](#configurator-item-types)
33
+ - [Configurator Object Types](#configurator-object-types)
34
+ - [Error Types](#error-types)
35
+ - [Versioning](#versioning)
36
+
37
+ ---
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ npm install @alliumcloud/configurator-service
43
+ # or
44
+ yarn add @alliumcloud/configurator-service
45
+ # or
46
+ pnpm add @alliumcloud/configurator-service
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Quick Start
52
+
53
+ ```typescript
54
+ import { createConfiguratorSDK } from "@alliumcloud/configurator-service";
55
+
56
+ // Initialize once — pass your API key, that's it.
57
+ const sdk = createConfiguratorSDK({
58
+ apiKey: "your-api-key",
59
+ jwksUri: "https://your-auth-domain/.well-known/jwks.json", // JWKS is optional here
60
+ accessTokenProvider: async () => await yourAuthService.getToken(),
61
+ });
62
+
63
+ // Add a 3D model to a space
64
+ await sdk.sketchfab.addObject({
65
+ orgId: "org-id",
66
+ spaceId: "space-id",
67
+ spaceItemId: "item-id",
68
+ name: "My Model",
69
+ type: "RuntimeModel",
70
+ gltfUrl: "https://...",
71
+ materialOverrideId: "None",
72
+ scale: { x: 1, y: 1, z: 1 },
73
+ autoScale: true,
74
+ offsetUniformScale: 1,
75
+ collisionsEnabled: false,
76
+ position: { x: 0, y: 0, z: 0 },
77
+ rotation: { x: 0, y: 0, z: 0 },
78
+ offsetUpRotation: 0,
79
+ });
80
+
81
+ // Update its position
82
+ await sdk.transform.updatePosition("item-id", {
83
+ orgId: "org-id",
84
+ spaceId: "space-id",
85
+ spaceItemId: "item-id",
86
+ position: { x: 3, y: 0, z: 0 },
87
+ });
88
+ ```
89
+
90
+ You can also use the namespace default export:
91
+
92
+ ```typescript
93
+ import ConfiguratorSDK from "@alliumcloud/configurator-service";
94
+
95
+ const sdk = ConfiguratorSDK.create({
96
+ apiKey: "your-api-key",
97
+ jwksUri: "https://your-auth-domain/.well-known/jwks.json", // JWKS is optional here
98
+ accessTokenProvider: async () => await yourAuthService.getToken(),
99
+ });
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Architecture
105
+
106
+ The SDK is structured as a set of isolated, focused modules. Each module handles one domain of the backend API. All modules share a single configured HTTP client that is created once at initialization.
107
+
108
+ ```
109
+ createConfiguratorSDK({ apiKey })
110
+
111
+ ├── sdk.media → /media
112
+ ├── sdk.sketchfab → /sketchfab
113
+ ├── sdk.transform → /transform
114
+ ├── sdk.layer → /layer
115
+ ├── sdk.configuratorItems → /configurator_items
116
+ └── sdk.configuratorObjects → /configurator_objects
117
+ ```
118
+
119
+ **Key design decisions:**
120
+
121
+ - The backend base URL is baked into the SDK at build time. You never pass a URL — it is not configurable by consumers.
122
+ - Your API key is passed once at initialization and is automatically injected as `x-sdk-key` on every request.
123
+ - All errors are normalized into typed `AlliumError` objects with a `code` and `name` so you can catch them reliably.
124
+ - Debug logging is fully opt-in and zero-cost in production.
125
+
126
+ ---
127
+
128
+ ## Configuration
129
+
130
+ ```typescript
131
+ import {
132
+ createConfiguratorSDK,
133
+ ConfiguratorServiceSDKConfig,
134
+ } from "@alliumcloud/configurator-service";
135
+
136
+ const sdk = createConfiguratorSDK({
137
+ apiKey: "your-api-key",
138
+ jwksUri: "https://your-auth-domain/.well-known/jwks.json",
139
+ accessTokenProvider: async () => await yourAuthService.getToken(),
140
+ timeout: 60_000,
141
+ });
142
+ ```
143
+
144
+ | Option | Type | Required | Default | Description |
145
+ | --------------------- | --------------------------------- | -------- | ------- | ------------------------------------------------------------------------------- |
146
+ | `apiKey` | `string` | Yes | — | API key issued after SDK purchase. Sent as `x-sdk-key` header on every request. |
147
+ | `jwksUri` | `string` | No | — | JWKS endpoint URI. Sent as `x-jwks-uri` on every request. |
148
+ | `accessTokenProvider` | `() => string \| Promise<string>` | Yes | — | Called before every request to retrieve a Bearer token. |
149
+ | `timeout` | `number` | No | `30000` | Request timeout in milliseconds. |
150
+
151
+ ---
152
+
153
+ ## Error Handling
154
+
155
+ All SDK errors are instances of `AlliumError`. You can use `isAlliumError()` to safely narrow the type in catch blocks.
156
+
157
+ ```typescript
158
+ import { isAlliumError } from "@alliumcloud/configurator-service";
159
+
160
+ try {
161
+ await sdk.sketchfab.addObject({ ... });
162
+ } catch (err) {
163
+ if (isAlliumError(err)) {
164
+ console.log(err.name); // e.g. 'AlliumAuthError'
165
+ console.log(err.code); // e.g. 'AUTH_ERROR'
166
+ console.log(err.message); // human-readable description
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### Error Types
172
+
173
+ | `err.name` | `err.code` | When it is thrown |
174
+ | ----------------------- | ------------------ | ----------------------------------------------------------- |
175
+ | `AlliumConfigError` | `INVALID_CONFIG` | API key is missing or base URL not configured in the build. |
176
+ | `AlliumAuthError` | `AUTH_ERROR` | Server returns `401` or `403` — key is invalid or expired. |
177
+ | `AlliumValidationError` | `VALIDATION_ERROR` | Server returns `400` or `422` — bad input data. |
178
+ | `AlliumRequestError` | `REQUEST_ERROR` | Network failure, timeout, or any other `5xx` response. |
179
+ | `AlliumSDKError` | `SDK_ERROR` | Generic fallback for uncategorized errors. |
180
+
181
+ ---
182
+
183
+ ## Debug Logging
184
+
185
+ The SDK ships with a built-in debug logger that is completely silent by default. Enable it to see every outgoing request, response status, and module-level operation in your console.
186
+
187
+ **In Node.js:**
188
+
189
+ ```bash
190
+ ALLIUM_DEBUG=true node your-script.js
191
+ ```
192
+
193
+ **In the browser:**
194
+
195
+ ```javascript
196
+ window.ALLIUM_DEBUG = true;
197
+ ```
198
+
199
+ All log lines are prefixed with a timestamp and category:
200
+
201
+ ```
202
+ [14:23:01.452][SDK:HTTP] → POST /sketchfab/object
203
+ [14:23:01.891][SDK:HTTP] ← 200 /sketchfab/object
204
+ [14:23:01.892][SDK:Sketchfab] addObject { orgId: '...', spaceItemId: '...' }
205
+ ```
206
+
207
+ ---
208
+
209
+ ## API Reference
210
+
211
+ ### Media
212
+
213
+ #### `sdk.media.addVideo(data)`
214
+
215
+ Add a Vimeo video screen to a space.
216
+
217
+ ```typescript
218
+ await sdk.media.addVideo({
219
+ orgId: "org-id",
220
+ spaceId: "space-id",
221
+ spaceItemId: "item-id",
222
+ name: "My Video",
223
+ type: "SpatialMedia",
224
+ mediaType: "video",
225
+ url: "https://vimeo.com/...",
226
+ attenuation: 1000,
227
+ volume: 100,
228
+ loop: true,
229
+ audioOnly: false,
230
+ showPreview: false,
231
+ position: { x: 0, y: 1, z: 0 },
232
+ rotation: { x: 0, y: 0, z: 0 },
233
+ offsetUpRotation: 0,
234
+ });
235
+ ```
236
+
237
+ **Returns:** `Promise<void>`
238
+
239
+ ---
240
+
241
+ #### `sdk.media.updateVideo(spaceItemId, data)`
242
+
243
+ Update properties of an existing video screen.
244
+
245
+ ```typescript
246
+ await sdk.media.updateVideo("item-id", {
247
+ orgId: "org-id",
248
+ spaceId: "space-id",
249
+ spaceItemId: "item-id",
250
+ url: "https://vimeo.com/new-video",
251
+ volume: 80,
252
+ loop: false,
253
+ });
254
+ ```
255
+
256
+ | Field | Type | Required | Description |
257
+ | ------------- | --------- | -------- | ----------------------------- |
258
+ | `orgId` | `string` | Yes | Organization ID. |
259
+ | `spaceId` | `string` | Yes | Space ID. |
260
+ | `spaceItemId` | `string` | Yes | Space item ID. |
261
+ | `url` | `string` | No | New Vimeo URL. |
262
+ | `volume` | `number` | No | Volume level (0–100). |
263
+ | `attenuation` | `number` | No | Audio attenuation distance. |
264
+ | `loop` | `boolean` | No | Whether to loop the video. |
265
+ | `audioOnly` | `boolean` | No | Play audio only, no visuals. |
266
+ | `showPreview` | `boolean` | No | Show video preview thumbnail. |
267
+
268
+ **Returns:** `Promise<void>`
269
+
270
+ ---
271
+
272
+ #### `sdk.media.addLink(data)`
273
+
274
+ Add a website link screen to a space.
275
+
276
+ ```typescript
277
+ await sdk.media.addLink({
278
+ orgId: "org-id",
279
+ spaceId: "space-id",
280
+ spaceItemId: "item-id",
281
+ name: "My Link",
282
+ type: "SpatialMedia",
283
+ mediaType: "link",
284
+ url: "https://example.com",
285
+ attenuation: 1000,
286
+ isPortrait: false,
287
+ openInNewTab: true,
288
+ position: { x: 0, y: 1, z: 0 },
289
+ rotation: { x: 0, y: 0, z: 0 },
290
+ offsetUpRotation: 0,
291
+ });
292
+ ```
293
+
294
+ **Returns:** `Promise<void>`
295
+
296
+ ---
297
+
298
+ #### `sdk.media.updateLink(spaceItemId, data)`
299
+
300
+ Update properties of an existing link screen.
301
+
302
+ ```typescript
303
+ await sdk.media.updateLink("item-id", {
304
+ orgId: "org-id",
305
+ spaceId: "space-id",
306
+ spaceItemId: "item-id",
307
+ url: "https://new-url.com",
308
+ isPortrait: true,
309
+ });
310
+ ```
311
+
312
+ | Field | Type | Required | Description |
313
+ | -------------- | --------- | -------- | ------------------------------- |
314
+ | `orgId` | `string` | Yes | Organization ID. |
315
+ | `spaceId` | `string` | Yes | Space ID. |
316
+ | `spaceItemId` | `string` | Yes | Space item ID. |
317
+ | `url` | `string` | No | New website URL. |
318
+ | `name` | `string` | No | Display name. |
319
+ | `openInNewTab` | `boolean` | No | Open link in a new tab. |
320
+ | `isPortrait` | `boolean` | No | Render screen in portrait mode. |
321
+
322
+ **Returns:** `Promise<void>`
323
+
324
+ ---
325
+
326
+ #### `sdk.media.addStream(data)`
327
+
328
+ Add a live stream screen to a space.
329
+
330
+ ```typescript
331
+ await sdk.media.addStream({
332
+ orgId: "org-id",
333
+ spaceId: "space-id",
334
+ spaceItemId: "item-id",
335
+ name: "My Stream",
336
+ type: "RuntimeStream",
337
+ spaceStreamId: "stream-id",
338
+ scale: { x: 1, y: 1, z: 1 },
339
+ offsetUniformScale: 1,
340
+ attenuation: 1000,
341
+ volume: 100,
342
+ audioOnly: false,
343
+ position: { x: 0, y: 1, z: 0 },
344
+ rotation: { x: 0, y: 0, z: 0 },
345
+ offsetUpRotation: 0,
346
+ });
347
+ ```
348
+
349
+ **Returns:** `Promise<void>`
350
+
351
+ ---
352
+
353
+ #### `sdk.media.updateStream(spaceItemId, data)`
354
+
355
+ Update properties of an existing stream screen.
356
+
357
+ ```typescript
358
+ await sdk.media.updateStream("item-id", {
359
+ orgId: "org-id",
360
+ spaceId: "space-id",
361
+ spaceItemId: "item-id",
362
+ volume: 50,
363
+ aspectRatio: "16:9",
364
+ attenuation: 2000,
365
+ });
366
+ ```
367
+
368
+ | Field | Type | Required | Description |
369
+ | ------------- | ----------------- | -------- | --------------------------------------- |
370
+ | `orgId` | `string` | Yes | Organization ID. |
371
+ | `spaceId` | `string` | Yes | Space ID. |
372
+ | `spaceItemId` | `string` | Yes | Space item ID. |
373
+ | `audioOnly` | `boolean` | No | Play audio only. |
374
+ | `curvature` | `number` | No | Screen curvature (−100 to 100). |
375
+ | `aspectRatio` | `"4:3" \| "16:9"` | No | Screen aspect ratio. |
376
+ | `attenuation` | `number` | No | Audio attenuation distance (200–10000). |
377
+ | `volume` | `number` | No | Volume level (0–100). |
378
+
379
+ **Returns:** `Promise<void>`
380
+
381
+ ---
382
+
383
+ ### Sketchfab
384
+
385
+ #### `sdk.sketchfab.addObject(data)`
386
+
387
+ Add a 3D model to a space. Supports Sketchfab browse, file upload, and recent model reuse — all produce the same payload shape.
388
+
389
+ ```typescript
390
+ await sdk.sketchfab.addObject({
391
+ orgId: "org-id",
392
+ spaceId: "space-id",
393
+ spaceItemId: "item-id",
394
+ name: "My Model",
395
+ type: "RuntimeModel",
396
+ gltfUrl: "https://...",
397
+ materialOverrideId: "None",
398
+ scale: { x: 1, y: 1, z: 1 },
399
+ autoScale: true,
400
+ offsetUniformScale: 1,
401
+ collisionsEnabled: false,
402
+ position: { x: 0, y: 0, z: 0 },
403
+ rotation: { x: 0, y: 0, z: 0 },
404
+ offsetUpRotation: 0,
405
+ metadata: {
406
+ uid: "sketchfab-uid",
407
+ author: { username: "artist", profileUrl: "https://sketchfab.com/artist" },
408
+ },
409
+ });
410
+ ```
411
+
412
+ **Returns:** `Promise<void>`
413
+
414
+ ---
415
+
416
+ #### `sdk.sketchfab.updateObject(spaceItemId, data)`
417
+
418
+ Update collision and animation properties of an existing 3D model.
419
+
420
+ ```typescript
421
+ await sdk.sketchfab.updateObject("item-id", {
422
+ orgId: "org-id",
423
+ spaceId: "space-id",
424
+ spaceItemId: "item-id",
425
+ collisionsEnabled: true,
426
+ currentAnimation: "Walk",
427
+ });
428
+ ```
429
+
430
+ | Field | Type | Required | Description |
431
+ | ------------------- | --------- | -------- | ------------------------------ |
432
+ | `orgId` | `string` | Yes | Organization ID. |
433
+ | `spaceId` | `string` | Yes | Space ID. |
434
+ | `spaceItemId` | `string` | Yes | Space item ID. |
435
+ | `collisionsEnabled` | `boolean` | No | Enable or disable collisions. |
436
+ | `currentAnimation` | `string` | No | Name of the animation to play. |
437
+
438
+ **Returns:** `Promise<void>`
439
+
440
+ ---
441
+
442
+ ### Transform
443
+
444
+ #### `sdk.transform.updatePosition(spaceItemId, data)`
445
+
446
+ Update the world position of a space item.
447
+
448
+ ```typescript
449
+ await sdk.transform.updatePosition("item-id", {
450
+ orgId: "org-id",
451
+ spaceId: "space-id",
452
+ spaceItemId: "item-id",
453
+ position: { x: 3, y: 0, z: 0 },
454
+ });
455
+ ```
456
+
457
+ **Returns:** `Promise<void>`
458
+
459
+ ---
460
+
461
+ #### `sdk.transform.updateRotation(spaceItemId, data)`
462
+
463
+ Update the rotation of a space item.
464
+
465
+ ```typescript
466
+ await sdk.transform.updateRotation("item-id", {
467
+ orgId: "org-id",
468
+ spaceId: "space-id",
469
+ spaceItemId: "item-id",
470
+ rotation: { x: 0, y: 90, z: 0 },
471
+ offsetUpRotation: 45,
472
+ });
473
+ ```
474
+
475
+ | Field | Type | Required | Description |
476
+ | ------------------ | --------- | -------- | ------------------------------------------ |
477
+ | `orgId` | `string` | Yes | Organization ID. |
478
+ | `spaceId` | `string` | Yes | Space ID. |
479
+ | `spaceItemId` | `string` | Yes | Space item ID. |
480
+ | `rotation` | `Vector3` | Yes | Rotation in degrees per axis. |
481
+ | `offsetUpRotation` | `number` | No | Additional up-axis rotation (−180 to 180). |
482
+
483
+ **Returns:** `Promise<void>`
484
+
485
+ ---
486
+
487
+ #### `sdk.transform.updateScale(spaceItemId, data)`
488
+
489
+ Update the scale of a space item.
490
+
491
+ ```typescript
492
+ await sdk.transform.updateScale("item-id", {
493
+ orgId: "org-id",
494
+ spaceId: "space-id",
495
+ spaceItemId: "item-id",
496
+ scale: { x: 2, y: 2, z: 2 },
497
+ offsetUniformScale: 2,
498
+ });
499
+ ```
500
+
501
+ | Field | Type | Required | Description |
502
+ | -------------------- | --------- | -------- | ------------------------------------ |
503
+ | `orgId` | `string` | Yes | Organization ID. |
504
+ | `spaceId` | `string` | Yes | Space ID. |
505
+ | `spaceItemId` | `string` | Yes | Space item ID. |
506
+ | `scale` | `Vector3` | No | Per-axis scale values. |
507
+ | `offsetUniformScale` | `number` | Yes | Uniform scale multiplier (min 0.01). |
508
+
509
+ **Returns:** `Promise<void>`
510
+
511
+ ---
512
+
513
+ #### `sdk.transform.snapToGround(spaceItemId, data)`
514
+
515
+ Snap a space item to the ground. The UE bridge calculates the correct Z position.
516
+
517
+ ```typescript
518
+ await sdk.transform.snapToGround("item-id", {
519
+ orgId: "org-id",
520
+ spaceId: "space-id",
521
+ spaceItemId: "item-id",
522
+ });
523
+ ```
524
+
525
+ **Returns:** `Promise<void>`
526
+
527
+ ---
528
+
529
+ ### Layer
530
+
531
+ #### `sdk.layer.lockItem(spaceItemId, data)`
532
+
533
+ Lock or unlock a layer item.
534
+
535
+ ```typescript
536
+ // Lock
537
+ await sdk.layer.lockItem("item-id", {
538
+ orgId: "org-id",
539
+ spaceId: "space-id",
540
+ spaceItemId: "item-id",
541
+ isLocked: true,
542
+ });
543
+
544
+ // Unlock
545
+ await sdk.layer.lockItem("item-id", {
546
+ orgId: "org-id",
547
+ spaceId: "space-id",
548
+ spaceItemId: "item-id",
549
+ isLocked: false,
550
+ });
551
+ ```
552
+
553
+ **Returns:** `Promise<void>`
554
+
555
+ ---
556
+
557
+ #### `sdk.layer.renameItem(spaceItemId, data)`
558
+
559
+ Rename a layer item.
560
+
561
+ ```typescript
562
+ await sdk.layer.renameItem("item-id", {
563
+ orgId: "org-id",
564
+ spaceId: "space-id",
565
+ spaceItemId: "item-id",
566
+ name: "New Name",
567
+ });
568
+ ```
569
+
570
+ **Returns:** `Promise<void>`
571
+
572
+ ---
573
+
574
+ #### `sdk.layer.deleteItem(spaceItemId, data)`
575
+
576
+ Delete a single layer item from a space.
577
+
578
+ ```typescript
579
+ await sdk.layer.deleteItem("item-id", {
580
+ orgId: "org-id",
581
+ spaceId: "space-id",
582
+ spaceItemId: "item-id",
583
+ });
584
+ ```
585
+
586
+ **Returns:** `Promise<void>`
587
+
588
+ ---
589
+
590
+ #### `sdk.layer.deleteAll(data)`
591
+
592
+ Delete all layer items in a space. Locked items are skipped by the organization service.
593
+
594
+ ```typescript
595
+ await sdk.layer.deleteAll({
596
+ orgId: "org-id",
597
+ spaceId: "space-id",
598
+ });
599
+ ```
600
+
601
+ **Returns:** `Promise<void>`
602
+
603
+ ---
604
+
605
+ ### Configurator Items
606
+
607
+ #### `sdk.configuratorItems.create(data)`
608
+
609
+ Create a configurator item. Typically synced from Unreal Engine on session start via the WebRTC bridge.
610
+
611
+ ```typescript
612
+ await sdk.configuratorItems.create({
613
+ orgId: "org-id",
614
+ spaceId: "space-id",
615
+ spaceItemId: "item-id",
616
+ itemTemplateId: "template-id",
617
+ name: "Wall Color",
618
+ denormalizeOnUpdate: true,
619
+ currentState: "white",
620
+ schema: {
621
+ displayName: "Wall Color",
622
+ type: "enum",
623
+ default: "white",
624
+ values: ["white", "grey", "black"],
625
+ },
626
+ });
627
+ ```
628
+
629
+ **Returns:** `Promise<void>`
630
+
631
+ ---
632
+
633
+ #### `sdk.configuratorItems.updateState(spaceItemId, data)`
634
+
635
+ Update the current state of a level-wide configurator property.
636
+
637
+ ```typescript
638
+ await sdk.configuratorItems.updateState("item-id", {
639
+ orgId: "org-id",
640
+ spaceId: "space-id",
641
+ spaceItemId: "item-id",
642
+ currentState: "grey",
643
+ });
644
+ ```
645
+
646
+ **Returns:** `Promise<void>`
647
+
648
+ ---
649
+
650
+ ### Configurator Objects
651
+
652
+ #### `sdk.configuratorObjects.create(data)`
653
+
654
+ Place a UE actor in a space. Called when a user selects a card in the UE Object Importer grid.
655
+
656
+ ```typescript
657
+ await sdk.configuratorObjects.create({
658
+ orgId: "org-id",
659
+ spaceId: "space-id",
660
+ spaceItemId: "item-id",
661
+ name: "My Chair",
662
+ type: "ConfiguratorObject",
663
+ ueId: "ue-actor-id",
664
+ versionId: "version-id",
665
+ scale: { x: 1, y: 1, z: 1 },
666
+ offsetUniformScale: 1,
667
+ position: { x: 0, y: 0, z: 0 },
668
+ rotation: { x: 0, y: 0, z: 0 },
669
+ offsetUpRotation: 0,
670
+ configuration: {
671
+ color: {
672
+ displayName: "Color",
673
+ type: "enum",
674
+ currentState: "red",
675
+ default: "red",
676
+ values: ["red", "blue", "green"],
677
+ displayType: "dropdown",
678
+ },
679
+ },
680
+ });
681
+ ```
682
+
683
+ **Returns:** `Promise<void>`
684
+
685
+ ---
686
+
687
+ #### `sdk.configuratorObjects.updateConfiguration(spaceItemId, data)`
688
+
689
+ Update the full configuration map of a placed UE actor. Updates the entire map with new `currentState` per key.
690
+
691
+ ```typescript
692
+ await sdk.configuratorObjects.updateConfiguration("item-id", {
693
+ orgId: "org-id",
694
+ spaceId: "space-id",
695
+ spaceItemId: "item-id",
696
+ configuration: {
697
+ color: {
698
+ displayName: "Color",
699
+ type: "enum",
700
+ currentState: "blue",
701
+ default: "red",
702
+ values: ["red", "blue", "green"],
703
+ displayType: "dropdown",
704
+ },
705
+ },
706
+ });
707
+ ```
708
+
709
+ **Returns:** `Promise<void>`
710
+
711
+ ---
712
+
713
+ ## Types Reference
714
+
715
+ All types are exported directly from the package root:
716
+
717
+ ```typescript
718
+ import type { ... } from "@alliumcloud/configurator-service";
719
+ ```
720
+
721
+ ---
722
+
723
+ ### Config
724
+
725
+ ```typescript
726
+ type ConfiguratorServiceSDKConfig = {
727
+ apiKey: string;
728
+ jwksUri?: string;
729
+ accessTokenProvider: () => string | Promise<string>;
730
+ timeout?: number;
731
+ };
732
+ ```
733
+
734
+ ---
735
+
736
+ ### Common
737
+
738
+ ```typescript
739
+ type SpaceItemType =
740
+ | "RuntimeModel"
741
+ | "SpatialMedia"
742
+ | "LibraryModel"
743
+ | "RuntimeStream"
744
+ | "BridgeToolkitSettings"
745
+ | "Configurator"
746
+ | "ConfiguratorObject";
747
+
748
+ type ConfiguratorType =
749
+ | "string"
750
+ | "number"
751
+ | "boolean"
752
+ | "enum"
753
+ | "trigger"
754
+ | "image"
755
+ | "String"
756
+ | "Number"
757
+ | "Bool"
758
+ | "Enum"
759
+ | "Trigger"
760
+ | "Image";
761
+
762
+ type Vector3 = {
763
+ x: number;
764
+ y: number;
765
+ z: number;
766
+ };
767
+
768
+ type SpaceContext = {
769
+ orgId: string;
770
+ spaceId: string;
771
+ type: SpaceItemType;
772
+ name: string;
773
+ position: Vector3;
774
+ rotation: Vector3;
775
+ offsetUpRotation: number;
776
+ thumb?: string;
777
+ isLocked?: boolean;
778
+ user?: string;
779
+ };
780
+ ```
781
+
782
+ ---
783
+
784
+ ### Media Types
785
+
786
+ ```typescript
787
+ type SpatialMediaTypes = "video" | "link";
788
+
789
+ type CreateVideoInput = {
790
+ orgId: string;
791
+ spaceId: string;
792
+ spaceItemId: string;
793
+ name: string;
794
+ type: "SpatialMedia";
795
+ mediaType: "video";
796
+ url: string;
797
+ attenuation: number;
798
+ volume: number;
799
+ loop: boolean;
800
+ audioOnly: boolean;
801
+ showPreview: boolean;
802
+ autoplay?: boolean;
803
+ position: Vector3;
804
+ rotation: Vector3;
805
+ offsetUpRotation: number;
806
+ thumb?: string;
807
+ isLocked?: boolean;
808
+ user?: string;
809
+ };
810
+
811
+ type UpdateVideoInput = {
812
+ orgId: string;
813
+ spaceId: string;
814
+ spaceItemId: string;
815
+ url?: string;
816
+ volume?: number;
817
+ attenuation?: number;
818
+ loop?: boolean;
819
+ audioOnly?: boolean;
820
+ showPreview?: boolean;
821
+ };
822
+
823
+ type CreateLinkInput = {
824
+ orgId: string;
825
+ spaceId: string;
826
+ spaceItemId: string;
827
+ name: string;
828
+ type: "SpatialMedia";
829
+ mediaType: "link";
830
+ url: string;
831
+ attenuation: number;
832
+ isPortrait: boolean;
833
+ openInNewTab?: boolean;
834
+ displayName?: string;
835
+ position: Vector3;
836
+ rotation: Vector3;
837
+ offsetUpRotation: number;
838
+ thumb?: string;
839
+ isLocked?: boolean;
840
+ user?: string;
841
+ };
842
+
843
+ type UpdateLinkInput = {
844
+ orgId: string;
845
+ spaceId: string;
846
+ spaceItemId: string;
847
+ url?: string;
848
+ name?: string;
849
+ openInNewTab?: boolean;
850
+ isPortrait?: boolean;
851
+ };
852
+
853
+ type CreateStreamInput = {
854
+ orgId: string;
855
+ spaceId: string;
856
+ spaceItemId: string;
857
+ name: string;
858
+ type: "RuntimeStream";
859
+ spaceStreamId: string;
860
+ scale?: Vector3;
861
+ autoScale?: boolean;
862
+ offsetUniformScale?: number;
863
+ attenuation?: number;
864
+ volume?: number;
865
+ audioOnly?: boolean;
866
+ position: Vector3;
867
+ rotation: Vector3;
868
+ offsetUpRotation: number;
869
+ thumb?: string;
870
+ isLocked?: boolean;
871
+ user?: string;
872
+ };
873
+
874
+ type UpdateStreamInput = {
875
+ orgId: string;
876
+ spaceId: string;
877
+ spaceItemId: string;
878
+ audioOnly?: boolean;
879
+ curvature?: number;
880
+ aspectRatio?: "4:3" | "16:9";
881
+ attenuation?: number;
882
+ volume?: number;
883
+ };
884
+ ```
885
+
886
+ ---
887
+
888
+ ### Sketchfab Types
889
+
890
+ ```typescript
891
+ type ModelAuthor = {
892
+ username: string;
893
+ profileUrl: string;
894
+ };
895
+
896
+ type ModelGlbInfo = {
897
+ faceCount?: number;
898
+ textureCount?: number;
899
+ size?: number;
900
+ vertexCount?: number;
901
+ textureMaxResolution?: number;
902
+ };
903
+
904
+ type ModelMetadata = {
905
+ uid?: string;
906
+ viewerUrl?: string;
907
+ author?: ModelAuthor;
908
+ license?: string;
909
+ glb?: ModelGlbInfo;
910
+ };
911
+
912
+ type CreateSketchfabObjectInput = {
913
+ orgId: string;
914
+ spaceId: string;
915
+ spaceItemId: string;
916
+ name: string;
917
+ type: "RuntimeModel";
918
+ gltfUrl?: string;
919
+ materialOverrideId: string;
920
+ scale: Vector3;
921
+ autoScale: boolean;
922
+ offsetUniformScale: number;
923
+ collisionsEnabled: boolean;
924
+ currentAnimation?: string;
925
+ availableAnimations?: string[];
926
+ metadata?: ModelMetadata;
927
+ thumb?: string;
928
+ sketchfabTempUrl?: string;
929
+ position: Vector3;
930
+ rotation: Vector3;
931
+ offsetUpRotation: number;
932
+ isLocked?: boolean;
933
+ user?: string;
934
+ };
935
+
936
+ type UpdateSketchfabObjectInput = {
937
+ orgId: string;
938
+ spaceId: string;
939
+ spaceItemId: string;
940
+ collisionsEnabled?: boolean;
941
+ currentAnimation?: string;
942
+ };
943
+ ```
944
+
945
+ ---
946
+
947
+ ### Transform Types
948
+
949
+ ```typescript
950
+ type TransformItemContext = {
951
+ orgId: string;
952
+ spaceId: string;
953
+ spaceItemId: string;
954
+ };
955
+
956
+ type UpdatePositionInput = TransformItemContext & {
957
+ position: Vector3;
958
+ };
959
+
960
+ type UpdateRotationInput = TransformItemContext & {
961
+ rotation: Vector3;
962
+ offsetUpRotation?: number;
963
+ };
964
+
965
+ type UpdateScaleInput = TransformItemContext & {
966
+ scale?: Vector3;
967
+ offsetUniformScale: number;
968
+ };
969
+
970
+ type SnapToGroundInput = TransformItemContext;
971
+ ```
972
+
973
+ ---
974
+
975
+ ### Layer Types
976
+
977
+ ```typescript
978
+ type LockLayerItemInput = {
979
+ orgId: string;
980
+ spaceId: string;
981
+ spaceItemId: string;
982
+ isLocked: boolean;
983
+ };
984
+
985
+ type RenameLayerItemInput = {
986
+ orgId: string;
987
+ spaceId: string;
988
+ spaceItemId: string;
989
+ name: string;
990
+ };
991
+
992
+ type DeleteLayerItemInput = {
993
+ orgId: string;
994
+ spaceId: string;
995
+ spaceItemId: string;
996
+ };
997
+
998
+ type DeleteAllLayerItemsInput = {
999
+ orgId: string;
1000
+ spaceId: string;
1001
+ };
1002
+ ```
1003
+
1004
+ ---
1005
+
1006
+ ### Configurator Item Types
1007
+
1008
+ ```typescript
1009
+ type ConfiguratorItemSchema = {
1010
+ displayName: string;
1011
+ type: ConfiguratorType;
1012
+ default: string | number | boolean;
1013
+ values?: (string | number)[];
1014
+ max?: number;
1015
+ min?: number;
1016
+ step?: number;
1017
+ isPersisted?: boolean;
1018
+ isNetworked?: boolean;
1019
+ };
1020
+
1021
+ type CreateConfiguratorItemInput = {
1022
+ orgId: string;
1023
+ spaceId: string;
1024
+ spaceItemId: string;
1025
+ itemTemplateId: string;
1026
+ name: string;
1027
+ levelFilePath?: string;
1028
+ denormalizeOnUpdate: boolean;
1029
+ currentState?: string | number | boolean;
1030
+ schema: ConfiguratorItemSchema;
1031
+ };
1032
+
1033
+ type UpdateConfiguratorItemStateInput = {
1034
+ orgId: string;
1035
+ spaceId: string;
1036
+ spaceItemId: string;
1037
+ currentState: string | number | boolean;
1038
+ };
1039
+ ```
1040
+
1041
+ ---
1042
+
1043
+ ### Configurator Object Types
1044
+
1045
+ ```typescript
1046
+ type ObjectConfigurationValue = {
1047
+ displayName: string;
1048
+ type: ConfiguratorType;
1049
+ currentState: string | number | boolean;
1050
+ default: string | number | boolean;
1051
+ max?: number;
1052
+ min?: number;
1053
+ step?: number;
1054
+ values: (string | number)[];
1055
+ displayType?: "image" | "dropdown";
1056
+ valuesImages?: { displayName: string; thumb?: string }[];
1057
+ };
1058
+
1059
+ type EnumObjectConfigurationValue = {
1060
+ displayName: string;
1061
+ type: "enum";
1062
+ currentState: string | number;
1063
+ default: string | number;
1064
+ values: (string | number)[];
1065
+ displayType: "image" | "dropdown";
1066
+ max?: number;
1067
+ min?: number;
1068
+ step?: number;
1069
+ valuesImages?: { displayName: string; thumb?: string }[];
1070
+ };
1071
+
1072
+ type ConfigurationMap = {
1073
+ [key: string]: ObjectConfigurationValue | EnumObjectConfigurationValue;
1074
+ };
1075
+
1076
+ type CreateConfiguratorObjectInput = {
1077
+ orgId: string;
1078
+ spaceId: string;
1079
+ spaceItemId: string;
1080
+ name: string;
1081
+ type: "ConfiguratorObject";
1082
+ ueId: string;
1083
+ versionId: string;
1084
+ scale: Vector3;
1085
+ offsetUniformScale: number;
1086
+ configuration: ConfigurationMap;
1087
+ position: Vector3;
1088
+ rotation: Vector3;
1089
+ offsetUpRotation: number;
1090
+ thumb?: string;
1091
+ isLocked?: boolean;
1092
+ user?: string;
1093
+ };
1094
+
1095
+ type UpdateConfiguratorObjectConfigInput = {
1096
+ orgId: string;
1097
+ spaceId: string;
1098
+ spaceItemId: string;
1099
+ configuration: ConfigurationMap;
1100
+ };
1101
+ ```
1102
+
1103
+ ---
1104
+
1105
+ ### Error Types
1106
+
1107
+ ```typescript
1108
+ interface AlliumError extends Error {
1109
+ readonly code: string; // Machine-readable error code
1110
+ readonly name: string; // Human-readable error name
1111
+ readonly message: string; // Description of what went wrong
1112
+ }
1113
+
1114
+ // Type guard — use in catch blocks to narrow the error type
1115
+ function isAlliumError(err: unknown): err is AlliumError;
1116
+ ```
1117
+
1118
+ ---
1119
+
1120
+ ## Versioning
1121
+
1122
+ This SDK follows semantic versioning:
1123
+
1124
+ | Bump | When |
1125
+ | ----------------- | -------------------------------------------------------- |
1126
+ | `patch` — `x.x.1` | Bug fixes, no API changes. |
1127
+ | `minor` — `x.1.0` | New methods or fields added, fully backwards compatible. |
1128
+ | `major` — `2.0.0` | Breaking changes to existing method signatures or types. |
1129
+
1130
+ ---
1131
+
1132
+ ## License
1133
+
1134
+ Private — Allium Internal Use Only