@realtimex/sdk 1.1.3 → 1.2.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/dist/index.d.mts CHANGED
@@ -79,6 +79,24 @@ interface Task {
79
79
  updated_at: string;
80
80
  runs: TaskRun[];
81
81
  }
82
+ interface TTSOptions {
83
+ voice?: string;
84
+ model?: string;
85
+ speed?: number;
86
+ provider?: string;
87
+ }
88
+ interface TTSProvider {
89
+ id: string;
90
+ name: string;
91
+ type: 'remote' | 'local';
92
+ voices: string[];
93
+ }
94
+ interface TTSProvidersResponse {
95
+ success: boolean;
96
+ providers: TTSProvider[];
97
+ default: string;
98
+ error?: string;
99
+ }
82
100
 
83
101
  /**
84
102
  * Activities Module - HTTP Proxy to RealtimeX Main App
@@ -396,6 +414,36 @@ interface VectorListWorkspacesResponse {
396
414
  workspaces?: string[];
397
415
  error?: string;
398
416
  code?: string;
417
+ error_message?: string;
418
+ }
419
+ interface VectorRegisterResponse {
420
+ success: boolean;
421
+ message?: string;
422
+ error?: string;
423
+ code?: string;
424
+ }
425
+ interface VectorConfigResponse {
426
+ success: boolean;
427
+ provider?: string;
428
+ config?: Record<string, any>;
429
+ error?: string;
430
+ code?: string;
431
+ }
432
+ interface VectorProviderField {
433
+ name: string;
434
+ label: string;
435
+ type: 'string' | 'password';
436
+ placeholder?: string;
437
+ }
438
+ interface VectorProviderMetadata {
439
+ name: string;
440
+ label: string;
441
+ description?: string;
442
+ fields: VectorProviderField[];
443
+ }
444
+ interface VectorProvidersResponse {
445
+ success: boolean;
446
+ providers: VectorProviderMetadata[];
399
447
  }
400
448
  /**
401
449
  * @deprecated Use PermissionRequiredError from api module instead
@@ -468,6 +516,29 @@ declare class VectorStore {
468
516
  * ```
469
517
  */
470
518
  listWorkspaces(): Promise<VectorListWorkspacesResponse>;
519
+ /**
520
+ * Register a custom vector database configuration for this app
521
+ *
522
+ * @example
523
+ * ```ts
524
+ * await sdk.llm.vectors.registerConfig('lancedb', { });
525
+ * ```
526
+ */
527
+ registerConfig(provider: string, config: Record<string, any>): Promise<VectorRegisterResponse>;
528
+ /**
529
+ * List all supported vector database providers and their configuration requirements
530
+ */
531
+ listProviders(): Promise<VectorProvidersResponse>;
532
+ /**
533
+ * Get the current vector database configuration for this app
534
+ *
535
+ * @example
536
+ * ```ts
537
+ * const { provider, config } = await sdk.llm.vectors.getConfig();
538
+ * console.log(`App is using ${provider}`);
539
+ * ```
540
+ */
541
+ getConfig(): Promise<VectorConfigResponse>;
471
542
  }
