@eka-care/medassist-core 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.
Files changed (98) hide show
  1. package/README.md +32 -0
  2. package/dist/Synapse.d.ts +131 -0
  3. package/dist/Synapse.d.ts.map +1 -0
  4. package/dist/Synapse.js +479 -0
  5. package/dist/connection/ConnectionFactory.d.ts +17 -0
  6. package/dist/connection/ConnectionFactory.d.ts.map +1 -0
  7. package/dist/connection/ConnectionFactory.js +28 -0
  8. package/dist/connection/Websocket.d.ts +61 -0
  9. package/dist/connection/Websocket.d.ts.map +1 -0
  10. package/dist/connection/Websocket.js +184 -0
  11. package/dist/constants/index.d.ts +17 -0
  12. package/dist/constants/index.d.ts.map +1 -0
  13. package/dist/constants/index.js +28 -0
  14. package/dist/constants/types.d.ts +2 -0
  15. package/dist/constants/types.d.ts.map +1 -0
  16. package/dist/constants/types.js +2 -0
  17. package/dist/events/Events.d.ts +47 -0
  18. package/dist/events/Events.d.ts.map +1 -0
  19. package/dist/events/Events.js +46 -0
  20. package/dist/events/Incoming.d.ts +2 -0
  21. package/dist/events/Incoming.d.ts.map +1 -0
  22. package/dist/events/Incoming.js +2 -0
  23. package/dist/events/Outgoing.d.ts +2 -0
  24. package/dist/events/Outgoing.d.ts.map +1 -0
  25. package/dist/events/Outgoing.js +2 -0
  26. package/dist/events/index.d.ts +3 -0
  27. package/dist/events/index.d.ts.map +1 -0
  28. package/dist/events/index.js +38 -0
  29. package/dist/events/types.d.ts +86 -0
  30. package/dist/events/types.d.ts.map +1 -0
  31. package/dist/events/types.js +6 -0
  32. package/dist/index.d.ts +27 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +69 -0
  35. package/dist/internal/Api/BaseResource.d.ts +35 -0
  36. package/dist/internal/Api/BaseResource.d.ts.map +1 -0
  37. package/dist/internal/Api/BaseResource.js +54 -0
  38. package/dist/internal/Api/HttpClient.d.ts +25 -0
  39. package/dist/internal/Api/HttpClient.d.ts.map +1 -0
  40. package/dist/internal/Api/HttpClient.js +131 -0
  41. package/dist/internal/Api/types.d.ts +7 -0
  42. package/dist/internal/Api/types.d.ts.map +1 -0
  43. package/dist/internal/Api/types.js +2 -0
  44. package/dist/internal/Error/Error.d.ts +97 -0
  45. package/dist/internal/Error/Error.d.ts.map +1 -0
  46. package/dist/internal/Error/Error.js +243 -0
  47. package/dist/internal/Error/types.d.ts +17 -0
  48. package/dist/internal/Error/types.d.ts.map +1 -0
  49. package/dist/internal/Error/types.js +12 -0
  50. package/dist/internal/connection/BaseConnection.d.ts +100 -0
  51. package/dist/internal/connection/BaseConnection.d.ts.map +1 -0
  52. package/dist/internal/connection/BaseConnection.js +138 -0
  53. package/dist/internal/connection/types.d.ts +43 -0
  54. package/dist/internal/connection/types.d.ts.map +1 -0
  55. package/dist/internal/connection/types.js +20 -0
  56. package/dist/internal/events/EventEmitter.d.ts +7 -0
  57. package/dist/internal/events/EventEmitter.d.ts.map +1 -0
  58. package/dist/internal/events/EventEmitter.js +27 -0
  59. package/dist/internal/store/index.d.ts +10 -0
  60. package/dist/internal/store/index.d.ts.map +1 -0
  61. package/dist/internal/store/index.js +9 -0
  62. package/dist/media/audio/Audio.d.ts +37 -0
  63. package/dist/media/audio/Audio.d.ts.map +1 -0
  64. package/dist/media/audio/Audio.js +310 -0
  65. package/dist/media/audio/types.d.ts +25 -0
  66. package/dist/media/audio/types.d.ts.map +1 -0
  67. package/dist/media/audio/types.js +10 -0
  68. package/dist/media/file/File.d.ts +54 -0
  69. package/dist/media/file/File.d.ts.map +1 -0
  70. package/dist/media/file/File.js +159 -0
  71. package/dist/messages/MessageManager.d.ts +79 -0
  72. package/dist/messages/MessageManager.d.ts.map +1 -0
  73. package/dist/messages/MessageManager.js +420 -0
  74. package/dist/messages/types.d.ts +74 -0
  75. package/dist/messages/types.d.ts.map +1 -0
  76. package/dist/messages/types.js +34 -0
  77. package/dist/resources/config/Config.d.ts +5 -0
  78. package/dist/resources/config/Config.d.ts.map +1 -0
  79. package/dist/resources/config/Config.js +5 -0
  80. package/dist/resources/index.d.ts +34 -0
  81. package/dist/resources/index.d.ts.map +1 -0
  82. package/dist/resources/index.js +108 -0
  83. package/dist/resources/session/Session.d.ts +21 -0
  84. package/dist/resources/session/Session.d.ts.map +1 -0
  85. package/dist/resources/session/Session.js +39 -0
  86. package/dist/resources/session/types.d.ts +17 -0
  87. package/dist/resources/session/types.d.ts.map +1 -0
  88. package/dist/resources/session/types.js +8 -0
  89. package/dist/resources/types.d.ts +22 -0
  90. package/dist/resources/types.d.ts.map +1 -0
  91. package/dist/resources/types.js +5 -0
  92. package/dist/types/index.d.ts +8 -0
  93. package/dist/types/index.d.ts.map +1 -0
  94. package/dist/types/index.js +24 -0
  95. package/dist/utils/Error.d.ts +45 -0
  96. package/dist/utils/Error.d.ts.map +1 -0
  97. package/dist/utils/Error.js +114 -0
  98. package/package.json +41 -0
