@unboundcx/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +456 -0
- package/base.js +263 -0
- package/index.js +181 -0
- package/package.json +88 -0
- package/services/ai.js +151 -0
- package/services/enroll.js +238 -0
- package/services/externalOAuth.js +117 -0
- package/services/generateId.js +39 -0
- package/services/googleCalendar.js +92 -0
- package/services/layouts.js +91 -0
- package/services/login.js +76 -0
- package/services/lookup.js +53 -0
- package/services/messaging.js +687 -0
- package/services/notes.js +137 -0
- package/services/objects.js +163 -0
- package/services/phoneNumbers.js +215 -0
- package/services/portals.js +127 -0
- package/services/recordTypes.js +173 -0
- package/services/sipEndpoints.js +93 -0
- package/services/storage.js +168 -0
- package/services/subscriptions.js +73 -0
- package/services/verification.js +87 -0
- package/services/video.js +380 -0
- package/services/voice.js +434 -0
- package/services/workflows.js +291 -0
- package/test-backwards-compatibility.js +195 -0
- package/test-complete-coverage.js +247 -0
- package/test-constructor-patterns.js +111 -0
package/base.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/* eslint-disable indent */
|
|
2
|
+
/* eslint-disable prettier/prettier */
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* Base SDK Class with Transport Plugin System
|
|
6
|
+
*
|
|
7
|
+
* Optional Dependencies:
|
|
8
|
+
* - mime-types: For accurate MIME type detection (automatically imported if available)
|
|
9
|
+
*
|
|
10
|
+
* This package is optional and the SDK will gracefully fall back to built-in MIME type
|
|
11
|
+
* detection if not installed. For best MIME type accuracy, it's recommended to install:
|
|
12
|
+
*
|
|
13
|
+
* npm install mime-types
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export class BaseSDK {
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
// Support both object and legacy positional parameters for backwards compatibility
|
|
19
|
+
if (typeof options === 'string') {
|
|
20
|
+
// Legacy positional parameters: (namespace, callId, token, fwRequestId)
|
|
21
|
+
this.namespace = options || process?.env?.namespace;
|
|
22
|
+
this.callId = arguments[1];
|
|
23
|
+
this.token = arguments[2];
|
|
24
|
+
this.fwRequestId = arguments[3];
|
|
25
|
+
} else {
|
|
26
|
+
// New object-based parameters
|
|
27
|
+
const { namespace, callId, token, fwRequestId } = options;
|
|
28
|
+
this.namespace = namespace || process?.env?.namespace;
|
|
29
|
+
this.callId = callId;
|
|
30
|
+
this.token = token;
|
|
31
|
+
this.fwRequestId = fwRequestId;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.transports = new Map();
|
|
35
|
+
this._initializeEnvironment();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
_initializeEnvironment() {
|
|
39
|
+
if (typeof window === 'undefined') {
|
|
40
|
+
// Server-side (Node.js)
|
|
41
|
+
this.environment = 'node';
|
|
42
|
+
this.baseURL = `https://${this.namespace ? this.namespace : 'login'}.${
|
|
43
|
+
process.env?.API_BASE_URL
|
|
44
|
+
}`;
|
|
45
|
+
} else {
|
|
46
|
+
// Client-side (browser)
|
|
47
|
+
this.environment = 'browser';
|
|
48
|
+
this.baseUrl = this.baseUrl || process?.env?.API_BASE_URL;
|
|
49
|
+
if (this.baseUrl && !this.baseUrl.startsWith('api.')) {
|
|
50
|
+
this.baseUrl = `api.${this.baseUrl}`;
|
|
51
|
+
}
|
|
52
|
+
this.setNamespace(this.namespace);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
setToken(token) {
|
|
57
|
+
this.token = token;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
setNamespace(namespace) {
|
|
61
|
+
this.namespace = namespace;
|
|
62
|
+
|
|
63
|
+
if (this.environment === 'node') {
|
|
64
|
+
this.baseURL = `https://${this.namespace ? this.namespace : 'login'}.${
|
|
65
|
+
process.env?.API_BASE_URL
|
|
66
|
+
}`;
|
|
67
|
+
} else {
|
|
68
|
+
this.fullUrl = `https://${this.namespace}.${this.baseUrl}`;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
addTransport(transport) {
|
|
73
|
+
if (!transport || typeof transport.request !== 'function') {
|
|
74
|
+
throw new Error('Transport must have a request method');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const priority = transport.getPriority ? transport.getPriority() : 50;
|
|
78
|
+
const name = transport.name || `transport_${Date.now()}`;
|
|
79
|
+
|
|
80
|
+
this.transports.set(name, {
|
|
81
|
+
transport,
|
|
82
|
+
priority
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
removeTransport(name) {
|
|
87
|
+
this.transports.delete(name);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async _getAvailableTransport(forceFetch = false) {
|
|
91
|
+
if (forceFetch) {
|
|
92
|
+
return null; // Use built-in HTTP
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Sort transports by priority (lower number = higher priority)
|
|
96
|
+
const sortedTransports = Array.from(this.transports.values())
|
|
97
|
+
.sort((a, b) => a.priority - b.priority);
|
|
98
|
+
|
|
99
|
+
for (const { transport } of sortedTransports) {
|
|
100
|
+
try {
|
|
101
|
+
if (transport.isAvailable && await transport.isAvailable()) {
|
|
102
|
+
return transport;
|
|
103
|
+
}
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.debug(`Transport ${transport.name} not available:`, err.message);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return null; // Fall back to HTTP
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
validateParams(params, schema) {
|
|
114
|
+
for (const key in schema) {
|
|
115
|
+
if (params[key] === undefined && schema[key].required) {
|
|
116
|
+
throw new Error(`Missing required parameter ${key}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (params[key] !== undefined) {
|
|
120
|
+
const expectedType = schema[key].type;
|
|
121
|
+
const actualValue = params[key];
|
|
122
|
+
let isValidType = false;
|
|
123
|
+
|
|
124
|
+
if (expectedType === 'array') {
|
|
125
|
+
isValidType = Array.isArray(actualValue);
|
|
126
|
+
} else {
|
|
127
|
+
isValidType = typeof actualValue === expectedType;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!isValidType) {
|
|
131
|
+
const actualType = Array.isArray(actualValue)
|
|
132
|
+
? 'array'
|
|
133
|
+
: typeof actualValue;
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Invalid type for parameter ${key}: expected ${expectedType}, got ${actualType}`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async _fetch(endpoint, method, params = {}, forceFetch = false) {
|
|
143
|
+
const { body, query, headers = {} } = params;
|
|
144
|
+
|
|
145
|
+
this.validateParams(
|
|
146
|
+
{ endpoint, method, body, query, headers },
|
|
147
|
+
{
|
|
148
|
+
endpoint: { type: 'string', required: true },
|
|
149
|
+
method: { type: 'string', required: true },
|
|
150
|
+
body: { type: 'object', required: false },
|
|
151
|
+
query: { type: 'object', required: false },
|
|
152
|
+
headers: { type: 'object', required: false },
|
|
153
|
+
},
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Try transport plugins first
|
|
157
|
+
const transport = await this._getAvailableTransport(forceFetch);
|
|
158
|
+
if (transport) {
|
|
159
|
+
try {
|
|
160
|
+
const result = await transport.request(endpoint, method, params, {
|
|
161
|
+
namespace: this.namespace,
|
|
162
|
+
token: this.token,
|
|
163
|
+
callId: this.callId,
|
|
164
|
+
fwRequestId: this.fwRequestId,
|
|
165
|
+
baseURL: this.baseURL || this.fullUrl,
|
|
166
|
+
});
|
|
167
|
+
return result;
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.warn(`Transport ${transport.name} failed, falling back to HTTP:`, err.message);
|
|
170
|
+
// Fall through to HTTP
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Built-in HTTP transport (fallback)
|
|
175
|
+
return this._httpRequest(endpoint, method, params);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async _httpRequest(endpoint, method, params = {}) {
|
|
179
|
+
const { body, query, headers = {} } = params;
|
|
180
|
+
|
|
181
|
+
const options = {
|
|
182
|
+
method,
|
|
183
|
+
headers: {
|
|
184
|
+
// Only set Content-Type if not already provided (check both cases)
|
|
185
|
+
...(headers?.['Content-Type'] || headers?.['content-type']
|
|
186
|
+
? {}
|
|
187
|
+
: { 'Content-Type': 'application/json' }),
|
|
188
|
+
...headers,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// Add auth headers
|
|
193
|
+
if (this.token) {
|
|
194
|
+
options.headers.Authorization = `Bearer ${this.token}`;
|
|
195
|
+
}
|
|
196
|
+
if (this.fwRequestId) {
|
|
197
|
+
options.headers['x-request-id-fw'] = this.fwRequestId;
|
|
198
|
+
}
|
|
199
|
+
if (this.callId) {
|
|
200
|
+
options.headers['x-call-id'] = this.callId;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Set credentials for browser environment
|
|
204
|
+
if (this.environment === 'browser') {
|
|
205
|
+
options.credentials = 'include';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let url;
|
|
209
|
+
if (this.environment === 'node') {
|
|
210
|
+
url = `${this.baseURL}${endpoint}`;
|
|
211
|
+
} else {
|
|
212
|
+
url = `${this.fullUrl}${endpoint}`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Add query parameters
|
|
216
|
+
if (query) {
|
|
217
|
+
const params = new URLSearchParams(query).toString();
|
|
218
|
+
url += `?${params}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Handle body
|
|
222
|
+
if (options.method.toLowerCase() === 'get') {
|
|
223
|
+
delete options.body;
|
|
224
|
+
} else if (body) {
|
|
225
|
+
// For FormData or Buffer, pass directly without JSON.stringify
|
|
226
|
+
const isFormData =
|
|
227
|
+
body &&
|
|
228
|
+
(body.constructor.name === 'FormData' ||
|
|
229
|
+
typeof body.getBoundary === 'function');
|
|
230
|
+
const isBuffer = Buffer && Buffer.isBuffer && Buffer.isBuffer(body);
|
|
231
|
+
|
|
232
|
+
if (isFormData || isBuffer) {
|
|
233
|
+
options.body = body;
|
|
234
|
+
} else {
|
|
235
|
+
options.body = JSON.stringify(body);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const response = await fetch(url, options);
|
|
240
|
+
const bodyResponse = await response.json();
|
|
241
|
+
|
|
242
|
+
const responseHeaders = response.headers;
|
|
243
|
+
const responseRequestId =
|
|
244
|
+
responseHeaders?.get?.('x-request-id') ||
|
|
245
|
+
responseHeaders?.['x-request-id'];
|
|
246
|
+
|
|
247
|
+
if (!response.ok) {
|
|
248
|
+
throw {
|
|
249
|
+
name: `API :: Error :: https :: ${method} :: ${endpoint} :: ${responseRequestId} :: ${response?.status} :: ${response?.statusText}`,
|
|
250
|
+
message: bodyResponse?.message || `API Error occured.`,
|
|
251
|
+
method,
|
|
252
|
+
endpoint,
|
|
253
|
+
status: response?.status,
|
|
254
|
+
statusText: response?.statusText,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
console.log(
|
|
259
|
+
`API :: https :: ${method} :: ${endpoint} :: ${responseRequestId}`,
|
|
260
|
+
);
|
|
261
|
+
return bodyResponse;
|
|
262
|
+
}
|
|
263
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/* eslint-disable indent */
|
|
2
|
+
/* eslint-disable prettier/prettier */
|
|
3
|
+
|
|
4
|
+
import { BaseSDK } from './base.js';
|
|
5
|
+
import { LoginService } from './services/login.js';
|
|
6
|
+
import { ObjectsService } from './services/objects.js';
|
|
7
|
+
import { MessagingService } from './services/messaging.js';
|
|
8
|
+
import { VideoService } from './services/video.js';
|
|
9
|
+
import { VoiceService } from './services/voice.js';
|
|
10
|
+
import { AIService } from './services/ai.js';
|
|
11
|
+
import { LookupService } from './services/lookup.js';
|
|
12
|
+
import { LayoutsService } from './services/layouts.js';
|
|
13
|
+
import { SubscriptionsService } from './services/subscriptions.js';
|
|
14
|
+
import { WorkflowsService } from './services/workflows.js';
|
|
15
|
+
import { NotesService } from './services/notes.js';
|
|
16
|
+
import { StorageService } from './services/storage.js';
|
|
17
|
+
import { VerificationService } from './services/verification.js';
|
|
18
|
+
import { PortalsService } from './services/portals.js';
|
|
19
|
+
import { SipEndpointsService } from './services/sipEndpoints.js';
|
|
20
|
+
import { ExternalOAuthService } from './services/externalOAuth.js';
|
|
21
|
+
import { GoogleCalendarService } from './services/googleCalendar.js';
|
|
22
|
+
import { EnrollService } from './services/enroll.js';
|
|
23
|
+
import { PhoneNumbersService } from './services/phoneNumbers.js';
|
|
24
|
+
import { RecordTypesService } from './services/recordTypes.js';
|
|
25
|
+
import { GenerateIdService } from './services/generateId.js';
|
|
26
|
+
|
|
27
|
+
class UnboundSDK extends BaseSDK {
|
|
28
|
+
constructor(options = {}) {
|
|
29
|
+
// Support both object and legacy positional parameters for backwards compatibility
|
|
30
|
+
if (typeof options === 'string') {
|
|
31
|
+
// Legacy positional parameters: (namespace, callId, token, fwRequestId, url, socketStore)
|
|
32
|
+
const namespace = options;
|
|
33
|
+
const callId = arguments[1];
|
|
34
|
+
const token = arguments[2];
|
|
35
|
+
const fwRequestId = arguments[3];
|
|
36
|
+
const url = arguments[4];
|
|
37
|
+
const socketStore = arguments[5];
|
|
38
|
+
|
|
39
|
+
super({ namespace, callId, token, fwRequestId });
|
|
40
|
+
|
|
41
|
+
// Handle client-side specific parameters
|
|
42
|
+
if (url) {
|
|
43
|
+
this.baseUrl = url;
|
|
44
|
+
this._initializeEnvironment();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (socketStore) {
|
|
48
|
+
this.socketStore = socketStore;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
// New object-based parameters
|
|
52
|
+
const { namespace, callId, token, fwRequestId, url, socketStore } = options;
|
|
53
|
+
|
|
54
|
+
super({ namespace, callId, token, fwRequestId });
|
|
55
|
+
|
|
56
|
+
// Handle client-side specific parameters
|
|
57
|
+
if (url) {
|
|
58
|
+
this.baseUrl = url;
|
|
59
|
+
this._initializeEnvironment();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (socketStore) {
|
|
63
|
+
this.socketStore = socketStore;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Initialize all service modules
|
|
68
|
+
this.login = new LoginService(this);
|
|
69
|
+
this.objects = new ObjectsService(this);
|
|
70
|
+
this.messaging = new MessagingService(this);
|
|
71
|
+
this.video = new VideoService(this);
|
|
72
|
+
this.voice = new VoiceService(this);
|
|
73
|
+
this.ai = new AIService(this);
|
|
74
|
+
this.lookup = new LookupService(this);
|
|
75
|
+
this.layouts = new LayoutsService(this);
|
|
76
|
+
this.subscriptions = new SubscriptionsService(this);
|
|
77
|
+
this.workflows = new WorkflowsService(this);
|
|
78
|
+
this.notes = new NotesService(this);
|
|
79
|
+
this.storage = new StorageService(this);
|
|
80
|
+
this.verification = new VerificationService(this);
|
|
81
|
+
this.portals = new PortalsService(this);
|
|
82
|
+
this.sipEndpoints = new SipEndpointsService(this);
|
|
83
|
+
this.externalOAuth = new ExternalOAuthService(this);
|
|
84
|
+
this.googleCalendar = new GoogleCalendarService(this);
|
|
85
|
+
this.enroll = new EnrollService(this);
|
|
86
|
+
this.phoneNumbers = new PhoneNumbersService(this);
|
|
87
|
+
this.recordTypes = new RecordTypesService(this);
|
|
88
|
+
this.generateId = new GenerateIdService(this);
|
|
89
|
+
|
|
90
|
+
// Add additional services that might be missing
|
|
91
|
+
this._initializeAdditionalServices();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_initializeAdditionalServices() {
|
|
95
|
+
// Placeholder for additional services that might be discovered
|
|
96
|
+
// This will be populated as we find missing APIs
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Extension method for plugins (internal SDK, transport plugins, etc.)
|
|
100
|
+
use(plugin) {
|
|
101
|
+
if (typeof plugin === 'function') {
|
|
102
|
+
plugin(this);
|
|
103
|
+
} else if (plugin && typeof plugin.install === 'function') {
|
|
104
|
+
plugin.install(this);
|
|
105
|
+
} else {
|
|
106
|
+
throw new Error('Plugin must be a function or have an install method');
|
|
107
|
+
}
|
|
108
|
+
return this;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
extend(extension) {
|
|
112
|
+
if (typeof extension === 'function') {
|
|
113
|
+
// Extension is a class constructor
|
|
114
|
+
const instance = new extension(this);
|
|
115
|
+
|
|
116
|
+
// Merge extension methods/properties into this SDK
|
|
117
|
+
for (const key in instance) {
|
|
118
|
+
if (instance.hasOwnProperty(key) && typeof instance[key] !== 'undefined') {
|
|
119
|
+
this[key] = instance[key];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} else if (typeof extension === 'object') {
|
|
123
|
+
// Extension is an object with methods
|
|
124
|
+
Object.assign(this, extension);
|
|
125
|
+
} else {
|
|
126
|
+
throw new Error('Extension must be a class constructor or object');
|
|
127
|
+
}
|
|
128
|
+
return this;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Transport plugin methods
|
|
132
|
+
addTransport(transport) {
|
|
133
|
+
super.addTransport(transport);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
removeTransport(name) {
|
|
138
|
+
super.removeTransport(name);
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Backwards compatibility helper methods
|
|
143
|
+
async buildMasterAuth({ namespace, accountId, userId }) {
|
|
144
|
+
// This method should only be available in Node.js environment
|
|
145
|
+
// and will be added via internal SDK extension
|
|
146
|
+
throw new Error('buildMasterAuth is only available with the internal SDK extension. Please use: sdk.use(InternalExtension)');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Export both the class and a factory function for convenience
|
|
151
|
+
export default UnboundSDK;
|
|
152
|
+
export { UnboundSDK };
|
|
153
|
+
|
|
154
|
+
// Factory function for common usage patterns
|
|
155
|
+
export function createSDK(options = {}) {
|
|
156
|
+
return new UnboundSDK(options);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Re-export service classes for advanced usage
|
|
160
|
+
export { LoginService } from './services/login.js';
|
|
161
|
+
export { ObjectsService } from './services/objects.js';
|
|
162
|
+
export { MessagingService } from './services/messaging.js';
|
|
163
|
+
export { VideoService } from './services/video.js';
|
|
164
|
+
export { VoiceService } from './services/voice.js';
|
|
165
|
+
export { AIService } from './services/ai.js';
|
|
166
|
+
export { LookupService } from './services/lookup.js';
|
|
167
|
+
export { LayoutsService } from './services/layouts.js';
|
|
168
|
+
export { SubscriptionsService } from './services/subscriptions.js';
|
|
169
|
+
export { WorkflowsService } from './services/workflows.js';
|
|
170
|
+
export { NotesService } from './services/notes.js';
|
|
171
|
+
export { StorageService } from './services/storage.js';
|
|
172
|
+
export { VerificationService } from './services/verification.js';
|
|
173
|
+
export { PortalsService } from './services/portals.js';
|
|
174
|
+
export { SipEndpointsService } from './services/sipEndpoints.js';
|
|
175
|
+
export { ExternalOAuthService } from './services/externalOAuth.js';
|
|
176
|
+
export { GoogleCalendarService } from './services/googleCalendar.js';
|
|
177
|
+
export { EnrollService } from './services/enroll.js';
|
|
178
|
+
export { PhoneNumbersService, PhoneNumberCarrierService } from './services/phoneNumbers.js';
|
|
179
|
+
export { RecordTypesService, UserRecordTypeDefaultsService } from './services/recordTypes.js';
|
|
180
|
+
export { GenerateIdService } from './services/generateId.js';
|
|
181
|
+
export { BaseSDK } from './base.js';
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unboundcx/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=16.0.0"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"unbound",
|
|
12
|
+
"api",
|
|
13
|
+
"sdk",
|
|
14
|
+
"messaging",
|
|
15
|
+
"voice",
|
|
16
|
+
"video",
|
|
17
|
+
"ai",
|
|
18
|
+
"communication",
|
|
19
|
+
"javascript",
|
|
20
|
+
"typescript",
|
|
21
|
+
"sms",
|
|
22
|
+
"email",
|
|
23
|
+
"workflows"
|
|
24
|
+
],
|
|
25
|
+
"author": {
|
|
26
|
+
"name": "Unbound Team",
|
|
27
|
+
"email": "support@unbound.cx",
|
|
28
|
+
"url": "https://unbound.cx"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/unbound/sdk-js.git"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/unbound/sdk-js/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://docs.unbound.cx/sdk",
|
|
39
|
+
"files": [
|
|
40
|
+
"*.js",
|
|
41
|
+
"services/**/*.js",
|
|
42
|
+
"transports/**/*.js",
|
|
43
|
+
"types/**/*.d.ts",
|
|
44
|
+
"README.md",
|
|
45
|
+
"LICENSE"
|
|
46
|
+
],
|
|
47
|
+
"exports": {
|
|
48
|
+
".": {
|
|
49
|
+
"import": "./index.js",
|
|
50
|
+
"require": "./index.cjs"
|
|
51
|
+
},
|
|
52
|
+
"./base": {
|
|
53
|
+
"import": "./base.js"
|
|
54
|
+
},
|
|
55
|
+
"./services/*": {
|
|
56
|
+
"import": "./services/*.js"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "echo 'Build complete - ESM modules ready'",
|
|
61
|
+
"test": "echo 'Tests would run here'",
|
|
62
|
+
"lint": "echo 'Linting would run here'",
|
|
63
|
+
"prepublishOnly": "npm run build"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {},
|
|
66
|
+
"optionalDependencies": {
|
|
67
|
+
"mime-types": "^2.1.35"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"socket.io-client": "^4.0.0"
|
|
71
|
+
},
|
|
72
|
+
"peerDependenciesMeta": {
|
|
73
|
+
"socket.io-client": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"devDependencies": {},
|
|
78
|
+
"browserslist": [
|
|
79
|
+
"defaults",
|
|
80
|
+
"not IE 11",
|
|
81
|
+
"not IE_Mob 11",
|
|
82
|
+
"maintained node versions"
|
|
83
|
+
],
|
|
84
|
+
"publishConfig": {
|
|
85
|
+
"registry": "https://registry.npmjs.org/",
|
|
86
|
+
"access": "public"
|
|
87
|
+
}
|
|
88
|
+
}
|
package/services/ai.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
export class AIService {
|
|
2
|
+
constructor(sdk) {
|
|
3
|
+
this.sdk = sdk;
|
|
4
|
+
this.generative = new GenerativeService(sdk);
|
|
5
|
+
this.tts = new TextToSpeechService(sdk);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class GenerativeService {
|
|
10
|
+
constructor(sdk) {
|
|
11
|
+
this.sdk = sdk;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async chat({ prompt, messages, relatedId, model, temperature, subscriptionId, stream, method }) {
|
|
15
|
+
this.sdk.validateParams(
|
|
16
|
+
{ method },
|
|
17
|
+
{
|
|
18
|
+
prompt: { type: 'string', required: false },
|
|
19
|
+
messages: { type: 'array', required: false },
|
|
20
|
+
relatedId: { type: 'string', required: false },
|
|
21
|
+
model: { type: 'string', required: false },
|
|
22
|
+
temperature: { type: 'number', required: false },
|
|
23
|
+
subscriptionId: { type: 'string', required: false },
|
|
24
|
+
stream: { type: 'boolean', required: false },
|
|
25
|
+
method: { type: 'string', required: true }
|
|
26
|
+
},
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const params = {
|
|
30
|
+
body: {
|
|
31
|
+
prompt,
|
|
32
|
+
messages,
|
|
33
|
+
relatedId,
|
|
34
|
+
model,
|
|
35
|
+
temperature,
|
|
36
|
+
subscriptionId,
|
|
37
|
+
stream,
|
|
38
|
+
method,
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const result = await this.sdk._fetch('/ai/generative/chat', 'POST', params);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async playbook({ prompt, messages, relatedId, model, temperature, subscriptionId, stream, playbookId, sessionId }) {
|
|
47
|
+
this.sdk.validateParams(
|
|
48
|
+
{ playbookId },
|
|
49
|
+
{
|
|
50
|
+
prompt: { type: 'string', required: false },
|
|
51
|
+
messages: { type: 'array', required: false },
|
|
52
|
+
relatedId: { type: 'string', required: false },
|
|
53
|
+
model: { type: 'string', required: false },
|
|
54
|
+
temperature: { type: 'number', required: false },
|
|
55
|
+
subscriptionId: { type: 'string', required: false },
|
|
56
|
+
stream: { type: 'boolean', required: false },
|
|
57
|
+
playbookId: { type: 'string', required: true },
|
|
58
|
+
sessionId: { type: 'string', required: false }
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const params = {
|
|
63
|
+
body: {
|
|
64
|
+
prompt,
|
|
65
|
+
messages,
|
|
66
|
+
relatedId,
|
|
67
|
+
model,
|
|
68
|
+
temperature,
|
|
69
|
+
subscriptionId,
|
|
70
|
+
stream,
|
|
71
|
+
playbookId,
|
|
72
|
+
sessionId,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const result = await this.sdk._fetch('/ai/generative/playbook', 'POST', params);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async chatOllama({ prompt, messages, relatedId, model, temperature, subscriptionId, stream, method }) {
|
|
81
|
+
this.sdk.validateParams(
|
|
82
|
+
{ method },
|
|
83
|
+
{
|
|
84
|
+
prompt: { type: 'string', required: false },
|
|
85
|
+
messages: { type: 'array', required: false },
|
|
86
|
+
relatedId: { type: 'string', required: false },
|
|
87
|
+
model: { type: 'string', required: false },
|
|
88
|
+
temperature: { type: 'number', required: false },
|
|
89
|
+
subscriptionId: { type: 'string', required: false },
|
|
90
|
+
stream: { type: 'boolean', required: false },
|
|
91
|
+
method: { type: 'string', required: true }
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const params = {
|
|
96
|
+
body: {
|
|
97
|
+
prompt,
|
|
98
|
+
messages,
|
|
99
|
+
relatedId,
|
|
100
|
+
model,
|
|
101
|
+
temperature,
|
|
102
|
+
subscriptionId,
|
|
103
|
+
stream,
|
|
104
|
+
method,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = await this.sdk._fetch('/ai/generative/ollama', 'POST', params);
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export class TextToSpeechService {
|
|
114
|
+
constructor(sdk) {
|
|
115
|
+
this.sdk = sdk;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async create({ text, voice, languageCode, ssmlGender, audioEncoding, speakingRate, pitch, volumeGainDb, effectsProfileIds }) {
|
|
119
|
+
this.sdk.validateParams(
|
|
120
|
+
{ text },
|
|
121
|
+
{
|
|
122
|
+
text: { type: 'string', required: true },
|
|
123
|
+
voice: { type: 'string', required: false },
|
|
124
|
+
languageCode: { type: 'string', required: false },
|
|
125
|
+
ssmlGender: { type: 'string', required: false },
|
|
126
|
+
audioEncoding: { type: 'string', required: false },
|
|
127
|
+
speakingRate: { type: 'number', required: false },
|
|
128
|
+
pitch: { type: 'number', required: false },
|
|
129
|
+
volumeGainDb: { type: 'number', required: false },
|
|
130
|
+
effectsProfileIds: { type: 'array', required: false },
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const ttsData = { text };
|
|
135
|
+
if (voice) ttsData.voice = voice;
|
|
136
|
+
if (languageCode) ttsData.languageCode = languageCode;
|
|
137
|
+
if (ssmlGender) ttsData.ssmlGender = ssmlGender;
|
|
138
|
+
if (audioEncoding) ttsData.audioEncoding = audioEncoding;
|
|
139
|
+
if (speakingRate) ttsData.speakingRate = speakingRate;
|
|
140
|
+
if (pitch) ttsData.pitch = pitch;
|
|
141
|
+
if (volumeGainDb) ttsData.volumeGainDb = volumeGainDb;
|
|
142
|
+
if (effectsProfileIds) ttsData.effectsProfileIds = effectsProfileIds;
|
|
143
|
+
|
|
144
|
+
const params = {
|
|
145
|
+
body: ttsData,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const result = await this.sdk._fetch('/ai/tts', 'POST', params);
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
}
|