472
543
  declare class LLMModule {
473
544
  private baseUrl;
@@ -583,6 +654,49 @@ declare class LLMModule {
583
654
  search(query: string, options?: VectorQueryOptions): Promise<VectorQueryResult[]>;
584
655
  }
585
656
 
657
+ declare class TTSModule {
658
+ private baseUrl;
659
+ private appId;
660
+ private appName;
661
+ private apiKey?;
662
+ constructor(realtimexUrl: string, appId: string, appName?: string, apiKey?: string);
663
+ private get headers();
664
+ /**
665
+ * Request a single permission from Electron via internal API
666
+ */
667
+ private requestPermission;
668
+ /**
669
+ * Internal request wrapper that handles automatic permission prompts
670
+ */
671
+ private request;
672
+ /**
673
+ * Generate speech from text (returns full buffer)
674
+ *
675
+ * @example
676
+ * ```ts
677
+ * const buffer = await sdk.tts.speak("Hello world");
678
+ * // Play buffer...
679
+ * ```
680
+ */
681
+ speak(text: string, options?: TTSOptions): Promise<ArrayBuffer>;
682
+ /**
683
+ * Generate speech from text (returns stream)
684
+ *
685
+ * @example
686
+ * ```ts
687
+ * const stream = await sdk.tts.speakStream("Hello world");
688
+ * for await (const chunk of stream) {
689
+ * // Play chunk...
690
+ * }
691
+ * ```
692
+ */
693
+ speakStream(text: string, options?: TTSOptions): AsyncGenerator<Uint8Array>;
694
+ /**
695
+ * List available TTS providers
696
+ */
697
+ listProviders(): Promise<TTSProvider[]>;
698
+ }
699
+
586
700
  /**
587
701
  * RealtimeX Local App SDK
588
702
  *
@@ -597,6 +711,7 @@ declare class RealtimeXSDK {
597
711
  task: TaskModule;
598
712
  port: PortModule;
599
713
  llm: LLMModule;
714
+ tts: TTSModule;
600
715
  readonly appId: string;
601
716
  readonly appName: string | undefined;
602
717
  readonly apiKey: string | undefined;
@@ -623,6 +738,11 @@ declare class RealtimeXSDK {
623
738
  appId?: string;
624
739
  timestamp: string;
625
740
  }>;
741
+ /**
742
+ * Get the absolute path to the data directory for this app.
743
+ * Path: ~/.realtimex.ai/Resources/local-apps/{appId}
744
+ */
745
+ getAppDataDir(): Promise<string>;
626
746
  }
627
747
 
628
- export { ActivitiesModule, type Activity, type Agent, ApiModule, type ChatMessage, type ChatOptions, type ChatResponse, type EmbedOptions, type EmbedResponse, LLMModule, LLMPermissionError, LLMProviderError, PermissionDeniedError, PermissionRequiredError, PortModule, type Provider, type ProvidersResponse, RealtimeXSDK, type SDKConfig, type StreamChunk, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, type VectorDeleteOptions, type VectorDeleteResponse, type VectorQueryOptions, type VectorQueryResponse, type VectorQueryResult, type VectorRecord, VectorStore, type VectorUpsertOptions, type VectorUpsertResponse, WebhookModule, type Workspace };
748
+ export { ActivitiesModule, type Activity, type Agent, ApiModule, type ChatMessage, type ChatOptions, type ChatResponse, type EmbedOptions, type EmbedResponse, LLMModule, LLMPermissionError, LLMProviderError, PermissionDeniedError, PermissionRequiredError, PortModule, type Provider, type ProvidersResponse, RealtimeXSDK, type SDKConfig, type StreamChunk, TTSModule, type TTSOptions, type TTSProvider, type TTSProvidersResponse, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, type VectorDeleteOptions, type VectorDeleteResponse, type VectorQueryOptions, type VectorQueryResponse, type VectorQueryResult, type VectorRecord, VectorStore, type VectorUpsertOptions, type VectorUpsertResponse, WebhookModule, type Workspace };
package/dist/index.d.ts CHANGED
@@ -79,6 +79,24 @@ interface Task {
79
79
  updated_at: string;
80
80
  runs: TaskRun[];
81
81
  }
82
+ interface TTSOptions {
83
+ voice?: string;
84
+ model?: string;
85
+ speed?: number;
86
+ provider?: string;
87
+ }
88
+ interface TTSProvider {
89
+ id: string;
90
+ name: string;
91
+ type: 'remote' | 'local';
92
+ voices: string[];
93
+ }
94
+ interface TTSProvidersResponse {
95
+ success: boolean;
96
+ providers: TTSProvider[];
97
+ default: string;
98
+ error?: string;
99
+ }
82
100
 
