@eka-care/medassist-core 1.0.66 → 1.0.67

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 (145) hide show
  1. package/dist/Synapse.d.ts +0 -1
  2. package/dist/connection/ConnectionFactory.d.ts +0 -1
  3. package/dist/connection/SSE.d.ts +0 -1
  4. package/dist/connection/Websocket.d.ts +0 -1
  5. package/dist/constants/index.d.ts +0 -1
  6. package/dist/constants/types.d.ts +0 -1
  7. package/dist/conversation.d.ts +0 -1
  8. package/dist/esm/Synapse.js +612 -0
  9. package/dist/esm/connection/ConnectionFactory.js +27 -0
  10. package/dist/esm/connection/SSE.js +212 -0
  11. package/dist/esm/connection/Websocket.js +178 -0
  12. package/dist/esm/constants/index.js +25 -0
  13. package/dist/esm/constants/types.js +1 -0
  14. package/dist/esm/conversation.js +7 -0
  15. package/dist/esm/events/Events.js +41 -0
  16. package/dist/esm/events/Incoming.js +1 -0
  17. package/dist/esm/events/Outgoing.js +1 -0
  18. package/dist/esm/events/index.js +2 -0
  19. package/dist/esm/events/types.js +5 -0
  20. package/dist/esm/index.js +34 -0
  21. package/dist/esm/internal/Api/BaseResource.js +50 -0
  22. package/dist/esm/internal/Api/HttpClient.js +131 -0
  23. package/dist/esm/internal/Api/types.js +1 -0
  24. package/dist/esm/internal/Error/Error.js +229 -0
  25. package/dist/esm/internal/Error/types.js +9 -0
  26. package/dist/esm/internal/connection/BaseConnection.js +134 -0
  27. package/dist/esm/internal/connection/types.js +17 -0
  28. package/dist/esm/internal/events/EventEmitter.js +26 -0
  29. package/dist/esm/internal/store/index.js +5 -0
  30. package/dist/esm/media/audio/Audio.copy.js +363 -0
  31. package/dist/esm/media/audio/Audio.js +310 -0
  32. package/dist/esm/media/audio/types.js +13 -0
  33. package/dist/esm/media/file/File.js +159 -0
  34. package/dist/esm/messages/MessageManager.js +476 -0
  35. package/dist/esm/messages/types.js +35 -0
  36. package/dist/esm/resources/config/Config.js +11 -0
  37. package/dist/esm/resources/feedback/Feedback.js +9 -0
  38. package/dist/esm/resources/feedback/types.js +7 -0
  39. package/dist/esm/resources/index.js +152 -0
  40. package/dist/esm/resources/session/Session.js +44 -0
  41. package/dist/esm/resources/session/types.js +5 -0
  42. package/dist/esm/resources/toolCall/ToolCall.js +12 -0
  43. package/dist/esm/resources/toolCall/types.js +34 -0
  44. package/dist/esm/resources/types.js +4 -0
  45. package/dist/esm/resources/voice/VoiceResource.js +14 -0
  46. package/dist/esm/resources/voice/types.js +1 -0
  47. package/dist/esm/types/index.js +8 -0
  48. package/dist/esm/utils/Error.js +110 -0
  49. package/dist/esm/voice/VoiceAgent.js +305 -0
  50. package/dist/esm/voice/VoiceAudioAnalyser.js +32 -0
  51. package/dist/esm/voice/index.js +1 -0
  52. package/dist/esm/voice/types.js +15 -0
  53. package/dist/events/Events.d.ts +0 -1
  54. package/dist/events/Incoming.d.ts +0 -1
  55. package/dist/events/Outgoing.d.ts +0 -1
  56. package/dist/events/index.d.ts +0 -1
  57. package/dist/events/types.d.ts +0 -1
  58. package/dist/index.d.ts +0 -1
  59. package/dist/internal/Api/BaseResource.d.ts +0 -1
  60. package/dist/internal/Api/HttpClient.d.ts +0 -1
  61. package/dist/internal/Api/types.d.ts +0 -1
  62. package/dist/internal/Error/Error.d.ts +0 -1
  63. package/dist/internal/Error/types.d.ts +0 -1
  64. package/dist/internal/connection/BaseConnection.d.ts +0 -1
  65. package/dist/internal/connection/types.d.ts +0 -1
  66. package/dist/internal/events/EventEmitter.d.ts +0 -1
  67. package/dist/internal/store/index.d.ts +0 -1
  68. package/dist/media/audio/Audio.copy.d.ts +0 -1
  69. package/dist/media/audio/Audio.d.ts +0 -1
  70. package/dist/media/audio/types.d.ts +0 -1
  71. package/dist/media/file/File.d.ts +0 -1
  72. package/dist/messages/MessageManager.d.ts +0 -1
  73. package/dist/messages/types.d.ts +0 -1
  74. package/dist/resources/config/Config.d.ts +0 -1
  75. package/dist/resources/feedback/Feedback.d.ts +0 -1
  76. package/dist/resources/feedback/types.d.ts +0 -1
  77. package/dist/resources/index.d.ts +0 -1
  78. package/dist/resources/session/Session.d.ts +0 -1
  79. package/dist/resources/session/types.d.ts +0 -1
  80. package/dist/resources/toolCall/ToolCall.d.ts +0 -1
  81. package/dist/resources/toolCall/types.d.ts +0 -1
  82. package/dist/resources/types.d.ts +0 -1
  83. package/dist/resources/voice/VoiceResource.d.ts +0 -1
  84. package/dist/resources/voice/types.d.ts +0 -1
  85. package/dist/types/index.d.ts +0 -1
  86. package/dist/utils/Error.d.ts +0 -1
  87. package/dist/voice/VoiceAgent.d.ts +0 -1
  88. package/dist/voice/VoiceAudioAnalyser.d.ts +0 -1
  89. package/dist/voice/index.d.ts +0 -1
  90. package/dist/voice/types.d.ts +0 -1
  91. package/package.json +4 -2
  92. package/dist/Synapse.d.ts.map +0 -1
  93. package/dist/auth/constants.d.ts +0 -12
  94. package/dist/auth/constants.d.ts.map +0 -1
  95. package/dist/auth/constants.js +0 -10
  96. package/dist/auth/index.d.ts +0 -3
  97. package/dist/auth/index.d.ts.map +0 -1
  98. package/dist/auth/index.js +0 -18
  99. package/dist/auth/session.d.ts +0 -5
  100. package/dist/auth/session.d.ts.map +0 -1
  101. package/dist/auth/session.js +0 -36
  102. package/dist/connection/ConnectionFactory.d.ts.map +0 -1
  103. package/dist/connection/SSE.d.ts.map +0 -1
  104. package/dist/connection/Websocket.d.ts.map +0 -1
  105. package/dist/constants/index.d.ts.map +0 -1
  106. package/dist/constants/types.d.ts.map +0 -1
  107. package/dist/conversation.d.ts.map +0 -1
  108. package/dist/events/Events.d.ts.map +0 -1
  109. package/dist/events/Incoming.d.ts.map +0 -1
  110. package/dist/events/Outgoing.d.ts.map +0 -1
  111. package/dist/events/index.d.ts.map +0 -1
  112. package/dist/events/types.d.ts.map +0 -1
  113. package/dist/index.d.ts.map +0 -1
  114. package/dist/internal/Api/BaseResource.d.ts.map +0 -1
  115. package/dist/internal/Api/HttpClient.d.ts.map +0 -1
  116. package/dist/internal/Api/types.d.ts.map +0 -1
  117. package/dist/internal/Error/Error.d.ts.map +0 -1
  118. package/dist/internal/Error/types.d.ts.map +0 -1
  119. package/dist/internal/connection/BaseConnection.d.ts.map +0 -1
  120. package/dist/internal/connection/types.d.ts.map +0 -1
  121. package/dist/internal/events/EventEmitter.d.ts.map +0 -1
  122. package/dist/internal/store/index.d.ts.map +0 -1
  123. package/dist/media/audio/Audio.copy.d.ts.map +0 -1
  124. package/dist/media/audio/Audio.d.ts.map +0 -1
  125. package/dist/media/audio/types.d.ts.map +0 -1
  126. package/dist/media/file/File.d.ts.map +0 -1
  127. package/dist/messages/MessageManager.d.ts.map +0 -1
  128. package/dist/messages/types.d.ts.map +0 -1
  129. package/dist/resources/config/Config.d.ts.map +0 -1
  130. package/dist/resources/feedback/Feedback.d.ts.map +0 -1
  131. package/dist/resources/feedback/types.d.ts.map +0 -1
  132. package/dist/resources/index.d.ts.map +0 -1
  133. package/dist/resources/session/Session.d.ts.map +0 -1
  134. package/dist/resources/session/types.d.ts.map +0 -1
  135. package/dist/resources/toolCall/ToolCall.d.ts.map +0 -1
  136. package/dist/resources/toolCall/types.d.ts.map +0 -1
  137. package/dist/resources/types.d.ts.map +0 -1
  138. package/dist/resources/voice/VoiceResource.d.ts.map +0 -1
  139. package/dist/resources/voice/types.d.ts.map +0 -1
  140. package/dist/types/index.d.ts.map +0 -1
  141. package/dist/utils/Error.d.ts.map +0 -1
  142. package/dist/voice/VoiceAgent.d.ts.map +0 -1
  143. package/dist/voice/VoiceAudioAnalyser.d.ts.map +0 -1
  144. package/dist/voice/index.d.ts.map +0 -1
  145. package/dist/voice/types.d.ts.map +0 -1
