@digisglobal/omnivox-sdk 0.3.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.cjs +750 -0
- package/dist/index.d.cts +899 -0
- package/dist/index.d.ts +899 -0
- package/dist/index.js +711 -0
- package/package.json +39 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
// src/http/response.ts
|
|
2
|
+
var NO_BODY_STATUSES = [204, 205, 304];
|
|
3
|
+
var OmnivoxRequestError = class extends Error {
|
|
4
|
+
/** HTTP status code of the failed response. */
|
|
5
|
+
status;
|
|
6
|
+
/** Parsed error envelope, or the raw text when the body was not JSON. */
|
|
7
|
+
body;
|
|
8
|
+
constructor(status, body) {
|
|
9
|
+
super(`Omnivox request failed with status ${status}`);
|
|
10
|
+
this.name = "OmnivoxRequestError";
|
|
11
|
+
this.status = status;
|
|
12
|
+
this.body = body;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
async function parseResponse(res) {
|
|
16
|
+
const noBody = NO_BODY_STATUSES.includes(res.status);
|
|
17
|
+
const text = noBody ? null : await res.text();
|
|
18
|
+
if (!res.ok && !noBody) {
|
|
19
|
+
let body;
|
|
20
|
+
try {
|
|
21
|
+
body = text ? JSON.parse(text) : void 0;
|
|
22
|
+
} catch {
|
|
23
|
+
body = text;
|
|
24
|
+
}
|
|
25
|
+
throw new OmnivoxRequestError(res.status, body);
|
|
26
|
+
}
|
|
27
|
+
return text ? JSON.parse(text) : void 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/auth/auth-me.ts
|
|
31
|
+
function createAuthMeModule(options) {
|
|
32
|
+
const baseUrl = options.baseUrl;
|
|
33
|
+
function buildInit() {
|
|
34
|
+
return {
|
|
35
|
+
method: "GET",
|
|
36
|
+
credentials: options.getCredentials(),
|
|
37
|
+
headers: {
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
...options.getHeaders()
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
/**
|
|
45
|
+
* Get the identity context for the authenticated actor.
|
|
46
|
+
* Calls GET /api/v1/auth/me.
|
|
47
|
+
*
|
|
48
|
+
* Returns the unwrapped { subject, tenant, agent } object.
|
|
49
|
+
* Throws an OmnivoxRequestError (carrying `status`) on any non-OK response,
|
|
50
|
+
* including 401 when unauthenticated.
|
|
51
|
+
*/
|
|
52
|
+
async me() {
|
|
53
|
+
const url = `${baseUrl}/api/v1/auth/me`;
|
|
54
|
+
const res = await fetch(url, buildInit());
|
|
55
|
+
const json = await parseResponse(res);
|
|
56
|
+
return json?.data ?? null;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/_generated/client.ts
|
|
62
|
+
var getApiKeysControllerListUrl = (id) => {
|
|
63
|
+
return `/api/v1/tenants/${id}/api-keys`;
|
|
64
|
+
};
|
|
65
|
+
var getApiKeysControllerCreateUrl = (id) => {
|
|
66
|
+
return `/api/v1/tenants/${id}/api-keys`;
|
|
67
|
+
};
|
|
68
|
+
var getApiKeysControllerRevokeUrl = (id, keyId) => {
|
|
69
|
+
return `/api/v1/tenants/${id}/api-keys/${keyId}`;
|
|
70
|
+
};
|
|
71
|
+
var getContactsControllerCreateUrl = () => {
|
|
72
|
+
return `/api/v1/contacts`;
|
|
73
|
+
};
|
|
74
|
+
var getContactsControllerSearchUrl = (params) => {
|
|
75
|
+
const normalizedParams = new URLSearchParams();
|
|
76
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
77
|
+
if (value !== void 0) {
|
|
78
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
const stringifiedParams = normalizedParams.toString();
|
|
82
|
+
return stringifiedParams.length > 0 ? `/api/v1/contacts?${stringifiedParams}` : `/api/v1/contacts`;
|
|
83
|
+
};
|
|
84
|
+
var getContactsControllerGetMetadataUrl = () => {
|
|
85
|
+
return `/api/v1/contacts/metadata`;
|
|
86
|
+
};
|
|
87
|
+
var getContactsControllerGetDetailUrl = (id) => {
|
|
88
|
+
return `/api/v1/contacts/${id}`;
|
|
89
|
+
};
|
|
90
|
+
var getContactsControllerPatchUrl = (id) => {
|
|
91
|
+
return `/api/v1/contacts/${id}`;
|
|
92
|
+
};
|
|
93
|
+
var getContactsControllerAddIdentityUrl = (id) => {
|
|
94
|
+
return `/api/v1/contacts/${id}/identities`;
|
|
95
|
+
};
|
|
96
|
+
var getConversationsControllerListUrl = (params) => {
|
|
97
|
+
const normalizedParams = new URLSearchParams();
|
|
98
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
99
|
+
if (value !== void 0) {
|
|
100
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const stringifiedParams = normalizedParams.toString();
|
|
104
|
+
return stringifiedParams.length > 0 ? `/api/v1/conversations?${stringifiedParams}` : `/api/v1/conversations`;
|
|
105
|
+
};
|
|
106
|
+
var getConversationsControllerReopenOrCreateUrl = () => {
|
|
107
|
+
return `/api/v1/conversations/reopen-or-create`;
|
|
108
|
+
};
|
|
109
|
+
var getConversationsControllerUpdateStatusUrl = (id) => {
|
|
110
|
+
return `/api/v1/conversations/${id}/status`;
|
|
111
|
+
};
|
|
112
|
+
var getConversationsControllerAssignUrl = (id) => {
|
|
113
|
+
return `/api/v1/conversations/${id}/assign`;
|
|
114
|
+
};
|
|
115
|
+
var getConversationsControllerListLobbyUrl = (params) => {
|
|
116
|
+
const normalizedParams = new URLSearchParams();
|
|
117
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
118
|
+
if (value !== void 0) {
|
|
119
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
const stringifiedParams = normalizedParams.toString();
|
|
123
|
+
return stringifiedParams.length > 0 ? `/api/v1/conversations/lobby?${stringifiedParams}` : `/api/v1/conversations/lobby`;
|
|
124
|
+
};
|
|
125
|
+
var getConversationsControllerPickupLobbyEntryUrl = (entryId) => {
|
|
126
|
+
return `/api/v1/conversations/lobby/${entryId}/pickup`;
|
|
127
|
+
};
|
|
128
|
+
var getConversationsControllerFindOneUrl = (id) => {
|
|
129
|
+
return `/api/v1/conversations/${id}`;
|
|
130
|
+
};
|
|
131
|
+
var getMessagesControllerSendUrl = () => {
|
|
132
|
+
return `/api/v1/messages`;
|
|
133
|
+
};
|
|
134
|
+
var getMessagesControllerListUrl = (params) => {
|
|
135
|
+
const normalizedParams = new URLSearchParams();
|
|
136
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
137
|
+
if (value !== void 0) {
|
|
138
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
const stringifiedParams = normalizedParams.toString();
|
|
142
|
+
return stringifiedParams.length > 0 ? `/api/v1/messages?${stringifiedParams}` : `/api/v1/messages`;
|
|
143
|
+
};
|
|
144
|
+
var getMessagesControllerGetByIdUrl = (id, params) => {
|
|
145
|
+
const normalizedParams = new URLSearchParams();
|
|
146
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
147
|
+
if (value !== void 0) {
|
|
148
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const stringifiedParams = normalizedParams.toString();
|
|
152
|
+
return stringifiedParams.length > 0 ? `/api/v1/messages/${id}?${stringifiedParams}` : `/api/v1/messages/${id}`;
|
|
153
|
+
};
|
|
154
|
+
var getMessagesControllerSoftDeleteUrl = (id) => {
|
|
155
|
+
return `/api/v1/messages/${id}`;
|
|
156
|
+
};
|
|
157
|
+
var getChannelsControllerListUrl = (id) => {
|
|
158
|
+
return `/api/v1/tenants/${id}/channels`;
|
|
159
|
+
};
|
|
160
|
+
var getChannelsControllerCreateUrl = (id) => {
|
|
161
|
+
return `/api/v1/tenants/${id}/channels`;
|
|
162
|
+
};
|
|
163
|
+
var getChannelsControllerFindOneUrl = (id, channelId) => {
|
|
164
|
+
return `/api/v1/tenants/${id}/channels/${channelId}`;
|
|
165
|
+
};
|
|
166
|
+
var getChannelsControllerUpdateUrl = (id, channelId) => {
|
|
167
|
+
return `/api/v1/tenants/${id}/channels/${channelId}`;
|
|
168
|
+
};
|
|
169
|
+
var getChannelsControllerVerifyUrl = (id, channelId) => {
|
|
170
|
+
return `/api/v1/tenants/${id}/channels/${channelId}/verify`;
|
|
171
|
+
};
|
|
172
|
+
var getAgentsControllerCreateUrl = () => {
|
|
173
|
+
return `/api/v1/agents`;
|
|
174
|
+
};
|
|
175
|
+
var getAgentsControllerListUrl = (params) => {
|
|
176
|
+
const normalizedParams = new URLSearchParams();
|
|
177
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
178
|
+
if (value !== void 0) {
|
|
179
|
+
normalizedParams.append(key, value === null ? "null" : String(value));
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
const stringifiedParams = normalizedParams.toString();
|
|
183
|
+
return stringifiedParams.length > 0 ? `/api/v1/agents?${stringifiedParams}` : `/api/v1/agents`;
|
|
184
|
+
};
|
|
185
|
+
var getAgentsControllerFindOneUrl = (id) => {
|
|
186
|
+
return `/api/v1/agents/${id}`;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// src/pagination/pagination.ts
|
|
190
|
+
var MAX_PAGE_SIZE = 100;
|
|
191
|
+
function buildPageParams(opts) {
|
|
192
|
+
return {
|
|
193
|
+
page: opts.page,
|
|
194
|
+
pageSize: Math.min(opts.pageSize, MAX_PAGE_SIZE)
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function iteratePages(fetchPage, opts) {
|
|
198
|
+
const items = [];
|
|
199
|
+
const clamped = buildPageParams(opts);
|
|
200
|
+
let currentPage = clamped.page;
|
|
201
|
+
while (true) {
|
|
202
|
+
const params = { page: currentPage, pageSize: clamped.pageSize };
|
|
203
|
+
const response = await fetchPage(params);
|
|
204
|
+
items.push(...response.data);
|
|
205
|
+
if (!response.meta.hasNextPage) {
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
currentPage += 1;
|
|
209
|
+
}
|
|
210
|
+
return items;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// src/tenants/tenants.ts
|
|
214
|
+
function createTenantsModule(options) {
|
|
215
|
+
const baseUrl = options.baseUrl;
|
|
216
|
+
function buildInit(method, extraInit) {
|
|
217
|
+
return {
|
|
218
|
+
...extraInit,
|
|
219
|
+
method,
|
|
220
|
+
credentials: options.getCredentials(),
|
|
221
|
+
headers: {
|
|
222
|
+
"Content-Type": "application/json",
|
|
223
|
+
...options.getHeaders(),
|
|
224
|
+
...extraInit?.headers
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
/** Channels sub-surface scoped to a tenant. */
|
|
230
|
+
channels: {
|
|
231
|
+
/**
|
|
232
|
+
* List channels for a tenant (non-secret view).
|
|
233
|
+
* Calls GET /api/v1/tenants/:id/channels.
|
|
234
|
+
*/
|
|
235
|
+
async list(tenantId, opts = { page: 1, pageSize: 25 }) {
|
|
236
|
+
const path = getChannelsControllerListUrl(tenantId);
|
|
237
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
238
|
+
const search = new URLSearchParams({
|
|
239
|
+
page: String(page),
|
|
240
|
+
pageSize: String(pageSize)
|
|
241
|
+
});
|
|
242
|
+
const url = `${baseUrl}${path}?${search.toString()}`;
|
|
243
|
+
const res = await fetch(url, buildInit("GET"));
|
|
244
|
+
return parseResponse(res);
|
|
245
|
+
}
|
|
246
|
+
},
|
|
247
|
+
/** API-keys sub-surface scoped to a tenant. */
|
|
248
|
+
apiKeys: {
|
|
249
|
+
/**
|
|
250
|
+
* List API keys for a tenant (metadata only — never exposes secrets).
|
|
251
|
+
* Calls GET /api/v1/tenants/:id/api-keys.
|
|
252
|
+
*/
|
|
253
|
+
async list(tenantId, opts = { page: 1, pageSize: 25 }) {
|
|
254
|
+
const path = getApiKeysControllerListUrl(tenantId);
|
|
255
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
256
|
+
const search = new URLSearchParams({
|
|
257
|
+
page: String(page),
|
|
258
|
+
pageSize: String(pageSize)
|
|
259
|
+
});
|
|
260
|
+
const url = `${baseUrl}${path}?${search.toString()}`;
|
|
261
|
+
const res = await fetch(url, buildInit("GET"));
|
|
262
|
+
return parseResponse(res);
|
|
263
|
+
},
|
|
264
|
+
/**
|
|
265
|
+
* Create a new API key for a tenant. Returns the key metadata plus the
|
|
266
|
+
* raw key value (shown once — the API will never return it again).
|
|
267
|
+
* Calls POST /api/v1/tenants/:id/api-keys.
|
|
268
|
+
*/
|
|
269
|
+
async create(tenantId, input) {
|
|
270
|
+
const path = getApiKeysControllerCreateUrl(tenantId);
|
|
271
|
+
const url = `${baseUrl}${path}`;
|
|
272
|
+
const body = {
|
|
273
|
+
label: input.label,
|
|
274
|
+
scopes: input.scopes ?? ["*"]
|
|
275
|
+
};
|
|
276
|
+
const res = await fetch(
|
|
277
|
+
url,
|
|
278
|
+
buildInit("POST", { body: JSON.stringify(body) })
|
|
279
|
+
);
|
|
280
|
+
return parseResponse(res);
|
|
281
|
+
},
|
|
282
|
+
/**
|
|
283
|
+
* Revoke an existing API key immediately.
|
|
284
|
+
* Calls DELETE /api/v1/tenants/:id/api-keys/:keyId.
|
|
285
|
+
*/
|
|
286
|
+
async revoke(tenantId, keyId) {
|
|
287
|
+
const path = getApiKeysControllerRevokeUrl(tenantId, keyId);
|
|
288
|
+
const url = `${baseUrl}${path}`;
|
|
289
|
+
const res = await fetch(url, buildInit("DELETE"));
|
|
290
|
+
return parseResponse(res);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/agents/agents.ts
|
|
297
|
+
function createAgentsModule(options) {
|
|
298
|
+
const baseUrl = options.baseUrl;
|
|
299
|
+
function buildInit(method, body) {
|
|
300
|
+
return {
|
|
301
|
+
method,
|
|
302
|
+
credentials: options.getCredentials(),
|
|
303
|
+
headers: {
|
|
304
|
+
"Content-Type": "application/json",
|
|
305
|
+
...options.getHeaders()
|
|
306
|
+
},
|
|
307
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
/**
|
|
312
|
+
* Create an agent for the authenticated tenant.
|
|
313
|
+
* Calls POST /api/v1/agents.
|
|
314
|
+
*/
|
|
315
|
+
async create(input) {
|
|
316
|
+
const path = getAgentsControllerCreateUrl();
|
|
317
|
+
const url = `${baseUrl}${path}`;
|
|
318
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
319
|
+
return parseResponse(res);
|
|
320
|
+
},
|
|
321
|
+
/**
|
|
322
|
+
* List agents for the authenticated tenant (paginated, sorted deterministically).
|
|
323
|
+
* pageSize is clamped to 100 per the API contract.
|
|
324
|
+
* Calls GET /api/v1/agents.
|
|
325
|
+
*/
|
|
326
|
+
async list(opts = { page: 1, pageSize: 25 }) {
|
|
327
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
328
|
+
const path = getAgentsControllerListUrl({ page, pageSize });
|
|
329
|
+
const url = `${baseUrl}${path}`;
|
|
330
|
+
const res = await fetch(url, buildInit("GET"));
|
|
331
|
+
return parseResponse(res);
|
|
332
|
+
},
|
|
333
|
+
/**
|
|
334
|
+
* Get an agent by ID.
|
|
335
|
+
* Calls GET /api/v1/agents/:id.
|
|
336
|
+
*/
|
|
337
|
+
async get(id) {
|
|
338
|
+
const path = getAgentsControllerFindOneUrl(id);
|
|
339
|
+
const url = `${baseUrl}${path}`;
|
|
340
|
+
const res = await fetch(url, buildInit("GET"));
|
|
341
|
+
return parseResponse(res);
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/channels/channels.ts
|
|
347
|
+
function createChannelsModule(options) {
|
|
348
|
+
const baseUrl = options.baseUrl;
|
|
349
|
+
function buildInit(method, body) {
|
|
350
|
+
return {
|
|
351
|
+
method,
|
|
352
|
+
credentials: options.getCredentials(),
|
|
353
|
+
headers: {
|
|
354
|
+
"Content-Type": "application/json",
|
|
355
|
+
...options.getHeaders()
|
|
356
|
+
},
|
|
357
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
/**
|
|
362
|
+
* Create a channel. For WhatsApp the secret material lives on the linked
|
|
363
|
+
* WABA (no inline secret); for Email the `{ config, secret }` envelope is
|
|
364
|
+
* sent verbatim — secret goes to the SecretsProvider and is never echoed.
|
|
365
|
+
* Calls POST /api/v1/tenants/:id/channels.
|
|
366
|
+
*/
|
|
367
|
+
async create(tenantId, body) {
|
|
368
|
+
const path = getChannelsControllerCreateUrl(tenantId);
|
|
369
|
+
const url = `${baseUrl}${path}`;
|
|
370
|
+
const res = await fetch(url, buildInit("POST", body));
|
|
371
|
+
return parseResponse(res);
|
|
372
|
+
},
|
|
373
|
+
/**
|
|
374
|
+
* Get a single channel by id (config + name/status/isDefault/type +
|
|
375
|
+
* webhookUrl for WhatsApp; no secrets).
|
|
376
|
+
* Calls GET /api/v1/tenants/:id/channels/:channelId.
|
|
377
|
+
*/
|
|
378
|
+
async get(tenantId, channelId) {
|
|
379
|
+
const path = getChannelsControllerFindOneUrl(tenantId, channelId);
|
|
380
|
+
const url = `${baseUrl}${path}`;
|
|
381
|
+
const res = await fetch(url, buildInit("GET"));
|
|
382
|
+
return parseResponse(res);
|
|
383
|
+
},
|
|
384
|
+
/**
|
|
385
|
+
* Update a channel (name/status/isDefault/config; Email may rotate secret).
|
|
386
|
+
* Calls PATCH /api/v1/tenants/:id/channels/:channelId.
|
|
387
|
+
*/
|
|
388
|
+
async update(tenantId, channelId, body) {
|
|
389
|
+
const path = getChannelsControllerUpdateUrl(tenantId, channelId);
|
|
390
|
+
const url = `${baseUrl}${path}`;
|
|
391
|
+
const res = await fetch(url, buildInit("PATCH", body));
|
|
392
|
+
return parseResponse(res);
|
|
393
|
+
},
|
|
394
|
+
/**
|
|
395
|
+
* Verify a channel through its adapter; on success sets lastVerifiedAt.
|
|
396
|
+
* Calls POST /api/v1/tenants/:id/channels/:channelId/verify.
|
|
397
|
+
*/
|
|
398
|
+
async verify(tenantId, channelId) {
|
|
399
|
+
const path = getChannelsControllerVerifyUrl(tenantId, channelId);
|
|
400
|
+
const url = `${baseUrl}${path}`;
|
|
401
|
+
const res = await fetch(url, buildInit("POST"));
|
|
402
|
+
await parseResponse(res);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// src/contacts/contacts.ts
|
|
408
|
+
function createContactsModule(options) {
|
|
409
|
+
const baseUrl = options.baseUrl;
|
|
410
|
+
function buildInit(method, body) {
|
|
411
|
+
return {
|
|
412
|
+
method,
|
|
413
|
+
credentials: options.getCredentials(),
|
|
414
|
+
headers: {
|
|
415
|
+
"Content-Type": "application/json",
|
|
416
|
+
...options.getHeaders()
|
|
417
|
+
},
|
|
418
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
return {
|
|
422
|
+
/**
|
|
423
|
+
* Create a contact with channel identity/identities.
|
|
424
|
+
* Calls POST /api/v1/contacts.
|
|
425
|
+
*/
|
|
426
|
+
async create(input) {
|
|
427
|
+
const path = getContactsControllerCreateUrl();
|
|
428
|
+
const url = `${baseUrl}${path}`;
|
|
429
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
430
|
+
return parseResponse(res);
|
|
431
|
+
},
|
|
432
|
+
/**
|
|
433
|
+
* Search contacts by display name or raw identifier.
|
|
434
|
+
* pageSize is clamped to 100 per the API contract.
|
|
435
|
+
* Calls GET /api/v1/contacts.
|
|
436
|
+
*/
|
|
437
|
+
async search(opts) {
|
|
438
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
439
|
+
const params = {
|
|
440
|
+
page,
|
|
441
|
+
pageSize,
|
|
442
|
+
...opts.q !== void 0 ? { q: opts.q } : {}
|
|
443
|
+
};
|
|
444
|
+
const path = getContactsControllerSearchUrl(params);
|
|
445
|
+
const url = `${baseUrl}${path}`;
|
|
446
|
+
const res = await fetch(url, buildInit("GET"));
|
|
447
|
+
return parseResponse(res);
|
|
448
|
+
},
|
|
449
|
+
/**
|
|
450
|
+
* Get contact detail with identities, tags, field values.
|
|
451
|
+
* Calls GET /api/v1/contacts/:id.
|
|
452
|
+
*/
|
|
453
|
+
async detail(id) {
|
|
454
|
+
const path = getContactsControllerGetDetailUrl(id);
|
|
455
|
+
const url = `${baseUrl}${path}`;
|
|
456
|
+
const res = await fetch(url, buildInit("GET"));
|
|
457
|
+
return parseResponse(res);
|
|
458
|
+
},
|
|
459
|
+
/**
|
|
460
|
+
* Return the tenant's tag catalog and custom-field definitions.
|
|
461
|
+
* Calls GET /api/v1/contacts/metadata.
|
|
462
|
+
*/
|
|
463
|
+
async metadata() {
|
|
464
|
+
const path = getContactsControllerGetMetadataUrl();
|
|
465
|
+
const url = `${baseUrl}${path}`;
|
|
466
|
+
const res = await fetch(url, buildInit("GET"));
|
|
467
|
+
return parseResponse(res);
|
|
468
|
+
},
|
|
469
|
+
/**
|
|
470
|
+
* Partially update a contact.
|
|
471
|
+
* Calls PATCH /api/v1/contacts/:id.
|
|
472
|
+
*/
|
|
473
|
+
async patch(id, input) {
|
|
474
|
+
const path = getContactsControllerPatchUrl(id);
|
|
475
|
+
const url = `${baseUrl}${path}`;
|
|
476
|
+
const res = await fetch(url, buildInit("PATCH", input));
|
|
477
|
+
return parseResponse(res);
|
|
478
|
+
},
|
|
479
|
+
/**
|
|
480
|
+
* Add a channel identity to an existing contact.
|
|
481
|
+
* Calls POST /api/v1/contacts/:id/identities.
|
|
482
|
+
*/
|
|
483
|
+
async addIdentity(id, input) {
|
|
484
|
+
const path = getContactsControllerAddIdentityUrl(id);
|
|
485
|
+
const url = `${baseUrl}${path}`;
|
|
486
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
487
|
+
return parseResponse(res);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// src/conversations/conversations.ts
|
|
493
|
+
function createConversationsModule(options) {
|
|
494
|
+
const baseUrl = options.baseUrl;
|
|
495
|
+
function buildInit(method, body) {
|
|
496
|
+
return {
|
|
497
|
+
method,
|
|
498
|
+
credentials: options.getCredentials(),
|
|
499
|
+
headers: {
|
|
500
|
+
"Content-Type": "application/json",
|
|
501
|
+
...options.getHeaders()
|
|
502
|
+
},
|
|
503
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
/**
|
|
508
|
+
* Idempotent reopen-or-create for a contact identity.
|
|
509
|
+
* Returns the existing non-CLOSED conversation (200) or creates a new OPEN one (201).
|
|
510
|
+
* Calls POST /api/v1/conversations/reopen-or-create.
|
|
511
|
+
*/
|
|
512
|
+
async reopenOrCreate(input) {
|
|
513
|
+
const path = getConversationsControllerReopenOrCreateUrl();
|
|
514
|
+
const url = `${baseUrl}${path}`;
|
|
515
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
516
|
+
return parseResponse(res);
|
|
517
|
+
},
|
|
518
|
+
/**
|
|
519
|
+
* List conversations with optional filters (paginated, sorted deterministically).
|
|
520
|
+
* pageSize is clamped to 100 per the API contract.
|
|
521
|
+
* Calls GET /api/v1/conversations.
|
|
522
|
+
*/
|
|
523
|
+
async list(opts = { page: 1, pageSize: 25 }) {
|
|
524
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
525
|
+
const params = { page, pageSize };
|
|
526
|
+
if (opts.contactId !== void 0) params["contactId"] = opts.contactId;
|
|
527
|
+
if (opts.assignedAgentId !== void 0)
|
|
528
|
+
params["assignedAgentId"] = opts.assignedAgentId;
|
|
529
|
+
if (opts.channel !== void 0) params["channel"] = opts.channel;
|
|
530
|
+
if (opts.status !== void 0) params["status"] = opts.status;
|
|
531
|
+
const path = getConversationsControllerListUrl(params);
|
|
532
|
+
const url = `${baseUrl}${path}`;
|
|
533
|
+
const res = await fetch(url, buildInit("GET"));
|
|
534
|
+
return parseResponse(res);
|
|
535
|
+
},
|
|
536
|
+
/**
|
|
537
|
+
* Update a conversation status via the state machine.
|
|
538
|
+
* Calls PATCH /api/v1/conversations/:id/status.
|
|
539
|
+
*/
|
|
540
|
+
async updateStatus(id, input) {
|
|
541
|
+
const path = getConversationsControllerUpdateStatusUrl(id);
|
|
542
|
+
const url = `${baseUrl}${path}`;
|
|
543
|
+
const res = await fetch(url, buildInit("PATCH", input));
|
|
544
|
+
return parseResponse(res);
|
|
545
|
+
},
|
|
546
|
+
/**
|
|
547
|
+
* Assign a conversation to an agent.
|
|
548
|
+
* Calls PATCH /api/v1/conversations/:id/assign.
|
|
549
|
+
*/
|
|
550
|
+
async assign(id, input) {
|
|
551
|
+
const path = getConversationsControllerAssignUrl(id);
|
|
552
|
+
const url = `${baseUrl}${path}`;
|
|
553
|
+
const res = await fetch(url, buildInit("PATCH", input));
|
|
554
|
+
return parseResponse(res);
|
|
555
|
+
},
|
|
556
|
+
/**
|
|
557
|
+
* List lobby entries awaiting pickup (paginated, sorted by receivedAt DESC).
|
|
558
|
+
* pageSize is clamped to 100 per the API contract.
|
|
559
|
+
* Calls GET /api/v1/conversations/lobby.
|
|
560
|
+
*/
|
|
561
|
+
async listLobby(opts = { page: 1, pageSize: 25 }) {
|
|
562
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
563
|
+
const path = getConversationsControllerListLobbyUrl({ page, pageSize });
|
|
564
|
+
const url = `${baseUrl}${path}`;
|
|
565
|
+
const res = await fetch(url, buildInit("GET"));
|
|
566
|
+
return parseResponse(res);
|
|
567
|
+
},
|
|
568
|
+
/**
|
|
569
|
+
* Get a single conversation by ID.
|
|
570
|
+
* Calls GET /api/v1/conversations/:id.
|
|
571
|
+
*/
|
|
572
|
+
async get(id) {
|
|
573
|
+
const path = getConversationsControllerFindOneUrl(id);
|
|
574
|
+
const url = `${baseUrl}${path}`;
|
|
575
|
+
const res = await fetch(url, buildInit("GET"));
|
|
576
|
+
return parseResponse(res);
|
|
577
|
+
},
|
|
578
|
+
/**
|
|
579
|
+
* Pick up a lobby entry (atomic 4-step transaction).
|
|
580
|
+
* Returns the resulting conversation.
|
|
581
|
+
* Calls POST /api/v1/conversations/lobby/:entryId/pickup.
|
|
582
|
+
*/
|
|
583
|
+
async pickup(entryId, input) {
|
|
584
|
+
const path = getConversationsControllerPickupLobbyEntryUrl(entryId);
|
|
585
|
+
const url = `${baseUrl}${path}`;
|
|
586
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
587
|
+
return parseResponse(res);
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// src/messages/messages.ts
|
|
593
|
+
function createMessagesModule(options) {
|
|
594
|
+
const baseUrl = options.baseUrl;
|
|
595
|
+
function buildInit(method, body) {
|
|
596
|
+
return {
|
|
597
|
+
method,
|
|
598
|
+
credentials: options.getCredentials(),
|
|
599
|
+
headers: {
|
|
600
|
+
"Content-Type": "application/json",
|
|
601
|
+
...options.getHeaders()
|
|
602
|
+
},
|
|
603
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
return {
|
|
607
|
+
/**
|
|
608
|
+
* Send a message in a conversation.
|
|
609
|
+
* Calls POST /api/v1/messages.
|
|
610
|
+
*/
|
|
611
|
+
async send(input) {
|
|
612
|
+
const path = getMessagesControllerSendUrl();
|
|
613
|
+
const url = `${baseUrl}${path}`;
|
|
614
|
+
const res = await fetch(url, buildInit("POST", input));
|
|
615
|
+
return parseResponse(res);
|
|
616
|
+
},
|
|
617
|
+
/**
|
|
618
|
+
* List messages in a conversation (newest first, paginated).
|
|
619
|
+
* pageSize is clamped to 100 per the API contract.
|
|
620
|
+
* Calls GET /api/v1/messages.
|
|
621
|
+
*/
|
|
622
|
+
async list(opts) {
|
|
623
|
+
const { page, pageSize } = buildPageParams(opts);
|
|
624
|
+
const params = {
|
|
625
|
+
conversationId: opts.conversationId,
|
|
626
|
+
page,
|
|
627
|
+
pageSize,
|
|
628
|
+
...opts.includeDeleted !== void 0 ? { includeDeleted: opts.includeDeleted } : {}
|
|
629
|
+
};
|
|
630
|
+
const path = getMessagesControllerListUrl(params);
|
|
631
|
+
const url = `${baseUrl}${path}`;
|
|
632
|
+
const res = await fetch(url, buildInit("GET"));
|
|
633
|
+
return parseResponse(res);
|
|
634
|
+
},
|
|
635
|
+
/**
|
|
636
|
+
* Fetch a single message by ID.
|
|
637
|
+
* Calls GET /api/v1/messages/:id.
|
|
638
|
+
*/
|
|
639
|
+
async get(id) {
|
|
640
|
+
const path = getMessagesControllerGetByIdUrl(id);
|
|
641
|
+
const url = `${baseUrl}${path}`;
|
|
642
|
+
const res = await fetch(url, buildInit("GET"));
|
|
643
|
+
return parseResponse(res);
|
|
644
|
+
},
|
|
645
|
+
/**
|
|
646
|
+
* Soft-delete a message (sets deletedAt; row preserved).
|
|
647
|
+
* Calls DELETE /api/v1/messages/:id.
|
|
648
|
+
*/
|
|
649
|
+
async delete(id) {
|
|
650
|
+
const path = getMessagesControllerSoftDeleteUrl(id);
|
|
651
|
+
const url = `${baseUrl}${path}`;
|
|
652
|
+
const res = await fetch(url, buildInit("DELETE"));
|
|
653
|
+
await parseResponse(res);
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
// src/client.ts
|
|
659
|
+
function createOmnivoxClient(options) {
|
|
660
|
+
const moduleOptions = {
|
|
661
|
+
baseUrl: options.baseUrl,
|
|
662
|
+
getHeaders: () => options.tokenProvider.getHeaders(),
|
|
663
|
+
getCredentials: () => options.tokenProvider.getCredentials()
|
|
664
|
+
};
|
|
665
|
+
return {
|
|
666
|
+
auth: createAuthMeModule(moduleOptions),
|
|
667
|
+
tenants: createTenantsModule(moduleOptions),
|
|
668
|
+
agents: createAgentsModule(moduleOptions),
|
|
669
|
+
channels: createChannelsModule(moduleOptions),
|
|
670
|
+
contacts: createContactsModule(moduleOptions),
|
|
671
|
+
conversations: createConversationsModule(moduleOptions),
|
|
672
|
+
messages: createMessagesModule(moduleOptions)
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// src/auth/token-provider.ts
|
|
677
|
+
function createApiKeyTokenProvider(apiKey) {
|
|
678
|
+
return {
|
|
679
|
+
getHeaders() {
|
|
680
|
+
return { "x-api-key": apiKey };
|
|
681
|
+
},
|
|
682
|
+
getCredentials() {
|
|
683
|
+
return "omit";
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
function createSessionTokenProvider() {
|
|
688
|
+
return {
|
|
689
|
+
getHeaders() {
|
|
690
|
+
return {};
|
|
691
|
+
},
|
|
692
|
+
getCredentials() {
|
|
693
|
+
return "include";
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
export {
|
|
698
|
+
OmnivoxRequestError,
|
|
699
|
+
buildPageParams,
|
|
700
|
+
createAgentsModule,
|
|
701
|
+
createApiKeyTokenProvider,
|
|
702
|
+
createAuthMeModule,
|
|
703
|
+
createChannelsModule,
|
|
704
|
+
createContactsModule,
|
|
705
|
+
createConversationsModule,
|
|
706
|
+
createMessagesModule,
|
|
707
|
+
createOmnivoxClient,
|
|
708
|
+
createSessionTokenProvider,
|
|
709
|
+
createTenantsModule,
|
|
710
|
+
iteratePages
|
|
711
|
+
};
|