@rtsdk/topia 0.19.4 → 0.19.6

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 CHANGED
@@ -240,44 +240,70 @@ export const getDroppedAssetAndVisitor = async (req: Request, res: Response) =>
240
240
  };
241
241
  ```
242
242
 
243
- <br/><br/>
244
-
245
243
  ## Data Objects
246
244
 
247
245
  Data Objects can be used to store information such as game state, configurations, themes, and analytics.
248
246
  There are three types of Data Objects:
249
247
 
250
- - **World:** The World data object should be used to store information unique to your app in a given world but not necessarily specific details about an instance or an active game. This information would persist even if the app was removed from the world.
251
- - **Example - Update two specific data points:**
252
- ```ts
253
- await world.updateDataObject({
254
- [`keyAssets.${keyAssetId}.itemsCollectedByUser.${profileId}`]: { [dateKey]: { count: 1 }, total: 1 },
255
- [`profileMapper.${profileId}`]: username,
256
- });
257
- ```
258
- - **Example - Increment a specific value within the data object by 1:**
259
- ```ts
260
- await world.incrementDataObjectValue([`keyAssets.${keyAssetId}.totalItemsCollected.count`], 1);
261
- ```
262
- - **Dropped Asset:** The Dropped Asset data object should only store what is unique to the specific instance of the app in the world such as game state. If the Dropped Asset is deleted, the data object would be lost as well so be sure to only store information here the doesn't need to persist!
263
- - **Example - Initialize data object with default data and keyAssetId:**
264
- ```ts
265
- await droppedAsset.setDataObject(
266
- {
267
- ...defaultGameData,
268
- keyAssetId: droppedAsset.id,
269
- },
270
- { lock: { lockId, releaseLock: true } },
271
- );
272
- ```
273
- - **Example - Update lastInteraction date and playerCount:**
274
- ```ts
275
- await droppedAsset.updateDataObject({ lastInteraction: new Date(), playerCount: playerCount + 1 });
276
- ```
277
- - **User:** The User data object should be used to store information unique to a user that is NOT unique to a world or instance (dropped asset) of an app.
278
- - **Example - Update totalMessagesSentCount by a user across all worlds:**
279
- `` js await world.incrementDataObjectValue([`totalMessagesSentCount`], 1); ``
280
- <br/>
248
+ ### World:
249
+
250
+ The data object attached to the world will store information for every instance of the app in a given world by keyAssetId or sceneDropId and will persist even if a specific instance is removed from world. Data stored in the World data object should be minimal to avoid running into limits.
251
+
252
+ #### Example - Update two specific data points:
253
+
254
+ ```ts
255
+ await world.updateDataObject({
256
+ [sceneDropId]: { keyAssetId: droppedAsset.id, themeId: "custom", totalInteractions: 1 },
257
+ });
258
+ ```
259
+
260
+ #### Example - Increment a specific value within the data object by 1:
261
+
262
+ ```ts
263
+ await world.incrementDataObjectValue([`${sceneDropId}.totalInteractions`], 1);
264
+ ```
265
+
266
+ ### Dropped Asset:
267
+
268
+ The Dropped Asset data object should only store what is unique to the specific instance of the app in the world such as game state. If the Dropped Asset is deleted, the data object would be lost as well so be sure to only store information here the doesn't need to persist!
269
+
270
+ #### Example - Initialize data object with default data and keyAssetId:
271
+
272
+ ```ts
273
+ await droppedAsset.setDataObject(
274
+ {
275
+ ...defaultGameData,
276
+ keyAssetId: droppedAsset.id,
277
+ },
278
+ { lock: { lockId, releaseLock: true } },
279
+ );
280
+ ```
281
+
282
+ #### Example - Update lastInteraction date and playerCount:
283
+
284
+ ```ts
285
+ await droppedAsset.updateDataObject({ lastInteraction: new Date(), playerCount: playerCount + 1 });
286
+ ```
287
+
288
+ ### User:
289
+
290
+ The data object attached to the visitor should store information related specifically to the visitor i.e. progress. For tracking across multiple world/instances use `${urlSlug}_${sceneDropId}` as a unique key.
291
+
292
+ #### Example - Initialize data object with default data and keyAssetId:
293
+
294
+ ```ts
295
+ await visitor.setDataObject(
296
+ {
297
+ [`${urlSlug}_${sceneDropId}`]: {
298
+ currentStreak: 0,
299
+ lastCollectedDate: null,
300
+ longestStreak: 0,
301
+ totalCollected: 0,
302
+ },
303
+ },
304
+ { lock: { lockId, releaseLock: true } },
305
+ );
306
+ ```
281
307
 
282
308
  ### Data Object Locking
283
309
 
@@ -324,7 +350,7 @@ await world.setDataObject({ hello: "world" }, { analytics: [{ analyticName: "res
324
350
 
325
351
  await world.updateDataObject({}, { analytics: [ {analyticName: "matches", uniqueKey: `${playerOneProfileId}-${playerTwoProfileId}`, urlSlug }], });
326
352
 
327
- await world.incrementDataObjectValue(`keyAssets.${assetId}.completions`, 1, { analytics: [{ analyticName:"completions", incrementBy: 2, profileId, uniqueKey: profileId, urlSlug }] });
353
+ await world.incrementDataObjectValue(`${sceneDropId}.completions`, 1, { analytics: [{ analyticName:"completions", incrementBy: 2, profileId, uniqueKey: profileId, urlSlug }] });
328
354
  ```