@@ -0,0 +1,37 @@
1
+ import { type AudioConfig, type AudioDataCallback, type AudioErrorCallback, type AudioRecordingStatusCallback } from "./types";
2
+ export declare class AudioManager {
3
+ private mediaRecorder;
4
+ private mediaStream;
5
+ private recordingStartTime;
6
+ private autoPauseTimer;
7
+ private config;
8
+ private onAudioData;
9
+ private onAudioError;
10
+ private onRecordingStatusChange;
11
+ private suppressCallbacks;
12
+ constructor(config?: Partial<AudioConfig>);
13
+ private checkCurrentPermissionState;
14
+ start(onAudioData: AudioDataCallback, onRecordingStatusChange?: AudioRecordingStatusCallback, onAudioError?: AudioErrorCallback): Promise<void>;
15
+ private processAudioChunk;
16
+ private toRecordingError;
17
+ private handleError;
18
+ /**
19
+ * Set up auto-pause timer for 15-minute limit
20
+ */
21
+ private setupAutoPauseTimer;
22
+ private setupMediaRecorderEvents;
23
+ /**
24
+ * Convert blob to base64 string
25
+ */
26
+ private blobToBase64;
27
+ /**
28
+ * Stop recording manually
29
+ */
30
+ stop(): void;
31
+ /**
32
+ * Cancel recording (discard data and suppress callbacks)
33
+ */
34
+ cancel(): void;
35
+ destroy(): void;
36
+ }
37
+ //# sourceMappingURL=Audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Audio.d.ts","sourceRoot":"","sources":["../../../src/media/audio/Audio.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EAEvB,KAAK,4BAA4B,EAElC,MAAM,SAAS,CAAC;AAGjB,qBAAa,YAAY;IACvB,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,cAAc,CAA8C;IAEpE,OAAO,CAAC,MAAM,CAAc;IAE5B,OAAO,CAAC,WAAW,CAAkC;IACrD,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,uBAAuB,CAA6C;IAC5E,OAAO,CAAC,iBAAiB,CAAS;gBAEtB,MAAM,GAAE,OAAO,CAAC,WAAW,CAAM;YAU/B,2BAA2B;IAa5B,KAAK,CAChB,WAAW,EAAE,iBAAiB,EAC9B,uBAAuB,CAAC,EAAE,4BAA4B,EACtD,YAAY,CAAC,EAAE,kBAAkB,GAChC,OAAO,CAAC,IAAI,CAAC;YAkGF,iBAAiB;IAyB/B,OAAO,CAAC,gBAAgB;IA0BxB,OAAO,CAAC,WAAW;IAoBnB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,wBAAwB;IAsChC;;OAEG;IACH,OAAO,CAAC,YAAY;IA8BpB;;OAEG;IACH,IAAI,IAAI,IAAI;IA8BZ;;OAEG;IACH,MAAM,IAAI,IAAI;IAiCd,OAAO,IAAI,IAAI;CAiChB"}
@@ -0,0 +1,310 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AudioManager = void 0;
4
+ const types_1 = require("./types");
5
+ const Error_1 = require("../../internal/Error/Error");
6
+ class AudioManager {
7
+ mediaRecorder = null;
8
+ mediaStream = null;
9
+ recordingStartTime = 0;
10
+ autoPauseTimer = null;
11
+ config;
12
+ onAudioData = null;
13
+ onAudioError = null;
14
+ onRecordingStatusChange = null;
15
+ suppressCallbacks = false; //gurad against late recorder events like ondatavaailable after cancel () or cleanup() is called
16
+ constructor(config = {}) {
17
+ this.config = {
18
+ mimeType: "audio/webm;codecs=opus",
19
+ audioBitsPerSecond: 128000,
20
+ maxRecordingDuration: 900000, // 15 minutes
21
+ autoPauseEnabled: true,
22
+ ...config,
23
+ };
24
+ }
25
+ async checkCurrentPermissionState() {
26
+ const permission = await navigator.permissions.query({
27
+ name: "microphone",
28
+ });
29
+ if (permission.state === "denied") {
30
+ throw new Error_1.RecordingError("Microphone permission denied", {
31
+ context: { permissionState: permission.state },
32
+ hint: "Ensure the browser has microphone access enabled for this site.",
33
+ });
34
+ }
35
+ return permission.state;
36
+ }
37
+ async start(onAudioData, onRecordingStatusChange, onAudioError //Clearly handles the error inside the callback without unhandled rejections
38
+ ) {
39
+ try {
40
+ // Check if mediaDevices is available
41
+ if (!navigator.mediaDevices) {
42
+ throw new Error_1.RecordingError("Media devices API is not available. This usually means the page is not served over HTTPS or there are browser restrictions.", {
43
+ context: { feature: "mediaDevices" },
44
+ hint: "Serve the app over HTTPS and verify browser/device microphone support.",
45
+ });
46
+ }
47
+ // Check if MediaRecorder is supported
48
+ if (!window.MediaRecorder) {
49
+ throw new Error_1.RecordingError("MediaRecorder is not supported in this browser", {
50
+ context: { feature: "MediaRecorder" },
51
+ hint: "Use a browser that supports the MediaRecorder API.",
52
+ });
53
+ }
54
+ // Check for supported audio formats in order of preference
55
+ const supportedTypes = [
56
+ "audio/mp3",
57
+ "audio/ogg;codecs=opus",
58
+ "audio/mp4",
59
+ "audio/ogg",
60
+ "audio/wav",
61
+ ].filter((type) => MediaRecorder.isTypeSupported(type));
62
+ if (supportedTypes.length === 0) {
63
+ throw new Error_1.RecordingError("No supported audio formats found in this browser", {
64
+ context: { requestedTypes: supportedTypes },
65
+ hint: "Verify codec support or adjust the requested MIME types.",
66
+ });
67
+ }
68
+ // Update config with best supported mime type
69
+ this.config.mimeType = supportedTypes[0];
70
+ await this.checkCurrentPermissionState();
71
+ this.onAudioData = onAudioData;
72
+ this.onAudioError = onAudioError ?? null;
73
+ this.onRecordingStatusChange = onRecordingStatusChange ?? null;
74
+ this.suppressCallbacks = false; //reset the guard against late recorder events
75
+ // Get user media
76
+ this.mediaStream = await navigator.mediaDevices.getUserMedia({
77
+ audio: {
78
+ echoCancellation: false,
79
+ noiseSuppression: false,
80
+ autoGainControl: false,
81
+ sampleRate: 44100,
82
+ channelCount: 1,
83
+ },
84
+ });
85
+ // Create MediaRecorder with fallback if the selected format fails
86
+ this.mediaRecorder = new MediaRecorder(this.mediaStream, {
87
+ mimeType: this.config.mimeType,
88
+ audioBitsPerSecond: this.config.audioBitsPerSecond,
89
+ });
90
+ // Verify MediaRecorder is in a valid state
91
+ if (this.mediaRecorder.state !== "inactive") {
92
+ throw new Error_1.RecordingError("MediaRecorder is in an invalid state for start()", {
93
+ context: { recorderState: this.mediaRecorder.state },
94
+ });
95
+ }
96
+ // Set up event handlers
97
+ this.setupMediaRecorderEvents();
98
+ // Start recording
99
+ this.mediaRecorder.start();
100
+ this.recordingStartTime = Date.now();
101
+ this.onRecordingStatusChange?.(types_1.AudioRecordingStatus.LISTENING);
102
+ // Set up auto-pause timer if enabled
103
+ if (this.config.autoPauseEnabled) {
104
+ this.setupAutoPauseTimer();
105
+ }
106
+ }
107
+ catch (error) {
108
+ throw this.toRecordingError(error, "Failed to start audio recording", {
109
+ stage: "start",
110
+ });
111
+ }
112
+ }
113
+ async processAudioChunk(blob) {
114
+ try {
115
+ this.onRecordingStatusChange?.(types_1.AudioRecordingStatus.PROCESSING);
116
+ const base64Audio = await this.blobToBase64(blob);
117
+ const now = Date.now();
118
+ if (!this.onAudioData) {
119
+ return;
120
+ }
121
+ const audioData = {
122
+ audio: base64Audio,
123
+ format: this.config.mimeType,
124
+ duration: this.recordingStartTime > 0 ? now - this.recordingStartTime : 0,
125
+ timestamp: this.recordingStartTime > 0 ? this.recordingStartTime : now,
126
+ };
127
+ this.onAudioData(audioData);
128
+ this.onRecordingStatusChange?.(types_1.AudioRecordingStatus.TRANSCRIBING);
129
+ }
130
+ catch (error) {
131
+ this.handleError(error, { stage: "process_audio_chunk" });
132
+ }
133
+ }
134
+ toRecordingError(error, fallbackMessage, context) {
135
+ if (error instanceof Error_1.RecordingError) {
136
+ return error;
137
+ }
138
+ if (error instanceof Error_1.SynapseError) {
139
+ return new Error_1.RecordingError(error.message, {
140
+ cause: error,
141
+ context: { ...error.context, ...context },
142
+ hint: error.hint,
143
+ });
144
+ }
145
+ const message = error instanceof Error && error.message ? error.message : fallbackMessage;
146
+ return new Error_1.RecordingError(message, {
147
+ cause: error,
148
+ context,
149
+ });
150
+ }
151
+ handleError(error, context) {
152
+ const recordingError = this.toRecordingError(error, "Unexpected recording error", context);
153
+ this.onRecordingStatusChange?.(types_1.AudioRecordingStatus.ERROR);
154
+ if (this.onAudioError) {
155
+ try {
156
+ this.onAudioError(recordingError);
157
+ }
158
+ catch (callbackError) {
159
+ console.error("Audio error callback failed:", callbackError);
160
+ }
161
+ }
162
+ else {
163
+ console.error("AudioManager error:", recordingError);
164
+ }
165
+ }
166
+ /**
167
+ * Set up auto-pause timer for 15-minute limit
168
+ */
169
+ setupAutoPauseTimer() {
170
+ if (this.autoPauseTimer) {
171
+ clearTimeout(this.autoPauseTimer);
172
+ }
173
+ this.autoPauseTimer = setTimeout(() => {
174
+ console.log("Auto-pause timer triggered after 15 minutes");
175
+ this.stop();
176
+ }, this.config.maxRecordingDuration);
177
+ }
178
+ setupMediaRecorderEvents() {
179
+ if (!this.mediaRecorder)
180
+ return;
181
+ this.mediaRecorder.ondataavailable = (event) => {
182
+ if (this.suppressCallbacks || event.data.size <= 0) {
183
+ return;
184
+ }
185
+ this.processAudioChunk(event.data).catch((error) => this.handleError(error, {
186
+ stage: "media_recorder_ondataavailable",
187
+ hasData: event.data.size > 0,
188
+ }));
189
+ };
190
+ this.mediaRecorder.onstop = async () => {
191
+ this.recordingStartTime = 0;
192
+ };
193
+ this.mediaRecorder.onerror = (event) => {
194
+ this.handleError(event.error instanceof Error
195
+ ? event.error
196
+ : new Error("MediaRecorder encountered an unknown error"), { stage: "media_recorder_onerror" });
197
+ };
198
+ this.mediaRecorder.onstart = () => {
199
+ console.log("MediaRecorder started recording");
200
+ if (this.mediaRecorder) {
201
+ console.log("MediaRecorder state:", this.mediaRecorder.state);
202
+ console.log("MediaRecorder MIME type:", this.mediaRecorder.mimeType);
203
+ }
204
+ };
205
+ }
206
+ /**
207
+ * Convert blob to base64 string
208
+ */
209
+ blobToBase64(blob) {
210
+ return new Promise((resolve, reject) => {
211
+ const reader = new FileReader();
212
+ reader.onload = () => {
213
+ if (typeof reader.result === "string") {
214
+ // Remove data URL prefix (e.g., "data:audio/mp3;base64,")
215
+ const base64 = reader.result.split(",")[1];
216
+ resolve(base64);
217
+ }
218
+ else {
219
+ reject(new Error_1.RecordingError("Failed to convert blob to base64", {
220
+ context: { stage: "blob_to_base64" },
221
+ }));
222
+ }
223
+ };
224
+ reader.onerror = () => reject(new Error_1.RecordingError("FileReader error while converting audio chunk to base64", {
225
+ cause: reader.error ?? undefined,
226
+ context: { stage: "blob_to_base64" },
227
+ }));
228
+ reader.readAsDataURL(blob);
229
+ });
230
+ }
231
+ /**
232
+ * Stop recording manually
233
+ */
234
+ stop() {
235
+ if (!this.mediaRecorder)
236
+ return;
237
+ try {
238
+ // Clear auto-pause timer
239
+ if (this.autoPauseTimer) {
240
+ clearTimeout(this.autoPauseTimer);
241
+ this.autoPauseTimer = null;
242
+ }
243
+ // Stop MediaRecorder
244
+ if (this.mediaRecorder.state === "recording") {
245
+ this.mediaRecorder.stop();
246
+ }
247
+ // Stop media stream
248
+ if (this.mediaStream) {
249
+ this.mediaStream.getTracks().forEach((track) => track.stop());
250
+ this.mediaStream = null;
251
+ }
252
+ this.onRecordingStatusChange?.(types_1.AudioRecordingStatus.IDLE);
253
+ console.log("Audio recording stopped manually");
254
+ }
255
+ catch (error) {
256
+ throw this.toRecordingError(error, "Failed to stop audio recording", {
257
+ stage: "stop",
258
+ });
259
+ }
260
+ }
261
+ /**
262
+ * Cancel recording (discard data and suppress callbacks)
263
+ */
264
+ cancel() {
265
+ if (!this.mediaRecorder)
266
+ return;
267
+ try {
268
+ this.suppressCallbacks = true;
269
+ if (this.autoPauseTimer) {
270
+ clearTimeout(this.autoPauseTimer);
271
+ this.autoPauseTimer = null;
272
+ }
273
+ // Prevent ondataavailable from pushing chunks
274
+ this.mediaRecorder.ondataavailable = null;
275
+ // Stop MediaRecorder
276
+ if (this.mediaRecorder.state === "recording") {
277
+ this.mediaRecorder.stop();
278
+ }
279
+ // Stop media stream
280
+ if (this.mediaStream) {
281
+ this.mediaStream.getTracks().forEach((track) => track.stop());
282
+ this.mediaStream = null;
283
+ }
284
+ this.onRecordingStatusChange?.(types_1.AudioRecordingStatus.IDLE);
285
+ }
286
+ catch (error) {
287
+ throw this.toRecordingError(error, "Failed to cancel audio recording", {
288
+ stage: "cancel",
289
+ });
290
+ }
291
+ }
292
+ destroy() {
293
+ try {
294
+ this.cancel();
295
+ if (this.mediaRecorder) {
296
+ this.mediaRecorder = null;
297
+ }
298
+ if (this.mediaStream) {
299
+ this.mediaStream.getTracks().forEach((track) => track.stop());
300
+ this.mediaStream = null;
301
+ }
302
+ }
303
+ catch (error) {
304
+ throw this.toRecordingError(error, "Failed to destroy audio resources", {
305
+ stage: "destroy",
306
+ });
307
+ }
308
+ }
309
+ }
310
+ exports.AudioManager = AudioManager;
@@ -0,0 +1,25 @@
1
+ import { RecordingError } from "../../internal/Error/Error";
2
+ export interface AudioMetaData {
3
+ audio: string;
4
+ format: string;
5
+ duration: number;
6
+ timestamp: number;
7
+ }
8
+ export interface AudioConfig {
9
+ mimeType: string;
10
+ audioBitsPerSecond: number;
11
+ maxRecordingDuration: number;
12
+ autoPauseEnabled: boolean;
13
+ }
14
+ export type AudioDataCallback = (data: AudioMetaData) => void;
15
+ export type AudioErrorCallback = (error: RecordingError) => void;
16
+ export declare const AudioRecordingStatus: {
17
+ readonly IDLE: "idle";
18
+ readonly LISTENING: "listening";
19
+ readonly ERROR: "error";
20
+ readonly PROCESSING: "processing";
21
+ readonly TRANSCRIBING: "transcribing";
22
+ };
23
+ export type AudioRecordingStatus = (typeof AudioRecordingStatus)[keyof typeof AudioRecordingStatus];
24
+ export type AudioRecordingStatusCallback = (status: AudioRecordingStatus) => void;
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/media/audio/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;AAC9D,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;AACjE,eAAO,MAAM,oBAAoB;;;;;;CAMvB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAC9B,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,OAAO,oBAAoB,CAAC,CAAC;AACnE,MAAM,MAAM,4BAA4B,GAAG,CACzC,MAAM,EAAE,oBAAoB,KACzB,IAAI,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AudioRecordingStatus = void 0;
4
+ exports.AudioRecordingStatus = {
5
+ IDLE: "idle",
6
+ LISTENING: "listening",
7
+ ERROR: "error",
8
+ PROCESSING: "processing",
9
+ TRANSCRIBING: "transcribing",
10
+ };
@@ -0,0 +1,54 @@
1
+ export declare class Filemanager {
2
+ private pendingFiles;
3
+ private pendingMessage?;
4
+ private pendingFormat;
5
+ private messageId?;
6
+ /**
7
+ * Set the files for upload
8
+ */
9
+ setFilesForUpload(files: File[], messageId?: string, message?: string): void;
10
+ /**
11
+ * Get the pending file state
12
+ */
13
+ getPendingFileState(): {
14
+ files: File[];
15
+ messageId: string;
16
+ message: string;
17
+ format: string;
18
+ };
19
+ /**
20
+ * Upload files to presigned URLs
21
+ */
22
+ uploadFilesToPresignedUrl(presignedUrls: string[]): Promise<string>;
23
+ /**
24
+ * Zips multiple files into a single zip file
25
+ * @param files Array of files to zip
26
+ * @param zipFileName Name for the zip file (without extension)
27
+ * @returns Promise<Blob> - The zipped file as a blob
28
+ */
29
+ zipFiles(): Promise<Blob>;
30
+ /**
31
+ * Creates a File object from a blob with a specific name
32
+ * @param blob The blob to convert
33
+ * @param fileName The name for the file
34
+ * @returns File object
35
+ */
36
+ blobToFile(blob: Blob, fileName: string): File;
37
+ /**
38
+ * Checks if multiple files should be zipped
39
+ * @param files Array of files
40
+ * @returns boolean - true if files should be zipped
41
+ */
42
+ shouldZipFiles(): boolean;
43
+ /**
44
+ * Gets the appropriate file name for upload (either zip or single file)
45
+ * @param files Array of files
46
+ * @returns string - the file name to use for upload
47
+ */
48
+ getUploadFileName(): string;
49
+ /**
50
+ * Clears the pending files
51
+ */
52
+ clearPendingFilesState(): void;
53
+ }
54
+ //# sourceMappingURL=File.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"File.d.ts","sourceRoot":"","sources":["../../../src/media/file/File.ts"],"names":[],"mappings":"AAMA,qBAAa,WAAW;IACtB,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,cAAc,CAAC,CAAc;IACrC,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,SAAS,CAAC,CAAc;IAEhC;;OAEG;IACI,iBAAiB,CACtB,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACf,IAAI;IAaP;;OAEG;IAEI,mBAAmB,IAAI;QAC5B,KAAK,EAAE,IAAI,EAAE,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB;IASD;;OAEG;IACU,yBAAyB,CACpC,aAAa,EAAE,MAAM,EAAE,GACtB,OAAO,CAAC,MAAM,CAAC;IA4ElB;;;;;OAKG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IActC;;;;;OAKG;IACI,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIrD;;;;OAIG;IACI,cAAc,IAAI,OAAO;IAIhC;;;;OAIG;IACI,iBAAiB,IAAI,MAAM;IAOlC;;OAEG;IACI,sBAAsB,IAAI,IAAI;CAMtC"}
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Filemanager = void 0;
7
+ /**
8
+ * Class to store file states
9
+ * Helpers: Zipping, uploading to presigned url, etc.
10
+ */
11
+ const jszip_1 = __importDefault(require("jszip"));
12
+ const Error_1 = require("../../internal/Error/Error");
13
+ class Filemanager {
14
+ pendingFiles = [];
15
+ pendingMessage = "";
16
+ pendingFormat = "";
17
+ messageId = "";
18
+ /**
19
+ * Set the files for upload
20
+ */
21
+ setFilesForUpload(files, messageId, message) {
22
+ if (this.pendingFiles.length > 0) {
23
+ this.clearPendingFilesState();
24
+ }
25
+ this.pendingFiles = files;
26
+ this.messageId = messageId || Date.now().toString();
27
+ if (message && message.trim()) {
28
+ this.pendingMessage = message;
29
+ }
30
+ this.pendingFormat =
31
+ files.length > 1 ? "zip" : files?.[0]?.type?.split("/")?.[1] || "unknown";
32
+ }
33
+ /**
34
+ * Get the pending file state
35
+ */
36
+ getPendingFileState() {
37
+ return {
38
+ files: this.pendingFiles,
39
+ messageId: this.messageId || "",
40
+ message: this.pendingMessage || "",
41
+ format: this.pendingFormat || "",
42
+ };
43
+ }
44
+ /**
45
+ * Upload files to presigned URLs
46
+ */
47
+ async uploadFilesToPresignedUrl(presignedUrls) {
48
+ let successCount = 0;
49
+ // Filter out invalid URLs
50
+ const validUrls = presignedUrls.filter((url) => url && url.trim());
51
+ try {
52
+ if (validUrls.length === 0) {
53
+ throw new Error_1.FileError("No valid presigned URLs provided", {
54
+ context: { stage: "uploadFilesToPresignedUrl" },
55
+ });
56
+ }
57
+ let fileToUpload;
58
+ let contentType;
59
+ if (this.shouldZipFiles()) {
60
+ // Zip multiple files into a single file
61
+ const zipBlob = await this.zipFiles();
62
+ const zipFileName = this.getUploadFileName();
63
+ fileToUpload = this.blobToFile(zipBlob, zipFileName);
64
+ contentType = "application/zip";
65
+ }
66
+ else {
67
+ // Single file, upload as is
68
+ fileToUpload = this.pendingFiles?.[0];
69
+ contentType = fileToUpload.type;
70
+ }
71
+ // Upload to all presigned URLs
72
+ for (let i = 0; i < validUrls.length; i++) {
73
+ const url = validUrls[i];
74
+ const response = await fetch(url, {
75
+ method: "PUT",
76
+ body: fileToUpload,
77
+ headers: {
78
+ "Content-Type": contentType,
79
+ "x-ms-blob-type": "BlockBlob",
80
+ },
81
+ });
82
+ if (!response.ok) {
83
+ throw new Error_1.FileError(`Failed to upload ${fileToUpload.name} to URL ${i + 1}: ${response.status} ${response.statusText}`, {
84
+ context: {
85
+ stage: "uploadFilesToPresignedUrl",
86
+ status: response.status,
87
+ url,
88
+ },
89
+ });
90
+ }
91
+ successCount++;
92
+ }
93
+ // Call sendFileUploadComplete only once with the first presigned URL
94
+ // this.sendFileUploadComplete(validUrls[0]);
95
+ return validUrls[0];
96
+ }
97
+ catch (error) {
98
+ if (successCount > 0) {
99
+ // this.sendFileUploadComplete(validUrls[0]);
100
+ return validUrls[0];
101
+ }
102
+ throw (0, Error_1.normalizeError)(error, Error_1.FileError, "Failed to upload files to presigned URL", { context: { stage: "uploadFilesToPresignedUrl" } });
103
+ }
104
+ }
105
+ /**
106
+ * Zips multiple files into a single zip file
107
+ * @param files Array of files to zip
108
+ * @param zipFileName Name for the zip file (without extension)
109
+ * @returns Promise<Blob> - The zipped file as a blob
110
+ */
111
+ async zipFiles() {
112
+ const zip = new jszip_1.default();
113
+ // Add each file to the zip
114
+ this.pendingFiles.forEach((file) => {
115
+ zip.file(file.name, file);
116
+ });
117
+ // Generate the zip file as a blob
118
+ const zipBlob = await zip.generateAsync({ type: "blob" });
119
+ return zipBlob;
120
+ }
121
+ /**
122
+ * Creates a File object from a blob with a specific name
123
+ * @param blob The blob to convert
124
+ * @param fileName The name for the file
125
+ * @returns File object
126
+ */
127
+ blobToFile(blob, fileName) {
128
+ return new File([blob], fileName, { type: blob.type });
129
+ }
130
+ /**
131
+ * Checks if multiple files should be zipped
132
+ * @param files Array of files
133
+ * @returns boolean - true if files should be zipped
134
+ */
135
+ shouldZipFiles() {
136
+ return this.pendingFiles.length > 1;
137
+ }
138
+ /**
139
+ * Gets the appropriate file name for upload (either zip or single file)
140
+ * @param files Array of files
141
+ * @returns string - the file name to use for upload
142
+ */
143
+ getUploadFileName() {
144
+ if (this.shouldZipFiles()) {
145
+ return `uploaded_files_${Date.now()}.zip`;
146
+ }
147
+ return this.pendingFiles[0]?.name || "file";
148
+ }
149
+ /**
150
+ * Clears the pending files
151
+ */
152
+ clearPendingFilesState() {
153
+ this.pendingFiles = [];
154
+ this.pendingMessage = "";
155
+ this.pendingFormat = "";
156
+ this.messageId = "";
157
+ }
158
+ }
159
+ exports.Filemanager = Filemanager;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * MessageManager class to handle sending and receiving messages
3
+ * Works with BaseConnection and Store
4
+ */
5
+ import { type SynapseSDKCallbacks } from "../Synapse";
6
+ import { type IncomingSocketChatMessage, type IncomingSocketStreamMessage, type IncomingSocketErrorMessage, type IncomingSocketEndOfStreamMessage } from "../events/Events";
7
+ import { BaseConnection } from "../internal/connection/BaseConnection";
8
+ import { type SocketChatRequestData } from "./types";
9
+ import { type DisconnectionDetails } from "../internal/connection/types";
10
+ export declare class MessageManager {
11
+ private connection;
12
+ private callbacks;
13
+ private fileManager;
14
+ private audioManager;
15
+ constructor(connection: BaseConnection, callbacks?: SynapseSDKCallbacks);
16
+ /**
17
+ * Handle file upload process
18
+ */
19
+ private handleFileUploadProcess;
20
+ /**
21
+ * send chat message through socket
22
+ */
23
+ sendSocketChatMessage({ message, messageId, type, files, url, tool_use_id, tool_use_params, hidden, }: SocketChatRequestData): void;
24
+ /**
25
+ * Handle incoming chat message
26
+ */
27
+ handleIncomingSocketChatMessage(message: IncomingSocketChatMessage): void;
28
+ /**
29
+ * Handle incoming stream message
30
+ */
31
+ handleIncomingSocketStreamMessage(message: IncomingSocketStreamMessage): void;
32
+ handleDisconnect(details: DisconnectionDetails): void;
33
+ /**
34
+ * Handle incoming end of stream message
35
+ */
36
+ handleIncomingSocketEndOfStreamMessage(_message: IncomingSocketEndOfStreamMessage): void;
37
+ /**
38
+ * Handle incoming error message
39
+ */
40
+ handleIncomingSocketErrorMessage(message: IncomingSocketErrorMessage): void;
41
+ /**
42
+ * send authentication message
43
+ */
44
+ sendSocketAuthMessage(sessionToken: string): void;
45
+ /**
46
+ * send ping message
47
+ */
48
+ sendSocketPingMessage(): void;
49
+ /**
50
+ * start recording audio
51
+ */
52
+ private sendSocketStreamMessage;
53
+ /**
54
+ * send audio message
55
+ */
56
+ startRecordingWithSocket(): void;
57
+ /**
58
+ * stop recording audio
59
+ */
60
+ endRecordingWithSocket(): void;
61
+ /**
62
+ * send pong message
63
+ */
64
+ sendSocketPongMessage(): void;
65
+ handleConnectionEstablished(): void;
66
+ /**
67
+ * Cleanup message service
68
+ */
69
+ cleanupMessageServerState(): void;
70
+ /**
71
+ * Generate a unique message ID
72
+ */
73
+ private generateId;
74
+ private emitError;
75
+ private toFileError;
76
+ private toRecordingError;
77
+ private assertConnection;
78
+ }
79
+ //# sourceMappingURL=MessageManager.d.ts.map