83
101
  /**
84
102
  * Activities Module - HTTP Proxy to RealtimeX Main App
@@ -396,6 +414,36 @@ interface VectorListWorkspacesResponse {
396
414
  workspaces?: string[];
397
415
  error?: string;
398
416
  code?: string;
417
+ error_message?: string;
418
+ }
419
+ interface VectorRegisterResponse {
420
+ success: boolean;
421
+ message?: string;
422
+ error?: string;
423
+ code?: string;
424
+ }
425
+ interface VectorConfigResponse {
426
+ success: boolean;
427
+ provider?: string;
428
+ config?: Record<string, any>;
429
+ error?: string;
430
+ code?: string;
431
+ }
432
+ interface VectorProviderField {
433
+ name: string;
434
+ label: string;
435
+ type: 'string' | 'password';
436
+ placeholder?: string;
437
+ }
438
+ interface VectorProviderMetadata {
439
+ name: string;
440
+ label: string;
441
+ description?: string;
442
+ fields: VectorProviderField[];
443
+ }
444
+ interface VectorProvidersResponse {
445
+ success: boolean;
446
+ providers: VectorProviderMetadata[];
399
447
  }
400
448
  /**
401
449
  * @deprecated Use PermissionRequiredError from api module instead
@@ -468,6 +516,29 @@ declare class VectorStore {
468
516
  * ```
469
517
  */
470
518
  listWorkspaces(): Promise<VectorListWorkspacesResponse>;
519
+ /**
520
+ * Register a custom vector database configuration for this app
521
+ *
522
+ * @example
523
+ * ```ts
524
+ * await sdk.llm.vectors.registerConfig('lancedb', { });
525
+ * ```
526
+ */
527
+ registerConfig(provider: string, config: Record<string, any>): Promise<VectorRegisterResponse>;
528
+ /**
529
+ * List all supported vector database providers and their configuration requirements
530
+ */
531
+ listProviders(): Promise<VectorProvidersResponse>;
532
+ /**
533
+ * Get the current vector database configuration for this app
534
+ *
535
+ * @example
536
+ * ```ts
537
+ * const { provider, config } = await sdk.llm.vectors.getConfig();
538
+ * console.log(`App is using ${provider}`);
539
+ * ```
540
+ */
541
+ getConfig(): Promise<VectorConfigResponse>;
471
542
  }
472
543
  declare class LLMModule {
473
544
  private baseUrl;
@@ -583,6 +654,49 @@ declare class LLMModule {
583
654
  search(query: string, options?: VectorQueryOptions): Promise<VectorQueryResult[]>;
584
655
  }
585
656
 
657
+ declare class TTSModule {
658
+ private baseUrl;
659
+ private appId;
660
+ private appName;
661
+ private apiKey?;
662
+ constructor(realtimexUrl: string, appId: string, appName?: string, apiKey?: string);
663
+ private get headers();
664
+ /**
665
+ * Request a single permission from Electron via internal API
666
+ */
667
+ private requestPermission;
668
+ /**
669
+ * Internal request wrapper that handles automatic permission prompts
670
+ */
671
+ private request;
672
+ /**
673
+ * Generate speech from text (returns full buffer)
674
+ *
675
+ * @example
676
+ * ```ts
677
+ * const buffer = await sdk.tts.speak("Hello world");
678
+ * // Play buffer...
679
+ * ```
680
+ */
681
+ speak(text: string, options?: TTSOptions): Promise<ArrayBuffer>;
682
+ /**
683
+ * Generate speech from text (returns stream)
684
+ *
685
+ * @example
686
+ * ```ts
687
+ * const stream = await sdk.tts.speakStream("Hello world");
688
+ * for await (const chunk of stream) {
689
+ * // Play chunk...
690
+ * }
691
+ * ```
692
+ */
693
+ speakStream(text: string, options?: TTSOptions): AsyncGenerator<Uint8Array>;
694
+ /**
695
+ * List available TTS providers
696
+ */
697
+ listProviders(): Promise<TTSProvider[]>;
698
+ }
699
+
586
700
  /**
587
701
  * RealtimeX Local App SDK
588
702
  *
@@ -597,6 +711,7 @@ declare class RealtimeXSDK {
597
711
  task: TaskModule;
598
712
  port: PortModule;
599
713
  llm: LLMModule;
714
+ tts: TTSModule;
600
715
  readonly appId: string;
601
716
  readonly appName: string | undefined;
602
717
  readonly apiKey: string | undefined;
@@ -623,6 +738,11 @@ declare class RealtimeXSDK {
623
738
  appId?: string;
624
739
  timestamp: string;
625
740
  }>;
741
+ /**
742
+ * Get the absolute path to the data directory for this app.
743
+ * Path: ~/.realtimex.ai/Resources/local-apps/{appId}
744
+ */
745
+ getAppDataDir(): Promise<string>;
626
746
  }