@@ -0,0 +1,131 @@
1
+ import { APIError, APIConnectionTimeoutError, } from "../Error/Error";
2
+ export class HttpClient {
3
+ baseUrl;
4
+ headers;
5
+ timeout;
6
+ maxRetries;
7
+ constructor(config) {
8
+ this.baseUrl = config.baseUrl.replace(/\/$/, ""); // Remove trailing slash
9
+ this.timeout = config.timeout || 30000;
10
+ this.maxRetries = config.maxRetries || 3;
11
+ this.headers = {
12
+ "Content-Type": "application/json",
13
+ ...config.headers, // Include custom headers
14
+ };
15
+ if (config.authorization) {
16
+ this.headers["Authorization"] = config.authorization;
17
+ }
18
+ }
19
+ async request(method, path, options) {
20
+ const maxRetries = options?.retries ?? this.maxRetries;
21
+ let lastError;
22
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
23
+ try {
24
+ const url = this.buildUrl(path, options?.params);
25
+ const response = await fetch(url, {
26
+ method,
27
+ headers: {
28
+ ...this.headers,
29
+ ...options?.headers,
30
+ },
31
+ body: options?.body ? JSON.stringify(options.body) : undefined,
32
+ signal: AbortSignal.timeout(this.timeout),
33
+ });
34
+ if (!response.ok) {
35
+ await this.handleError(response);
36
+ }
37
+ return response.json();
38
+ }
39
+ catch (error) {
40
+ lastError = error;
41
+ // Don't retry on the last attempt
42
+ if (attempt === maxRetries) {
43
+ break;
44
+ }
45
+ // Only retry on network errors and timeouts
46
+ const shouldRetry = (error instanceof TypeError && error.message === "Failed to fetch") ||
47
+ (error instanceof DOMException && error.name === "AbortError") ||
48
+ error instanceof SyntaxError;
49
+ if (!shouldRetry) {
50
+ // Don't retry for API errors (4xx, 5xx), parsing errors, etc.
51
+ break;
52
+ }
53
+ // Exponential backoff: wait 2^attempt * 100ms
54
+ const delay = Math.pow(2, attempt) * 100;
55
+ await new Promise((resolve) => setTimeout(resolve, delay));
56
+ }
57
+ }
58
+ // If we get here, all retries failed
59
+ if (!lastError) {
60
+ throw new APIError("Unknown error occurred", 500, {
61
+ type: "UNKNOWN_ERROR",
62
+ });
63
+ }
64
+ if (lastError instanceof TypeError &&
65
+ lastError.message === "Failed to fetch") {
66
+ // Network error - no internet, DNS failure, etc.
67
+ throw new APIError("Network error: Unable to connect to the server. Please check your internet connection.", 0, { type: "NETWORK_ERROR", originalError: lastError.message });
68
+ }
69
+ if (lastError instanceof DOMException && lastError.name === "AbortError") {
70
+ // Timeout error
71
+ throw new APIConnectionTimeoutError({
72
+ message: `Request timed out after ${this.timeout}ms`,
73
+ });
74
+ }
75
+ if (lastError instanceof SyntaxError) {
76
+ // JSON parsing error
77
+ throw new APIError("Invalid response format from server", 502, {
78
+ type: "PARSE_ERROR",
79
+ originalError: lastError.message,
80
+ });
81
+ }
82
+ // If it's already an APIError, re-throw it
83
+ if (lastError instanceof APIError) {
84
+ throw lastError;
85
+ }
86
+ // Any other unexpected error
87
+ throw new APIError(`Request failed: ${lastError.message || "Unknown error"}`, 500, { type: "UNKNOWN_ERROR", originalError: lastError });
88
+ }
89
+ async get(path, params, options) {
90
+ return this.request("GET", path, { params, ...options });
91
+ }
92
+ async post(path, body, options) {
93
+ return this.request("POST", path, { body, ...options });
94
+ }
95
+ async put(path, body, options) {
96
+ return this.request("PUT", path, { body, ...options });
97
+ }
98
+ async delete(path, options) {
99
+ return this.request("DELETE", path, { ...options });
100
+ }
101
+ async patch(path, body, options) {
102
+ return this.request("PATCH", path, { body, ...options });
103
+ }
104
+ buildUrl(path, params) {
105
+ let url = `${this.baseUrl}${path}`;
106
+ if (params) {
107
+ const queryString = new URLSearchParams(params).toString();
108
+ url += `?${queryString}`;
109
+ }
110
+ return url;
111
+ }
112
+ async handleError(response) {
113
+ let errorMessage;
114
+ let errorData;
115
+ try {
116
+ errorData = await response.json();
117
+ const body = errorData;
118
+ const nestedError = body?.error;
119
+ errorMessage =
120
+ body?.message ||
121
+ body?.msg ||
122
+ nestedError?.msg ||
123
+ nestedError?.message ||
124
+ response.statusText;
125
+ }
126
+ catch (error) {
127
+ errorMessage = response.statusText;
128
+ }
129
+ throw APIError.generate(response.status, errorData, errorMessage, response.headers);
130
+ }
131
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,229 @@
1
+ export const SynapseErrorCode = {
2
+ API: "API_ERROR",
3
+ CONNECTION: "CONNECTION_ERROR",
4
+ RECORDING: "RECORDING_ERROR",
5
+ FILE: "FILE_ERROR",
6
+ SESSION: "SESSION_ERROR",
7
+ MESSAGE: "MESSAGE_ERROR",
8
+ STORE: "STORE_ERROR",
9
+ CONFIGURATION: "CONFIGURATION_ERROR",
10
+ VALIDATION: "VALIDATION_ERROR",
11
+ AUTH: "AUTH_ERROR",
12
+ UNKNOWN: "UNKNOWN_ERROR",
13
+ };
14
+ export class SynapseError extends Error {
15
+ code;
16
+ timestamp;
17
+ cause;
18
+ context;
19
+ hint;
20
+ displayMessage;
21
+ constructor(message, code = SynapseErrorCode.UNKNOWN, options = {}) {
22
+ super(message);
23
+ this.name = "SynapseError";
24
+ this.code = code;
25
+ this.timestamp = new Date();
26
+ this.cause = options.cause;
27
+ this.context = options.context;
28
+ this.hint = options.hint;
29
+ this.displayMessage = options.displayMessage || options?.hint || message;
30
+ if (Error.captureStackTrace) {
31
+ Error.captureStackTrace(this, this.constructor);
32
+ }
33
+ }
34
+ }
35
+ export class APIError extends SynapseError {
36
+ /** HTTP status code */
37
+ status;
38
+ /** JSON body of the error response or custom error object */
39
+ error;
40
+ /** HTTP response headers */
41
+ headers;
42
+ constructor(message, status, error, headers) {
43
+ const errorMessage = APIError.makeMessage(status, error, message);
44
+ super(errorMessage, SynapseErrorCode.API, {
45
+ cause: error,
46
+ context: {
47
+ status,
48
+ hasBody: Boolean(error),
49
+ },
50
+ hint: status && status >= 500
51
+ ? "Retry the request or contact support if the issue persists."
52
+ : undefined,
53
+ displayMessage: message || "Something went wrong", //give user friednly message,
54
+ });
55
+ this.name = "APIError";
56
+ this.status = status;
57
+ this.error = error;
58
+ this.headers = headers;
59
+ }
60
+ static makeMessage(status, error, message) {
61
+ const msg = error instanceof Error ? error.message : message;
62
+ if (status && msg) {
63
+ return `HTTP ${status}: ${msg}`;
64
+ }
65
+ if (status) {
66
+ return `${status} status code (no body)`;
67
+ }
68
+ if (msg) {
69
+ return msg;
70
+ }
71
+ return "(no status code or body)";
72
+ }
73
+ static generate(status, errorResponse, message, headers) {
74
+ if (!status) {
75
+ return new APIUserAbortError({ message });
76
+ }
77
+ const extractedError = errorResponse?.["error"];
78
+ const error = extractedError &&
79
+ typeof extractedError === "object" &&
80
+ !Array.isArray(extractedError)
81
+ ? extractedError
82
+ : undefined;
83
+ switch (status) {
84
+ case 400:
85
+ return new BadRequestError(message || "Bad Request", status, error, headers);
86
+ case 401:
87
+ return new UnauthorizedError(message || "Unauthorized", status, error, headers);
88
+ case 403:
89
+ return new PermissionDeniedError(message || "Permission Denied", status, error, headers);
90
+ case 404:
91
+ return new NotFoundError(message || "Not Found", status, error, headers);
92
+ case 405:
93
+ return new MethodNotAllowedError(message || "Method Not Allowed", status, error, headers);
94
+ case 429:
95
+ return new RateLimitError(message || "Rate Limit Exceeded", status, error, headers);
96
+ case 500:
97
+ return new InternalServerError(message || "Internal Server Error", status, error, headers);
98
+ default:
99
+ return new APIError(message || "API Error", status, error, headers);
100
+ }
101
+ }
102
+ }
103
+ export class APIUserAbortError extends APIError {
104
+ constructor({ message } = {}) {
105
+ super(message || "Request was aborted.", undefined, undefined, undefined);
106
+ this.name = "APIUserAbortError";
107
+ }
108
+ }
109
+ export class APIConnectionTimeoutError extends APIError {
110
+ constructor({ message } = {}) {
111
+ super(message || "Request timed out.", undefined, undefined, undefined);
112
+ this.name = "APIConnectionTimeoutError";
113
+ }
114
+ }
115
+ export class BadRequestError extends APIError {
116
+ constructor(message, status, error, headers) {
117
+ super(message, status, error, headers);
118
+ this.name = "BadRequestError";
119
+ }
120
+ }
121
+ export class UnauthorizedError extends APIError {
122
+ constructor(message, status, error, headers) {
123
+ super(message, status, error, headers);
124
+ this.name = "UnauthorizedError";
125
+ }
126
+ }
127
+ export class PermissionDeniedError extends APIError {
128
+ constructor(message, status, error, headers) {
129
+ super(message, status, error, headers);
130
+ this.name = "PermissionDeniedError";
131
+ }
132
+ }
133
+ export class NotFoundError extends APIError {
134
+ constructor(message, status, error, headers) {
135
+ super(message, status, error, headers);
136
+ this.name = "NotFoundError";
137
+ }
138
+ }
139
+ export class MethodNotAllowedError extends APIError {
140
+ constructor(message, status, error, headers) {
141
+ super(message, status, error, headers);
142
+ this.name = "MethodNotAllowedError";
143
+ }
144
+ }
145
+ export class RateLimitError extends APIError {
146
+ constructor(message, status, error, headers) {
147
+ super(message, status, error, headers);
148
+ this.name = "RateLimitError";
149
+ }
150
+ }
151
+ export class InternalServerError extends APIError {
152
+ constructor(message, status, error, headers) {
153
+ super(message, status, error, headers);
154
+ this.name = "InternalServerError";
155
+ }
156
+ }
157
+ export class ConnectionError extends SynapseError {
158
+ constructor(message, options = {}) {
159
+ super(message, SynapseErrorCode.CONNECTION, options);
160
+ this.name = "ConnectionError";
161
+ }
162
+ }
163
+ export class RecordingError extends SynapseError {
164
+ constructor(message, options = {}) {
165
+ super(message, SynapseErrorCode.RECORDING, options);
166
+ this.name = "RecordingError";
167
+ }
168
+ }
169
+ export class AuthenticationError extends SynapseError {
170
+ constructor(message, options = {}) {
171
+ super(message, SynapseErrorCode.AUTH, options);
172
+ this.name = "AuthenticationError";
173
+ }
174
+ }
175
+ export class FileError extends SynapseError {
176
+ constructor(message, options = {}) {
177
+ super(message, SynapseErrorCode.FILE, options);
178
+ this.name = "FileError";
179
+ }
180
+ }
181
+ export class SessionError extends SynapseError {
182
+ constructor(message, options = {}) {
183
+ super(message, SynapseErrorCode.SESSION, options);
184
+ this.name = "SessionError";
185
+ }
186
+ }
187
+ export class MessageError extends SynapseError {
188
+ constructor(message, options = {}) {
189
+ super(message, SynapseErrorCode.MESSAGE, options);
190
+ this.name = "MessageError";
191
+ }
192
+ }
193
+ export class StoreError extends SynapseError {
194
+ constructor(message, options = {}) {
195
+ super(message, SynapseErrorCode.STORE, options);
196
+ this.name = "StoreError";
197
+ }
198
+ }
199
+ export class ConfigurationError extends SynapseError {
200
+ constructor(message, options = {}) {
201
+ super(message, SynapseErrorCode.CONFIGURATION, options);
202
+ this.name = "ConfigurationError";
203
+ }
204
+ }
205
+ export class ValidationError extends SynapseError {
206
+ constructor(message, options = {}) {
207
+ super(message, SynapseErrorCode.VALIDATION, options);
208
+ this.name = "ValidationError";
209
+ }
210
+ }
211
+ export function normalizeError(error, ctor, fallbackMessage, options = {}) {
212
+ if (error instanceof ctor) {
213
+ return error;
214
+ }
215
+ const baseOptions = {
216
+ ...options,
217
+ context: {
218
+ ...(error instanceof SynapseError ? error.context : undefined),
219
+ ...options.context,
220
+ },
221
+ hint: options.hint ?? (error instanceof SynapseError ? error.hint : undefined),
222
+ cause: options.cause ?? error,
223
+ };
224
+ if (error instanceof SynapseError) {
225
+ return new ctor(error.message, baseOptions);
226
+ }
227
+ const message = error instanceof Error && error.message ? error.message : fallbackMessage;
228
+ return new ctor(message, baseOptions);
229
+ }
@@ -0,0 +1,9 @@
1
+ export const ErrorType = {
2
+ NETWORK_ERROR: "NETWORK_ERROR",
3
+ TIMEOUT_ERROR: "TIMEOUT_ERROR",
4
+ API_ERROR: "API_ERROR",
5
+ RATE_LIMIT_ERROR: "RATE_LIMIT_ERROR",
6
+ SERVER_ERROR: "SERVER_ERROR",
7
+ PARSE_ERROR: "PARSE_ERROR",
8
+ UNKNOWN_ERROR: "UNKNOWN_ERROR",
9
+ };
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Abstract base class for all connection types
3
+ */
4
+ import { EventEmitter } from "../events/EventEmitter";
5
+ import { ConnectionStatus, } from "./types";
6
+ export class BaseConnection {
7
+ /**
8
+ * Current connection status
9
+ */
10
+ status = ConnectionStatus.CONNECTING;
11
+ /**
12
+ * Queue to store messages received before callback is registered
13
+ */
14
+ queue = [];
15
+ /**
16
+ * Event emitter to handle events
17
+ */
18
+ eventEmitter = new EventEmitter();
19
+ /**
20
+ * Disconnection details (null if still connected)
21
+ */
22
+ disconnectionDetails = null;
23
+ onErrorCallback = null;
24
+ onDisconnectCallback = null;
25
+ onMessageCallback = null;
26
+ onOpenCallback = null;
27
+ onStatusChangeCallback = null;
28
+ /**
29
+ * Get current connection status
30
+ */
31
+ getStatus() {
32
+ return this.status;
33
+ }
34
+ /**
35
+ * Register callback for connection open events
36
+ */
37
+ onOpen(callback) {
38
+ this.onOpenCallback = callback;
39
+ }
40
+ /**
41
+ * Register callback for incoming messages
42
+ */
43
+ onMessage(callback) {
44
+ this.onMessageCallback = callback;
45
+ if (this.queue.length > 0) {
46
+ const pendingMessages = [...this.queue];
47
+ this.queue.length = 0;
48
+ queueMicrotask(() => {
49
+ pendingMessages.forEach((message) => {
50
+ this.onMessageCallback?.(message);
51
+ });
52
+ });
53
+ }
54
+ }
55
+ /**
56
+ * Register callback for disconnection events
57
+ */
58
+ onDisconnect(callback) {
59
+ this.onDisconnectCallback = callback;
60
+ const details = this.disconnectionDetails;
61
+ if (details) {
62
+ queueMicrotask(() => {
63
+ this.onDisconnectCallback?.(details);
64
+ });
65
+ }
66
+ }
67
+ /**
68
+ * Register callback for error events
69
+ */
70
+ onError(callback) {
71
+ this.onErrorCallback = callback;
72
+ }
73
+ /**
74
+ * Register a listener for a specific event
75
+ */
76
+ on(event, listener) {
77
+ this.eventEmitter.on(event, listener);
78
+ }
79
+ /**
80
+ * Remove a listener for a specific event
81
+ */
82
+ off(event, listener) {
83
+ this.eventEmitter.off(event, listener);
84
+ }
85
+ /**
86
+ * Emit an event
87
+ */
88
+ emit(event, ...args) {
89
+ this.eventEmitter.emit(event, ...args);
90
+ }
91
+ /**
92
+ * Register callback for status changes
93
+ */
94
+ onStatusChange(callback) {
95
+ this.onStatusChangeCallback = callback;
96
+ // Immediately invoke with current status
97
+ queueMicrotask(() => {
98
+ callback(this.status);
99
+ });
100
+ }
101
+ /**
102
+ * Protected method to handle disconnection
103
+ * Ensures disconnect callback is only invoked once
104
+ */
105
+ disconnect(details) {
106
+ if (!this.disconnectionDetails) {
107
+ this.disconnectionDetails = details;
108
+ this.updateStatus(ConnectionStatus.NOT_CONNECTED);
109
+ this.onDisconnectCallback?.(details);
110
+ }
111
+ }
112
+ /**
113
+ * Protected method to handle incoming messages
114
+ * Queues messages if no callback is registered yet
115
+ * message type can be extended to include more types of messages
116
+ */
117
+ handleMessage(message) {
118
+ if (this.onMessageCallback) {
119
+ this.onMessageCallback(message);
120
+ }
121
+ else {
122
+ this.queue.push(message);
123
+ }
124
+ }
125
+ /**
126
+ * Protected method to update connection status
127
+ */
128
+ updateStatus(status) {
129
+ if (this.status !== status) {
130
+ this.status = status;
131
+ this.onStatusChangeCallback?.(status);
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Connection types and interfaces for the Synapse SDK
3
+ */
4
+ export const ConnectionStatus = {
5
+ CONNECTING: "connecting",
6
+ CONNECTED: "connected",
7
+ NOT_CONNECTED: "not_connected",
8
+ };
9
+ export const DisconnectionReason = {
10
+ CLIENT_CLOSED: "client_closed",
11
+ SERVER_CLOSED: "server_closed",
12
+ CONNECTION_ERROR: "connection_error",
13
+ AUTHENTICATION_ERROR: "authentication_error",
14
+ MAX_RECONNECT_ATTEMPTS: "max_reconnect_attempts",
15
+ TIMEOUT: "timeout",
16
+ NETWORK_ERROR: "network_error",
17
+ };
@@ -0,0 +1,26 @@
1
+ export class EventEmitter {
2
+ eventListeners = new Map();
3
+ on(event, listener) {
4
+ const listeners = this.eventListeners.get(event) || new Set();
5
+ listeners.add(listener);
6
+ this.eventListeners.set(event, listeners);
7
+ }
8
+ off(event, listener) {
9
+ const listeners = this.eventListeners.get(event);
10
+ if (listeners) {
11
+ listeners.delete(listener);
12
+ if (listeners.size === 0) {
13
+ this.eventListeners.delete(event);
14
+ }
15
+ }
16
+ }
17
+ emit(event, ...args) {
18
+ const listeners = this.eventListeners.get(event);
19
+ if (listeners) {
20
+ listeners.forEach((listener) => listener(...args));
21
+ }
22
+ }
23
+ removeAllListeners() {
24
+ this.eventListeners.clear();
25
+ }
26
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * make an abstract class for all types of storage (localStorage, sessionStorage, etc.)
3
+ */
4
+ export class Storage {
5
+ }