329
355
 
330
356
  Examples leveraging Visitor data objects calls:
@@ -345,7 +371,7 @@ await visitor.incrementDataObjectValue(`completions`, 1, {
345
371
  });
346
372
  ```
347
373
 
348
- Note: passing an empty object does NOT impact the data objects themselves but rather allows you to track custom analytics (incremented by 1) across all instances of your application with a given Public Key.
374
+ Note: passing an empty object does NOT impact the data objects themselves but rather allows you to track custom analytics across all instances of your application with a given Public Key.
349
375
 
350
376
  <br>
351
377
 
@@ -353,26 +379,18 @@ Note: passing an empty object does NOT impact the data objects themselves but ra
353
379
 
354
380
  <hr/>
355
381
 
356
- <br>
357
-
358
382
  ## Get Started
359
383
 
360
384
  Run `gh repo clone metaversecloud-com/mc-sdk-js`
361
385
 
362
- <br>
363
-
364
386
  ## Issues
365
387
 
366
388
  We've added an Issue template to help standardize Issues and ensure they have enough detail for a developer to start work and help prevent contributors from forgetting to add an important piece of information.
367
389
 
368
- <br>
369
-
370
390
  ## Pull Requests
371
391
 
372
392
  We've added a Pull Request template to help make it easier for developers to clarify what the proposed changes will do. This helps facilitate clear communication between all contributors of the SDK and ensures that we are all on the same page!
373
393
 
374
- <br>
375
-
376
394
  ## Documentation
377
395
 
378
396
  ### Styles
package/dist/index.cjs CHANGED
@@ -39727,11 +39727,6 @@ class SDKController {
39727
39727
  *
39728
39728
  * @keywords error, exception, handler, debugging, api error, http error
39729
39729
  *
39730
- * @param error - The error object from the failed operation (AxiosError, Error, or unknown)
39731
- * @param message - Optional custom error message (defaults to generic message)
39732
- * @param params - Optional parameters that were passed to the failed method
39733
- * @param sdkMethod - Optional name of the SDK method that failed (e.g., "World.fetchDetails")
39734
- *
39735
39730
  * @returns {object} Standardized error object with properties: data, message, method, params, sdkMethod, stack, status, success, url
39736
39731
  */
39737
39732
  errorHandler({ error, message = "Something went wrong. Please try again or contact support.", params = {}, sdkMethod, }) {
@@ -43670,7 +43665,13 @@ class Visitor extends User {
43670
43665
  createNpc(userInventoryItemId, options) {
43671
43666
  return __awaiter(this, void 0, void 0, function* () {
43672
43667
  try {
43673
- const response = yield this.topiaPublicApi().post(`/world/${this.urlSlug}/visitors/${this.id}/create-npc`, { userInventoryItemId, showNameplate: options === null || options === void 0 ? void 0 : options.showNameplate }, this.requestOptions);
43668
+ const response = yield this.topiaPublicApi().post(`/world/${this.urlSlug}/visitors/${this.id}/create-npc`, {
43669
+ userInventoryItemId,
43670
+ showNameplate: options === null || options === void 0 ? void 0 : options.showNameplate,
43671
+ stationary: options === null || options === void 0 ? void 0 : options.stationary,
43672
+ replace: options === null || options === void 0 ? void 0 : options.replace,
43673
+ spawnEffect: options === null || options === void 0 ? void 0 : options.spawnEffect,
43674
+ }, this.requestOptions);
43674
43675
  return new Visitor(this.topia, response.data.player.playerId, this.urlSlug, {
43675
43676
  attributes: response.data,
43676
43677
  credentials: this.credentials,
@@ -43715,6 +43716,77 @@ class Visitor extends User {
43715
43716
  }
43716
43717
  });
43717
43718
  }
43719
+ /**
43720
+ * Start an AI voice session for this visitor's NPC.
43721
+ *
43722
+ * @remarks
43723
+ * Establishes a real-time voice connection between the visitor and an AI backend
43724
+ * (currently OpenAI Realtime API) through the NPC. The NPC must already be spawned
43725
+ * via `createNpc()` before calling this method.
43726
+ *
43727
+ * The voice session occupies a video slot in the visitor's peer video grid, showing
43728
+ * the NPC's avatar image. Audio streams bidirectionally between the visitor's microphone
43729
+ * and the AI model. Only the NPC's owner hears the AI audio.
43730
+ *
43731
+ * Topia automatically prepends non-removable child safety guardrails to the instructions.
43732
+ * Only one voice session is allowed per visitor per world at a time.
43733
+ *
43734
+ * @keywords voice, npc, ai, chat, audio, realtime, session, start, speech
43735
+ *
43736
+ * @category NPCs
43737
+ *
43738
+ * @param config - Voice session configuration including ephemeral key and AI instructions
43739
+ *
43740
+ * @example
43741
+ * ```ts
43742
+ * const ephemeralKey = await generateOpenAIEphemeralKey();
43743
+ *
43744
+ * await visitor.startNpcVoiceSession({
43745
+ * ephemeralKey,
43746
+ * voice: "alloy",
43747
+ * instructions: "You are a friendly science tutor helping with photosynthesis.",
43748
+ * model: "gpt-4o-realtime-preview",
43749
+ * });
43750
+ * ```
43751
+ *
43752
+ * @returns {Promise<void | ResponseType>} Returns `{ success: true }` or an error.
43753
+ */
43754
+ startNpcVoiceSession(config) {
43755
+ return __awaiter(this, void 0, void 0, function* () {
43756
+ try {
43757
+ const response = yield this.topiaPublicApi().put(`/world/${this.urlSlug}/visitors/${this.id}/start-npc-voice-session`, { voiceConfig: config }, this.requestOptions);
43758
+ return response.data;
43759
+ }
43760
+ catch (error) {
43761
+ throw this.errorHandler({ error, params: config, sdkMethod: "Visitor.startNpcVoiceSession" });
43762
+ }
43763
+ });
43764
+ }
43765
+ /**
43766
+ * Stop the active AI voice session for this visitor's NPC.
43767
+ *
43768
+ * @keywords voice, npc, ai, chat, audio, realtime, session, stop, end
43769
+ *
43770
+ * @category NPCs
43771
+ *
43772
+ * @example
43773
+ * ```ts
43774
+ * await visitor.stopNpcVoiceSession();
43775
+ * ```
43776
+ *
43777
+ * @returns {Promise<void | ResponseType>} Returns `{ success: true }` or an error.
43778
+ */
43779
+ stopNpcVoiceSession() {
43780
+ return __awaiter(this, void 0, void 0, function* () {
43781
+ try {
43782
+ const response = yield this.topiaPublicApi().put(`/world/${this.urlSlug}/visitors/${this.id}/stop-npc-voice-session`, {}, this.requestOptions);
43783
+ return response.data;
43784
+ }
43785
+ catch (error) {
43786
+ throw this.errorHandler({ error, sdkMethod: "Visitor.stopNpcVoiceSession" });
43787
+ }
43788
+ });
43789
+ }
43718
43790
  /**
43719
43791
  * Retrieves all inventory items owned by this visitor and app's key.
43720
43792
  *
package/dist/index.d.ts CHANGED
@@ -74,7 +74,7 @@ type DroppedAssetLinkType = {
74
74
  linkSamlQueryParams?: string;
75
75
  };
76
76
 
77
- type InteractiveCredentials = {
77
+ type InteractiveCredentials$1 = {
78
78
  apiKey?: string;
79
79
  assetId?: string;
80
80
  interactiveNonce?: string;
@@ -88,22 +88,22 @@ type InteractiveCredentials = {
88
88
 
89
89
  type AssetOptions = {
90
90
  attributes?: AssetInterface | undefined;
91
- credentials?: InteractiveCredentials | undefined;
91
+ credentials?: InteractiveCredentials$1 | undefined;
92
92
  };
93
93
  type DroppedAssetOptions = {
94
94
  attributes?: DroppedAssetInterface | undefined;
95
- credentials?: InteractiveCredentials | undefined;
95
+ credentials?: InteractiveCredentials$1 | undefined;
96
96
  };
97
97
  type UserOptions = {
98
- credentials?: InteractiveCredentials | undefined;
98
+ credentials?: InteractiveCredentials$1 | undefined;
99
99
  };
100
100
  type VisitorOptions = {
101
101
  attributes?: VisitorInterface | undefined;
102
- credentials?: InteractiveCredentials | undefined;
102
+ credentials?: InteractiveCredentials$1 | undefined;
103
103
  };
104
104
  type WorldOptions = {
105
105
  attributes?: WorldDetailsInterface | undefined;
106
- credentials?: InteractiveCredentials | undefined;
106
+ credentials?: InteractiveCredentials$1 | undefined;
107
107
  };
108
108
 
109
109
  type ResponseType = {
@@ -2160,9 +2160,7 @@ declare class Visitor extends User implements VisitorInterface {
2160
2160
  *
2161
2161
  * @returns {Promise<Visitor>} Returns a Visitor object representing the created NPC. The NPC will automatically follow the visitor.
2162
2162
  */
2163
- createNpc(userInventoryItemId: string, options?: {
2164
- showNameplate?: boolean;
2165
- }): Promise<Visitor>;
2163
+ createNpc(userInventoryItemId: string, options?: CreateNpcOptions): Promise<Visitor>;
2166
2164
  /**
2167
2165
  * Deletes the NPC (Non-Player Character) this app has assigned to this visitor.
2168
2166
  *
@@ -2188,6 +2186,57 @@ declare class Visitor extends User implements VisitorInterface {
2188
2186
  * @returns {Promise<void>} Returns nothing if successful.
2189
2187
  */
2190
2188
  deleteNpc(): Promise<void>;
2189
+ /**
2190
+ * Start an AI voice session for this visitor's NPC.
2191
+ *
2192
+ * @remarks
2193
+ * Establishes a real-time voice connection between the visitor and an AI backend
2194
+ * (currently OpenAI Realtime API) through the NPC. The NPC must already be spawned
2195
+ * via `createNpc()` before calling this method.
2196
+ *
2197
+ * The voice session occupies a video slot in the visitor's peer video grid, showing
2198
+ * the NPC's avatar image. Audio streams bidirectionally between the visitor's microphone
2199
+ * and the AI model. Only the NPC's owner hears the AI audio.
2200
+ *
2201
+ * Topia automatically prepends non-removable child safety guardrails to the instructions.
2202
+ * Only one voice session is allowed per visitor per world at a time.
2203
+ *
2204
+ * @keywords voice, npc, ai, chat, audio, realtime, session, start, speech
2205
+ *
2206
+ * @category NPCs
2207
+ *
2208
+ * @param config - Voice session configuration including ephemeral key and AI instructions
2209
+ *
2210
+ * @example
2211
+ * ```ts
2212
+ * const ephemeralKey = await generateOpenAIEphemeralKey();
2213
+ *
2214
+ * await visitor.startNpcVoiceSession({
2215
+ * ephemeralKey,
2216
+ * voice: "alloy",
2217
+ * instructions: "You are a friendly science tutor helping with photosynthesis.",
2218
+ * model: "gpt-4o-realtime-preview",
2219
+ * });
2220
+ * ```
2221
+ *
2222
+ * @returns {Promise<void | ResponseType>} Returns `{ success: true }` or an error.
2223
+ */
2224
+ startNpcVoiceSession(config: NpcVoiceConfigInterface): Promise<void | ResponseType>;
2225
+ /**
2226
+ * Stop the active AI voice session for this visitor's NPC.
2227
+ *
2228
+ * @keywords voice, npc, ai, chat, audio, realtime, session, stop, end
2229
+ *
2230
+ * @category NPCs
2231
+ *
2232
+ * @example
2233
+ * ```ts
2234
+ * await visitor.stopNpcVoiceSession();
2235
+ * ```
2236
+ *
2237
+ * @returns {Promise<void | ResponseType>} Returns `{ success: true }` or an error.
2238
+ */
2239
+ stopNpcVoiceSession(): Promise<void | ResponseType>;
2191
2240
  /**
2192
2241
  * Retrieves all inventory items owned by this visitor and app's key.
2193
2242
  *
@@ -2294,7 +2343,7 @@ declare enum WorldActivityType {
2294
2343
  }
2295
2344
 
2296
2345
  interface SDKInterface {
2297
- credentials?: InteractiveCredentials;
2346
+ credentials?: InteractiveCredentials$1;
2298
2347
  jwt?: string;
2299
2348
  requestOptions: object;
2300
2349
  topia: Topia;
@@ -2331,7 +2380,7 @@ interface AssetInterface extends SDKInterface {
2331
2380
  }
2332
2381
  type AssetOptionalInterface = {
2333
2382
  attributes?: AssetInterface | object;
2334
- credentials?: InteractiveCredentials;
2383
+ credentials?: InteractiveCredentials$1;
2335
2384
  };
2336
2385
 
2337
2386
  interface DroppedAssetInterface extends AssetInterface {
@@ -2453,7 +2502,7 @@ interface DroppedAssetOptionalInterface {
2453
2502
  text?: string;
2454
2503
  urlSlug?: string;
2455
2504
  };
2456
- credentials?: InteractiveCredentials | object;
2505
+ credentials?: InteractiveCredentials$1 | object;
2457
2506
  }
2458
2507
  interface UpdateBroadcastInterface {
2459
2508
  assetBroadcast?: boolean;
@@ -2545,7 +2594,7 @@ interface EcosystemInterface extends SDKInterface {
2545
2594
  incrementDataObjectValue(path: string, amount: number, options: object): Promise<void | ResponseType>;
2546
2595
  }
2547
2596
  interface EcosystemOptionalInterface {
2548
- credentials?: InteractiveCredentials;
2597
+ credentials?: InteractiveCredentials$1;
2549
2598
  }
2550
2599
 
2551
2600
  interface SceneInterface {
@@ -2573,7 +2622,7 @@ interface SceneInterface {
2573
2622
  }
2574
2623
  type SceneOptionalInterface = {
2575
2624
  attributes?: SceneInterface | object;
2576
- credentials?: InteractiveCredentials;
2625
+ credentials?: InteractiveCredentials$1;
2577
2626
  };
2578
2627
 
2579
2628
  interface FireToastInterface {
@@ -2621,7 +2670,7 @@ interface UserInterface {
2621
2670
  dataObject?: object | null;
2622
2671
  }
2623
2672
  interface UserOptionalInterface {
2624
- credentials?: InteractiveCredentials;
2673
+ credentials?: InteractiveCredentials$1;
2625
2674
  profileId?: string | null;
2626
2675
  visitorId?: number | null;
2627
2676
  urlSlug?: string;
@@ -2649,11 +2698,11 @@ interface VisitorInterface extends SDKInterface {
2649
2698
  grantInventoryItem(item: InventoryItemInterface, quantity: number): Promise<UserInventoryItem>;
2650
2699
  modifyInventoryItemQuantity(item: UserInventoryItemInterface | InventoryItemInterface, quantity: number): Promise<UserInventoryItem>;
2651
2700
  fetchInventoryItem(item: InventoryItemInterface): Promise<UserInventoryItem>;
2652
- createNpc(userInventoryItemId: string, options?: {
2653
- showNameplate?: boolean;
2654
- }): Promise<Visitor>;
2701
+ createNpc(userInventoryItemId: string, options?: CreateNpcOptions): Promise<Visitor>;
2655
2702
  deleteNpc(): Promise<void>;
2656
2703
  getNpc(): Promise<Visitor | null>;
2704
+ startNpcVoiceSession(config: NpcVoiceConfigInterface): Promise<void | ResponseType>;
2705
+ stopNpcVoiceSession(): Promise<void | ResponseType>;
2657
2706
  triggerParticle({ id, name, duration, }: {
2658
2707
  id?: string;
2659
2708
  name?: string;
@@ -2697,7 +2746,7 @@ interface VisitorInterface extends SDKInterface {
2697
2746
  }
2698
2747
  interface VisitorOptionalInterface {
2699
2748
  attributes?: VisitorInterface | object;
2700
- credentials?: InteractiveCredentials;
2749
+ credentials?: InteractiveCredentials$1;
2701
2750
  }
2702
2751
  interface MoveVisitorInterface {
2703
2752
  shouldTeleportVisitor: boolean;
@@ -2710,6 +2759,39 @@ interface OpenIframeInterface {
2710
2759
  shouldOpenInDrawer?: boolean;
2711
2760
  title?: string;
2712
2761
  }
2762
+ interface SpawnEffectConfig {
2763
+ type?: "portal" | "none";
2764
+ colors?: number[];
2765
+ glowColor?: number;
2766
+ glowOpacity?: number;
2767
+ centerColor?: number;
2768
+ duration?: number;
2769
+ sectorCount?: number;
2770
+ gridSize?: number;
2771
+ }
2772
+ interface CreateNpcOptions {
2773
+ showNameplate?: boolean;
2774
+ stationary?: boolean;
2775
+ replace?: boolean;
2776
+ spawnEffect?: SpawnEffectConfig;
2777
+ }
2778
+ interface NpcVoiceConfigInterface {
2779
+ /** OpenAI ephemeral key (ek_*). Generated server-side, used once to establish WebRTC connection. */
2780
+ ephemeralKey: string;
2781
+ /** OpenAI voice ID (e.g., "alloy", "echo", "shimmer"). */
2782
+ voice: string;
2783
+ /** System prompt including curriculum context and behavioral instructions. */
2784
+ instructions: string;
2785
+ /** OpenAI model ID. Defaults to "gpt-4o-realtime-preview". */
2786
+ model?: string;
2787
+ /** Voice activity detection configuration. */
2788
+ turnDetection?: {
2789
+ type: "server_vad";
2790
+ threshold?: number;
2791
+ prefix_padding_ms?: number;
2792
+ silence_duration_ms?: number;
2793
+ };
2794
+ }
2713
2795
 
2714
2796
  interface WebhookInterface {
2715
2797
  webhookId?: string;
@@ -2730,12 +2812,12 @@ interface WebRTCConnectorInterface {
2730
2812
  getTwilioConfig(): Promise<void | ResponseType>;
2731
2813
  }
2732
2814
  interface WebRTCConnectorOptionalInterface {
2733
- credentials?: InteractiveCredentials;
2815
+ credentials?: InteractiveCredentials$1;
2734
2816
  twilioConfig?: object;
2735
2817
  }
2736
2818
 
2737
2819
  interface WorldActivityOptionalInterface {
2738
- credentials?: InteractiveCredentials;
2820
+ credentials?: InteractiveCredentials$1;
2739
2821
  }
2740
2822
  interface MoveAllVisitorsInterface {
2741
2823
  shouldFetchVisitors?: boolean;
@@ -2825,13 +2907,13 @@ interface WorldInterface extends SDKInterface, WorldDetailsInterface {
2825
2907
  }
2826
2908
  interface WorldOptionalInterface {
2827
2909
  attributes?: WorldDetailsInterface | object;
2828
- credentials?: InteractiveCredentials;
2910
+ credentials?: InteractiveCredentials$1;
2829
2911
  }
2830
2912
  interface WorldWebhooksInterface {
2831
2913
  webhooks: Array<WebhookInterface>;
2832
2914
  }
2833
2915
 
2834
- type InteractiveCredentials$1 = {
2916
+ type InteractiveCredentials = {
2835
2917
  apiKey?: string;
2836
2918
  assetId?: string;
2837
2919
  interactiveNonce?: string;
@@ -2862,7 +2944,7 @@ interface InventoryItemInterface extends SDKInterface {
2862
2944
  }
2863
2945
  type InventoryItemOptionalInterface = {
2864
2946
  attributes?: InventoryItemInterface | object;
2865
- credentials?: InteractiveCredentials$1;
2947
+ credentials?: InteractiveCredentials;
2866
2948
  };
2867
2949
 
2868
2950
  /**
@@ -2880,7 +2962,7 @@ interface UserInventoryItemInterface extends InventoryItemInterface {
2880
2962
  }
2881
2963
  type UserInventoryItemOptionalInterface = {
2882
2964
  attributes?: UserInventoryItemInterface | object;
2883
- credentials?: InteractiveCredentials$1;
2965
+ credentials?: InteractiveCredentials;
2884
2966
  };
2885
2967
  type UserInventoryItemMetadataType = {
2886
2968
  id: string;
@@ -2959,11 +3041,11 @@ declare class Topia implements TopiaInterface {
2959
3041
  * ```