627
747
 
628
- export { ActivitiesModule, type Activity, type Agent, ApiModule, type ChatMessage, type ChatOptions, type ChatResponse, type EmbedOptions, type EmbedResponse, LLMModule, LLMPermissionError, LLMProviderError, PermissionDeniedError, PermissionRequiredError, PortModule, type Provider, type ProvidersResponse, RealtimeXSDK, type SDKConfig, type StreamChunk, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, type VectorDeleteOptions, type VectorDeleteResponse, type VectorQueryOptions, type VectorQueryResponse, type VectorQueryResult, type VectorRecord, VectorStore, type VectorUpsertOptions, type VectorUpsertResponse, WebhookModule, type Workspace };
748
+ export { ActivitiesModule, type Activity, type Agent, ApiModule, type ChatMessage, type ChatOptions, type ChatResponse, type EmbedOptions, type EmbedResponse, LLMModule, LLMPermissionError, LLMProviderError, PermissionDeniedError, PermissionRequiredError, PortModule, type Provider, type ProvidersResponse, RealtimeXSDK, type SDKConfig, type StreamChunk, TTSModule, type TTSOptions, type TTSProvider, type TTSProvidersResponse, type Task, TaskModule, type TaskRun, type Thread, type TriggerAgentPayload, type TriggerAgentResponse, type VectorDeleteOptions, type VectorDeleteResponse, type VectorQueryOptions, type VectorQueryResponse, type VectorQueryResult, type VectorRecord, VectorStore, type VectorUpsertOptions, type VectorUpsertResponse, WebhookModule, type Workspace };
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ __export(index_exports, {
39
39
  PermissionRequiredError: () => PermissionRequiredError,
40
40
  PortModule: () => PortModule,
41
41
  RealtimeXSDK: () => RealtimeXSDK,
42
+ TTSModule: () => TTSModule,
42
43
  TaskModule: () => TaskModule,
43
44
  VectorStore: () => VectorStore,
44
45
  WebhookModule: () => WebhookModule
@@ -643,6 +644,38 @@ var VectorStore = class {
643
644
  async listWorkspaces() {
644
645
  return this.request("GET", "/sdk/llm/vectors/workspaces");
645
646
  }
647
+ /**
648
+ * Register a custom vector database configuration for this app
649
+ *
650
+ * @example
651
+ * ```ts
652
+ * await sdk.llm.vectors.registerConfig('lancedb', { });
653
+ * ```
654
+ */
655
+ async registerConfig(provider, config) {
656
+ return this.request("POST", "/sdk/llm/vectors/register", {
657
+ provider,
658
+ config
659
+ });
660
+ }
661
+ /**
662
+ * List all supported vector database providers and their configuration requirements
663
+ */
664
+ async listProviders() {
665
+ return this.request("GET", "/sdk/llm/vectors/providers");
666
+ }
667
+ /**
668
+ * Get the current vector database configuration for this app
669
+ *
670
+ * @example
671
+ * ```ts
672
+ * const { provider, config } = await sdk.llm.vectors.getConfig();
673
+ * console.log(`App is using ${provider}`);
674
+ * ```
675
+ */
676
+ async getConfig() {
677
+ return this.request("GET", "/sdk/llm/vectors/config");
678
+ }
646
679
  };
647
680
  var LLMModule = class {
648
681
  constructor(baseUrl, appId, appName = "Local App", apiKey) {
@@ -948,6 +981,129 @@ var LLMModule = class {
948
981
  }
949
982
  };
950
983
 
984
+ // src/modules/tts.ts
985
+ var TTSModule = class {
986
+ constructor(realtimexUrl, appId, appName, apiKey) {
987
+ this.baseUrl = realtimexUrl.replace(/\/$/, "");
988
+ this.appId = appId;
989
+ this.appName = appName || process.env.RTX_APP_NAME || "Local App";
990
+ this.apiKey = apiKey;
991
+ }
992
+ get headers() {
993
+ if (this.apiKey) {
994
+ return {
995
+ "Content-Type": "application/json",
996
+ "Authorization": `Bearer ${this.apiKey}`
997
+ };
998
+ }
999
+ return {
1000
+ "Content-Type": "application/json",
1001
+ "x-app-id": this.appId
1002
+ };
1003
+ }
1004
+ /**
1005
+ * Request a single permission from Electron via internal API
1006
+ */
1007
+ async requestPermission(permission) {
1008
+ try {
1009
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
1010
+ method: "POST",
1011
+ headers: { "Content-Type": "application/json" },
1012
+ body: JSON.stringify({
1013
+ app_id: this.appId,
1014
+ app_name: this.appName,
1015
+ permission
1016
+ })
1017
+ });
1018
+ const data = await response.json();
1019
+ return data.granted === true;
1020
+ } catch (error) {
1021
+ console.error("[SDK] Permission request failed:", error);
1022
+ return false;
1023
+ }
1024
+ }
1025
+ /**
1026
+ * Internal request wrapper that handles automatic permission prompts
1027
+ */
1028
+ async request(method, endpoint, body, isStream = false) {
1029
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
1030
+ method,
1031
+ headers: this.headers,
1032
+ body: body ? JSON.stringify(body) : void 0
1033
+ });
1034
+ if (!response.ok) {
1035
+ const data = await response.json();
1036
+ if (data.code === "PERMISSION_REQUIRED") {
1037
+ const permission = data.permission || "tts.speak";
1038
+ const granted = await this.requestPermission(permission);
1039
+ if (granted) {
1040
+ return this.request(method, endpoint, body, isStream);
1041
+ }
1042
+ throw new PermissionDeniedError(permission);
1043
+ }
1044
+ throw new Error(data.error || `Request failed: ${response.status}`);
1045
+ }
1046
+ if (isStream) {
1047
+ return response.body;
1048
+ }
1049
+ const contentType = response.headers.get("content-type");
1050
+ if (contentType && contentType.includes("application/json")) {
1051
+ return response.json();
1052
+ }
1053
+ return response.arrayBuffer();
1054
+ }
1055
+ /**
1056
+ * Generate speech from text (returns full buffer)
1057
+ *
1058
+ * @example
1059
+ * ```ts
1060
+ * const buffer = await sdk.tts.speak("Hello world");
1061
+ * // Play buffer...
1062
+ * ```
1063
+ */
1064
+ async speak(text, options = {}) {
1065
+ return this.request("POST", "/sdk/tts", {
1066
+ text,
1067
+ ...options
1068
+ });
1069
+ }
1070
+ /**
1071
+ * Generate speech from text (returns stream)
1072
+ *
1073
+ * @example
1074
+ * ```ts
1075
+ * const stream = await sdk.tts.speakStream("Hello world");
1076
+ * for await (const chunk of stream) {
1077
+ * // Play chunk...
1078
+ * }
1079
+ * ```
1080
+ */
1081
+ async *speakStream(text, options = {}) {
1082
+ const body = await this.request("POST", "/sdk/tts/stream", {
1083
+ text,
1084
+ ...options
1085
+ }, true);
1086
+ if (!body) throw new Error("No response body");
1087
+ const reader = body.getReader();
1088
+ try {
1089
+ while (true) {
1090
+ const { done, value } = await reader.read();
1091
+ if (done) break;
1092
+ yield value;
1093
+ }
1094
+ } finally {
1095
+ reader.releaseLock();
1096
+ }
1097
+ }
1098
+ /**
1099
+ * List available TTS providers
1100
+ */
1101
+ async listProviders() {
1102
+ const data = await this.request("GET", "/sdk/tts/providers");
1103
+ return data.providers || [];
1104
+ }
1105
+ };
1106
+
951
1107
  // src/index.ts