2960
3042
  */
2961
3043
  declare abstract class SDKController implements SDKInterface {
2962
- credentials: InteractiveCredentials | undefined;
3044
+ credentials: InteractiveCredentials$1 | undefined;
2963
3045
  jwt?: string;
2964
3046
  requestOptions: object;
2965
3047
  topia: Topia;
2966
- constructor(topia: Topia, credentials?: InteractiveCredentials);
3048
+ constructor(topia: Topia, credentials?: InteractiveCredentials$1);
2967
3049
  /**
2968
3050
  * Returns the configured Axios instance for making API calls to Topia's Public API.
2969
3051
  *
@@ -2991,11 +3073,6 @@ declare abstract class SDKController implements SDKInterface {
2991
3073
  *
2992
3074
  * @keywords error, exception, handler, debugging, api error, http error
2993
3075
  *
2994
- * @param error - The error object from the failed operation (AxiosError, Error, or unknown)
2995
- * @param message - Optional custom error message (defaults to generic message)
2996
- * @param params - Optional parameters that were passed to the failed method
2997
- * @param sdkMethod - Optional name of the SDK method that failed (e.g., "World.fetchDetails")
2998
- *
2999
3076
  * @returns {object} Standardized error object with properties: data, message, method, params, sdkMethod, stack, status, success, url
3000
3077
  */
3001
3078
  errorHandler({ error, message, params, sdkMethod, }: {
@@ -3608,7 +3685,7 @@ declare class DroppedAssetFactory extends SDKController {
3608
3685
  *
3609
3686
  * @returns {Promise<DroppedAsset>} Returns a new DroppedAsset object with all properties already fetched.
3610
3687
  */
3611
- getWithUniqueName(uniqueName: string, urlSlug: string, interactiveSecret: string, credentials: InteractiveCredentials): Promise<DroppedAsset>;
3688
+ getWithUniqueName(uniqueName: string, urlSlug: string, interactiveSecret: string, credentials: InteractiveCredentials$1): Promise<DroppedAsset>;
3612
3689
  /**
3613
3690
  * Drops an asset in a world and returns a new instance of DroppedAsset class with all properties.
3614
3691
  *
@@ -4190,4 +4267,4 @@ declare class WorldFactory extends SDKController {
4190
4267
  }>;
4191
4268
  }
4192
4269
 
4193
- export { AnalyticType, AnimationMetaType, Asset, AssetFactory, AssetInterface, AssetOptionalInterface, AssetOptions, AssetType, DroppedAsset, DroppedAssetClickType, DroppedAssetFactory, DroppedAssetInterface, DroppedAssetLinkType, DroppedAssetMediaType, DroppedAssetMediaVolumeRadius, DroppedAssetOptionalInterface, DroppedAssetOptions, Ecosystem, EcosystemFactory, EcosystemInterface, EcosystemOptionalInterface, FireToastInterface, FrameType, InteractiveCredentials, InventoryItemInterface, InventoryItemOptionalInterface, MoveAllVisitorsInterface, MoveVisitorInterface, OpenIframeInterface, RemoveClickableLinkInterface, ResponseType, SDKController, SDKInterface, Scene, SceneFactory, SceneInterface, SceneOptionalInterface, SetClickableLinkMultiInterface, Topia, TopiaInterface, UpdateBroadcastInterface, UpdateClickTypeInterface, UpdateClickableLinkMultiInterface, UpdateDroppedAssetInterface, UpdateMediaTypeInterface, UpdatePrivateZoneInterface, User, UserFactory, UserInterface, UserInventoryItemInterface, UserInventoryItemMetadataType, UserInventoryItemOptionalInterface, UserOptionalInterface, UserOptions, Visitor, VisitorFactory, VisitorInterface, VisitorOptionalInterface, VisitorOptions, VisitorType, VisitorsToMoveArrayType, VisitorsToMoveType, WebRTCConnector, WebRTCConnectorFactory, WebRTCConnectorInterface, WebRTCConnectorOptionalInterface, WebhookInterface, World, WorldActivity, WorldActivityFactory, WorldActivityOptionalInterface, WorldActivityType, WorldDetailsInterface, WorldFactory, WorldInterface, WorldOptionalInterface, WorldOptions, WorldWebhooksInterface };
4270
+ export { AnalyticType, AnimationMetaType, Asset, AssetFactory, AssetInterface, AssetOptionalInterface, AssetOptions, AssetType, CreateNpcOptions, DroppedAsset, DroppedAssetClickType, DroppedAssetFactory, DroppedAssetInterface, DroppedAssetLinkType, DroppedAssetMediaType, DroppedAssetMediaVolumeRadius, DroppedAssetOptionalInterface, DroppedAssetOptions, Ecosystem, EcosystemFactory, EcosystemInterface, EcosystemOptionalInterface, FireToastInterface, FrameType, InteractiveCredentials$1 as InteractiveCredentials, InventoryItemInterface, InventoryItemOptionalInterface, MoveAllVisitorsInterface, MoveVisitorInterface, NpcVoiceConfigInterface, OpenIframeInterface, RemoveClickableLinkInterface, ResponseType, SDKController, SDKInterface, Scene, SceneFactory, SceneInterface, SceneOptionalInterface, SetClickableLinkMultiInterface, SpawnEffectConfig, Topia, TopiaInterface, UpdateBroadcastInterface, UpdateClickTypeInterface, UpdateClickableLinkMultiInterface, UpdateDroppedAssetInterface, UpdateMediaTypeInterface, UpdatePrivateZoneInterface, User, UserFactory, UserInterface, UserInventoryItemInterface, UserInventoryItemMetadataType, UserInventoryItemOptionalInterface, UserOptionalInterface, UserOptions, Visitor, VisitorFactory, VisitorInterface, VisitorOptionalInterface, VisitorOptions, VisitorType, VisitorsToMoveArrayType, VisitorsToMoveType, WebRTCConnector, WebRTCConnectorFactory, WebRTCConnectorInterface, WebRTCConnectorOptionalInterface, WebhookInterface, World, WorldActivity, WorldActivityFactory, WorldActivityOptionalInterface, WorldActivityType, WorldDetailsInterface, WorldFactory, WorldInterface, WorldOptionalInterface, WorldOptions, WorldWebhooksInterface };
package/dist/index.js CHANGED
@@ -39725,11 +39725,6 @@ class SDKController {
39725
39725
  *
39726
39726
  * @keywords error, exception, handler, debugging, api error, http error
39727
39727
  *
39728
- * @param error - The error object from the failed operation (AxiosError, Error, or unknown)
39729
- * @param message - Optional custom error message (defaults to generic message)
39730
- * @param params - Optional parameters that were passed to the failed method
39731
- * @param sdkMethod - Optional name of the SDK method that failed (e.g., "World.fetchDetails")
39732
- *
39733
39728
  * @returns {object} Standardized error object with properties: data, message, method, params, sdkMethod, stack, status, success, url
39734
39729
  */
39735
39730
  errorHandler({ error, message = "Something went wrong. Please try again or contact support.", params = {}, sdkMethod, }) {
@@ -43668,7 +43663,13 @@ class Visitor extends User {
43668
43663
  createNpc(userInventoryItemId, options) {
43669
43664
  return __awaiter(this, void 0, void 0, function* () {
43670
43665
  try {
43671
- const response = yield this.topiaPublicApi().post(`/world/${this.urlSlug}/visitors/${this.id}/create-npc`, { userInventoryItemId, showNameplate: options === null || options === void 0 ? void 0 : options.showNameplate }, this.requestOptions);
43666
+ const response = yield this.topiaPublicApi().post(`/world/${this.urlSlug}/visitors/${this.id}/create-npc`, {
43667
+ userInventoryItemId,
43668
+ showNameplate: options === null || options === void 0 ? void 0 : options.showNameplate,
43669
+ stationary: options === null || options === void 0 ? void 0 : options.stationary,
43670
+ replace: options === null || options === void 0 ? void 0 : options.replace,
43671
+ spawnEffect: options === null || options === void 0 ? void 0 : options.spawnEffect,
43672
+ }, this.requestOptions);
43672
43673
  return new Visitor(this.topia, response.data.player.playerId, this.urlSlug, {
43673
43674
  attributes: response.data,
43674
43675
  credentials: this.credentials,
@@ -43713,6 +43714,77 @@ class Visitor extends User {
43713
43714
  }
43714
43715
  });
43715
43716
  }
43717
+ /**
43718
+ * Start an AI voice session for this visitor's NPC.
43719
+ *
43720
+ * @remarks
43721
+ * Establishes a real-time voice connection between the visitor and an AI backend
43722
+ * (currently OpenAI Realtime API) through the NPC. The NPC must already be spawned
43723
+ * via `createNpc()` before calling this method.
43724
+ *
43725
+ * The voice session occupies a video slot in the visitor's peer video grid, showing
43726
+ * the NPC's avatar image. Audio streams bidirectionally between the visitor's microphone
43727
+ * and the AI model. Only the NPC's owner hears the AI audio.
43728
+ *
43729
+ * Topia automatically prepends non-removable child safety guardrails to the instructions.
43730
+ * Only one voice session is allowed per visitor per world at a time.
43731
+ *
43732
+ * @keywords voice, npc, ai, chat, audio, realtime, session, start, speech
43733
+ *
43734
+ * @category NPCs
43735
+ *
43736
+ * @param config - Voice session configuration including ephemeral key and AI instructions
43737
+ *
43738
+ * @example
43739
+ * ```ts
43740
+ * const ephemeralKey = await generateOpenAIEphemeralKey();
43741
+ *
43742
+ * await visitor.startNpcVoiceSession({
43743
+ * ephemeralKey,
43744
+ * voice: "alloy",
43745
+ * instructions: "You are a friendly science tutor helping with photosynthesis.",
43746
+ * model: "gpt-4o-realtime-preview",
43747
+ * });
43748
+ * ```
43749
+ *
43750
+ * @returns {Promise<void | ResponseType>} Returns `{ success: true }` or an error.
43751
+ */
43752
+ startNpcVoiceSession(config) {
43753
+ return __awaiter(this, void 0, void 0, function* () {
43754
+ try {
43755
+ const response = yield this.topiaPublicApi().put(`/world/${this.urlSlug}/visitors/${this.id}/start-npc-voice-session`, { voiceConfig: config }, this.requestOptions);
43756
+ return response.data;
43757
+ }
43758
+ catch (error) {
43759
+ throw this.errorHandler({ error, params: config, sdkMethod: "Visitor.startNpcVoiceSession" });
43760
+ }
43761
+ });
43762
+ }
43763
+ /**
43764
+ * Stop the active AI voice session for this visitor's NPC.
43765
+ *
43766
+ * @keywords voice, npc, ai, chat, audio, realtime, session, stop, end
43767
+ *
43768
+ * @category NPCs
43769
+ *
43770
+ * @example
43771
+ * ```ts
43772
+ * await visitor.stopNpcVoiceSession();
43773
+ * ```
43774
+ *
43775
+ * @returns {Promise<void | ResponseType>} Returns `{ success: true }` or an error.
43776
+ */
43777
+ stopNpcVoiceSession() {
43778
+ return __awaiter(this, void 0, void 0, function* () {
43779
+ try {
43780
+ const response = yield this.topiaPublicApi().put(`/world/${this.urlSlug}/visitors/${this.id}/stop-npc-voice-session`, {}, this.requestOptions);
43781
+ return response.data;
43782
+ }
43783
+ catch (error) {
43784
+ throw this.errorHandler({ error, sdkMethod: "Visitor.stopNpcVoiceSession" });
43785
+ }
43786
+ });
43787
+ }
43716
43788
  /**
43717
43789
  * Retrieves all inventory items owned by this visitor and app's key.
43718
43790
  *
package/package.json CHANGED
@@ -61,5 +61,5 @@
61
61
  "yalc-push": "yarn build && yalc publish --push --dev --no-scripts"
62
62
  },
63
63
  "type": "module",
64
- "version": "0.19.04"
64
+ "version": "0.19.06"
65
65
  }