952
1108
  var _RealtimeXSDK = class _RealtimeXSDK {
953
1109
  constructor(config = {}) {
@@ -965,6 +1121,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
965
1121
  this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
966
1122
  this.port = new PortModule(config.defaultPort);
967
1123
  this.llm = new LLMModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
1124
+ this.tts = new TTSModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
968
1125
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
969
1126
  this.register().catch((err) => {
970
1127
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
@@ -1034,6 +1191,31 @@ var _RealtimeXSDK = class _RealtimeXSDK {
1034
1191
  throw new Error(`Connection failed: ${error.message}`);
1035
1192
  }
1036
1193
  }
1194
+ /**
1195
+ * Get the absolute path to the data directory for this app.
1196
+ * Path: ~/.realtimex.ai/Resources/local-apps/{appId}
1197
+ */
1198
+ async getAppDataDir() {
1199
+ try {
1200
+ const headers = { "Content-Type": "application/json" };
1201
+ if (this.apiKey) {
1202
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
1203
+ } else if (this.appId) {
1204
+ headers["x-app-id"] = this.appId;
1205
+ }
1206
+ const response = await fetch(`${this.realtimexUrl.replace(/\/$/, "")}/sdk/local-apps/data-dir`, {
1207
+ method: "GET",
1208
+ headers
1209
+ });
1210
+ const data = await response.json();
1211
+ if (!response.ok) {
1212
+ throw new Error(data.error || "Failed to get data directory");
1213
+ }
1214
+ return data.dataDir;
1215
+ } catch (error) {
1216
+ throw new Error(`Failed to get app data directory: ${error.message}`);
1217
+ }
1218
+ }
1037
1219
  };
1038
1220
  _RealtimeXSDK.DEFAULT_REALTIMEX_URL = "http://localhost:3001";
1039
1221
  var RealtimeXSDK = _RealtimeXSDK;
@@ -1048,6 +1230,7 @@ var RealtimeXSDK = _RealtimeXSDK;
1048
1230
  PermissionRequiredError,
1049
1231
  PortModule,
1050
1232
  RealtimeXSDK,
1233
+ TTSModule,
1051
1234
  TaskModule,
1052
1235
  VectorStore,
1053
1236
  WebhookModule
package/dist/index.mjs CHANGED
@@ -596,6 +596,38 @@ var VectorStore = class {
596
596
  async listWorkspaces() {
597
597
  return this.request("GET", "/sdk/llm/vectors/workspaces");
598
598
  }
599
+ /**
600
+ * Register a custom vector database configuration for this app
601
+ *
602
+ * @example
603
+ * ```ts
604
+ * await sdk.llm.vectors.registerConfig('lancedb', { });
605
+ * ```
606
+ */
607
+ async registerConfig(provider, config) {
608
+ return this.request("POST", "/sdk/llm/vectors/register", {
609
+ provider,
610
+ config
611
+ });
612
+ }
613
+ /**
614
+ * List all supported vector database providers and their configuration requirements
615
+ */
616
+ async listProviders() {
617
+ return this.request("GET", "/sdk/llm/vectors/providers");
618
+ }
619
+ /**
620
+ * Get the current vector database configuration for this app
621
+ *
622
+ * @example
623
+ * ```ts
624
+ * const { provider, config } = await sdk.llm.vectors.getConfig();
625
+ * console.log(`App is using ${provider}`);
626
+ * ```
627
+ */
628
+ async getConfig() {
629
+ return this.request("GET", "/sdk/llm/vectors/config");
630
+ }
599
631
  };
600
632
  var LLMModule = class {
601
633
  constructor(baseUrl, appId, appName = "Local App", apiKey) {
@@ -901,6 +933,129 @@ var LLMModule = class {
901
933
  }
902
934
  };
903
935
 
936
+ // src/modules/tts.ts
937
+ var TTSModule = class {
938
+ constructor(realtimexUrl, appId, appName, apiKey) {
939
+ this.baseUrl = realtimexUrl.replace(/\/$/, "");
940
+ this.appId = appId;
941
+ this.appName = appName || process.env.RTX_APP_NAME || "Local App";
942
+ this.apiKey = apiKey;
943
+ }
944
+ get headers() {
945
+ if (this.apiKey) {
946
+ return {
947
+ "Content-Type": "application/json",
948
+ "Authorization": `Bearer ${this.apiKey}`
949
+ };
950
+ }
951
+ return {
952
+ "Content-Type": "application/json",
953
+ "x-app-id": this.appId
954
+ };
955
+ }
956
+ /**
957
+ * Request a single permission from Electron via internal API
958
+ */
959
+ async requestPermission(permission) {
960
+ try {
961
+ const response = await fetch(`${this.baseUrl}/api/local-apps/request-permission`, {
962
+ method: "POST",
963
+ headers: { "Content-Type": "application/json" },
964
+ body: JSON.stringify({
965
+ app_id: this.appId,
966
+ app_name: this.appName,
967
+ permission
968
+ })
969
+ });
970
+ const data = await response.json();
971
+ return data.granted === true;
972
+ } catch (error) {
973
+ console.error("[SDK] Permission request failed:", error);
974
+ return false;
975
+ }
976
+ }
977
+ /**
978
+ * Internal request wrapper that handles automatic permission prompts
979
+ */
980
+ async request(method, endpoint, body, isStream = false) {
981
+ const response = await fetch(`${this.baseUrl}${endpoint}`, {
982
+ method,
983
+ headers: this.headers,
984
+ body: body ? JSON.stringify(body) : void 0
985
+ });
986
+ if (!response.ok) {
987
+ const data = await response.json();
988
+ if (data.code === "PERMISSION_REQUIRED") {
989
+ const permission = data.permission || "tts.speak";
990
+ const granted = await this.requestPermission(permission);
991
+ if (granted) {
992
+ return this.request(method, endpoint, body, isStream);
993
+ }
994
+ throw new PermissionDeniedError(permission);
995
+ }
996
+ throw new Error(data.error || `Request failed: ${response.status}`);
997
+ }
998
+ if (isStream) {
999
+ return response.body;
1000
+ }
1001
+ const contentType = response.headers.get("content-type");
1002
+ if (contentType && contentType.includes("application/json")) {
1003
+ return response.json();
1004
+ }
1005
+ return response.arrayBuffer();
1006
+ }
1007
+ /**
1008
+ * Generate speech from text (returns full buffer)
1009
+ *
1010
+ * @example
1011
+ * ```ts
1012
+ * const buffer = await sdk.tts.speak("Hello world");
1013
+ * // Play buffer...
1014
+ * ```
1015
+ */
1016
+ async speak(text, options = {}) {
1017
+ return this.request("POST", "/sdk/tts", {
1018
+ text,
1019
+ ...options
1020
+ });
1021
+ }
1022
+ /**
1023
+ * Generate speech from text (returns stream)
1024
+ *
1025
+ * @example
1026
+ * ```ts
1027
+ * const stream = await sdk.tts.speakStream("Hello world");
1028
+ * for await (const chunk of stream) {
1029
+ * // Play chunk...
1030
+ * }
1031
+ * ```
1032
+ */
1033
+ async *speakStream(text, options = {}) {
1034
+ const body = await this.request("POST", "/sdk/tts/stream", {
1035
+ text,
1036
+ ...options
1037
+ }, true);
1038
+ if (!body) throw new Error("No response body");
1039
+ const reader = body.getReader();
1040
+ try {
1041
+ while (true) {
1042
+ const { done, value } = await reader.read();
1043
+ if (done) break;
1044
+ yield value;
1045
+ }
1046
+ } finally {
1047
+ reader.releaseLock();
1048
+ }
1049
+ }
1050
+ /**
1051
+ * List available TTS providers
1052
+ */
1053
+ async listProviders() {
1054
+ const data = await this.request("GET", "/sdk/tts/providers");
1055
+ return data.providers || [];
1056
+ }
1057
+ };
1058
+
904
1059
  // src/index.ts
905
1060
  var _RealtimeXSDK = class _RealtimeXSDK {
906
1061
  constructor(config = {}) {
@@ -918,6 +1073,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
918
1073
  this.task = new TaskModule(this.realtimexUrl, this.appName, this.appId, this.apiKey);
919
1074
  this.port = new PortModule(config.defaultPort);
920
1075
  this.llm = new LLMModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
1076
+ this.tts = new TTSModule(this.realtimexUrl, this.appId, this.appName, this.apiKey);
921
1077
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
922
1078
  this.register().catch((err) => {
923
1079
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
@@ -987,6 +1143,31 @@ var _RealtimeXSDK = class _RealtimeXSDK {
987
1143
  throw new Error(`Connection failed: ${error.message}`);
988
1144
  }
989
1145
  }
1146
+ /**
1147
+ * Get the absolute path to the data directory for this app.
1148
+ * Path: ~/.realtimex.ai/Resources/local-apps/{appId}
1149
+ */
1150
+ async getAppDataDir() {
1151
+ try {
1152
+ const headers = { "Content-Type": "application/json" };
1153
+ if (this.apiKey) {
1154
+ headers["Authorization"] = `Bearer ${this.apiKey}`;
1155
+ } else if (this.appId) {
1156
+ headers["x-app-id"] = this.appId;
1157
+ }
1158
+ const response = await fetch(`${this.realtimexUrl.replace(/\/$/, "")}/sdk/local-apps/data-dir`, {
1159
+ method: "GET",
1160
+ headers
1161
+ });
1162
+ const data = await response.json();
1163
+ if (!response.ok) {
1164
+ throw new Error(data.error || "Failed to get data directory");
1165
+ }
1166
+ return data.dataDir;
1167
+ } catch (error) {
1168
+ throw new Error(`Failed to get app data directory: ${error.message}`);
1169
+ }
1170
+ }
990
1171
  };
991
1172
  _RealtimeXSDK.DEFAULT_REALTIMEX_URL = "http://localhost:3001";
992
1173
  var RealtimeXSDK = _RealtimeXSDK;
@@ -1000,6 +1181,7 @@ export {
1000
1181
  PermissionRequiredError,
1001
1182
  PortModule,
1002
1183
  RealtimeXSDK,
1184
+ TTSModule,
1003
1185
  TaskModule,
1004
1186
  VectorStore,
1005
1187
  WebhookModule
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realtimex/sdk",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "SDK for building Local Apps that integrate with RealtimeX",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -40,4 +40,4 @@
40
40
  "engines": {
41
41
  "node": ">=18.0.0"
42
42
  }
43
- }
43
+ }