@vuevox/sdk 0.2.0 → 0.4.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/README.md +85 -25
- package/dist/client.d.ts +80 -3
- package/dist/client.js +133 -31
- package/dist/errors.d.ts +5 -1
- package/dist/errors.js +9 -1
- package/dist/generated/schema.d.ts +429 -2
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ Available scopes:
|
|
|
23
23
|
```text
|
|
24
24
|
hello:read
|
|
25
25
|
spaces:read
|
|
26
|
+
calls:read
|
|
27
|
+
leads:read
|
|
26
28
|
```
|
|
27
29
|
|
|
28
30
|
## Basic Usage
|
|
@@ -33,21 +35,51 @@ import { createVueVoxClient } from "@vuevox/sdk";
|
|
|
33
35
|
const vuevox = createVueVoxClient({
|
|
34
36
|
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
35
37
|
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
36
|
-
scope: ["hello:read", "spaces:read"],
|
|
38
|
+
scope: ["hello:read", "spaces:read", "calls:read", "leads:read"],
|
|
37
39
|
});
|
|
38
40
|
|
|
39
|
-
const hello = await vuevox.hello();
|
|
40
|
-
console.log(hello.message);
|
|
41
|
+
const hello = await vuevox.hello.get();
|
|
42
|
+
console.log(hello.data.message, hello.requestId);
|
|
41
43
|
|
|
42
|
-
const spaces = await vuevox.
|
|
43
|
-
console.log(spaces.data);
|
|
44
|
+
const spaces = await vuevox.spaces.list({ limit: 50 });
|
|
45
|
+
console.log(spaces.data.data, spaces.requestId);
|
|
46
|
+
|
|
47
|
+
const calls = await vuevox.calls.list({ limit: 50 });
|
|
48
|
+
console.log(calls.data.data, calls.requestId);
|
|
49
|
+
|
|
50
|
+
const leads = await vuevox.leads.list({ limit: 50 });
|
|
51
|
+
console.log(leads.data.data, leads.requestId);
|
|
44
52
|
```
|
|
45
53
|
|
|
46
54
|
The SDK requests and caches a short-lived access token using client credentials, then sends it as a bearer token for API calls.
|
|
47
55
|
|
|
56
|
+
## Request IDs
|
|
57
|
+
|
|
58
|
+
Every Developer API response includes an `X-Request-Id` header. SDK endpoint methods return response metadata with the response body so you can log that ID for support requests.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
const call = await vuevox.calls.get("call-id");
|
|
62
|
+
|
|
63
|
+
console.log(call.requestId);
|
|
64
|
+
console.log(call.data.data.transcript);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
For centralized logging, pass `onResponse`. The hook runs for every SDK-managed HTTP response, including the token request.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const vuevox = createVueVoxClient({
|
|
71
|
+
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
72
|
+
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
73
|
+
scope: ["calls:read"],
|
|
74
|
+
onResponse: ({ method, path, status, requestId }) => {
|
|
75
|
+
console.log({ method, path, status, requestId });
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
48
80
|
## Error Handling
|
|
49
81
|
|
|
50
|
-
API errors throw `VueVoxApiError`.
|
|
82
|
+
API errors throw `VueVoxApiError`. The SDK exposes `error.requestId`, `error.details`, `error.retryAfter`, and `error.isRateLimited`.
|
|
51
83
|
|
|
52
84
|
```ts
|
|
53
85
|
import { VueVoxApiError, createVueVoxClient } from "@vuevox/sdk";
|
|
@@ -55,14 +87,14 @@ import { VueVoxApiError, createVueVoxClient } from "@vuevox/sdk";
|
|
|
55
87
|
const vuevox = createVueVoxClient({
|
|
56
88
|
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
57
89
|
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
58
|
-
scope: ["
|
|
90
|
+
scope: ["calls:read"],
|
|
59
91
|
});
|
|
60
92
|
|
|
61
93
|
try {
|
|
62
|
-
await vuevox.
|
|
94
|
+
await vuevox.calls.list({ limit: 50 });
|
|
63
95
|
} catch (error) {
|
|
64
96
|
if (error instanceof VueVoxApiError) {
|
|
65
|
-
console.error(error.status, error.code, error.message);
|
|
97
|
+
console.error(error.status, error.code, error.message, error.requestId);
|
|
66
98
|
}
|
|
67
99
|
|
|
68
100
|
throw error;
|
|
@@ -78,6 +110,49 @@ invalid_client
|
|
|
78
110
|
invalid_scope
|
|
79
111
|
insufficient_scope
|
|
80
112
|
rate_limited
|
|
113
|
+
invalid_request
|
|
114
|
+
call_not_found
|
|
115
|
+
lead_not_found
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Pagination
|
|
119
|
+
|
|
120
|
+
List endpoints use cursor pagination.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const firstPage = await vuevox.calls.list({ limit: 50 });
|
|
124
|
+
|
|
125
|
+
if (firstPage.data.pagination.nextCursor) {
|
|
126
|
+
const secondPage = await vuevox.calls.list({
|
|
127
|
+
limit: 50,
|
|
128
|
+
cursor: firstPage.data.pagination.nextCursor,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The SDK also includes async iterable helpers:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
for await (const call of vuevox.calls.paginate({ limit: 50 })) {
|
|
137
|
+
console.log(call.id);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Pagination helpers are available for `spaces`, `calls`, and `leads`.
|
|
142
|
+
|
|
143
|
+
## Retries
|
|
144
|
+
|
|
145
|
+
Configure retry/backoff for safe SDK-managed requests. The SDK retries token requests and GET endpoints for `429`, `500`, `502`, `503`, and `504`, and respects `Retry-After` when present.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
const vuevox = createVueVoxClient({
|
|
149
|
+
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
150
|
+
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
151
|
+
scope: ["calls:read"],
|
|
152
|
+
retries: 2,
|
|
153
|
+
retryBaseDelayMs: 250,
|
|
154
|
+
retryMaxDelayMs: 2000,
|
|
155
|
+
});
|
|
81
156
|
```
|
|
82
157
|
|
|
83
158
|
## Token Behavior
|
|
@@ -104,7 +179,7 @@ const vuevox = createVueVoxClient({
|
|
|
104
179
|
baseUrl: "https://api.vuevox.com",
|
|
105
180
|
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
106
181
|
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
107
|
-
scope: ["
|
|
182
|
+
scope: ["calls:read"],
|
|
108
183
|
});
|
|
109
184
|
```
|
|
110
185
|
|
|
@@ -119,18 +194,3 @@ const { data, error } = await vuevox.raw.GET("/v1/hello", {
|
|
|
119
194
|
},
|
|
120
195
|
});
|
|
121
196
|
```
|
|
122
|
-
|
|
123
|
-
## Pagination
|
|
124
|
-
|
|
125
|
-
List endpoints use cursor pagination.
|
|
126
|
-
|
|
127
|
-
```ts
|
|
128
|
-
const firstPage = await vuevox.listSpaces({ limit: 50 });
|
|
129
|
-
|
|
130
|
-
if (firstPage.pagination.nextCursor) {
|
|
131
|
-
const secondPage = await vuevox.listSpaces({
|
|
132
|
-
limit: 50,
|
|
133
|
-
cursor: firstPage.pagination.nextCursor,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
```
|
package/dist/client.d.ts
CHANGED
|
@@ -1,21 +1,98 @@
|
|
|
1
1
|
import type { components, paths } from "./generated/schema.js";
|
|
2
2
|
type HelloResponse = components["schemas"]["HelloResponse"];
|
|
3
3
|
type SpacesListResponse = components["schemas"]["SpacesListResponse"];
|
|
4
|
+
type CallsListResponse = components["schemas"]["CallsListResponse"];
|
|
5
|
+
type CallDetailResponse = components["schemas"]["CallDetailResponse"];
|
|
6
|
+
type LeadsListResponse = components["schemas"]["LeadsListResponse"];
|
|
7
|
+
type LeadDetailResponse = components["schemas"]["LeadDetailResponse"];
|
|
8
|
+
type Space = components["schemas"]["Space"];
|
|
9
|
+
type CallSummary = components["schemas"]["CallSummary"];
|
|
10
|
+
type Lead = components["schemas"]["Lead"];
|
|
4
11
|
export interface ListSpacesOptions {
|
|
5
12
|
limit?: number;
|
|
6
13
|
cursor?: string;
|
|
7
14
|
}
|
|
15
|
+
export interface ListCallsOptions extends ListSpacesOptions {
|
|
16
|
+
spaceId?: string;
|
|
17
|
+
leadId?: string;
|
|
18
|
+
agentId?: string;
|
|
19
|
+
createdAfter?: string;
|
|
20
|
+
createdBefore?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ListLeadsOptions extends ListSpacesOptions {
|
|
23
|
+
spaceId?: string;
|
|
24
|
+
createdAfter?: string;
|
|
25
|
+
createdBefore?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface VueVoxResponseMetadata {
|
|
28
|
+
requestId?: string;
|
|
29
|
+
status: number;
|
|
30
|
+
}
|
|
31
|
+
export interface VueVoxApiResponse<T> extends VueVoxResponseMetadata {
|
|
32
|
+
data: T;
|
|
33
|
+
}
|
|
34
|
+
export interface VueVoxResponseEvent extends VueVoxResponseMetadata {
|
|
35
|
+
method: string;
|
|
36
|
+
path: string;
|
|
37
|
+
retryAfter?: number;
|
|
38
|
+
}
|
|
8
39
|
export interface VueVoxClientOptions {
|
|
9
40
|
baseUrl?: string;
|
|
10
41
|
clientId: string;
|
|
11
42
|
clientSecret: string;
|
|
12
43
|
scope?: string | string[];
|
|
13
44
|
fetch?: typeof fetch;
|
|
45
|
+
onResponse?: (event: VueVoxResponseEvent) => void;
|
|
46
|
+
retries?: number;
|
|
47
|
+
retryBaseDelayMs?: number;
|
|
48
|
+
retryMaxDelayMs?: number;
|
|
14
49
|
}
|
|
15
50
|
export declare function createVueVoxClient(options: VueVoxClientOptions): {
|
|
16
51
|
getAccessToken: () => Promise<string>;
|
|
17
|
-
hello:
|
|
18
|
-
|
|
52
|
+
hello: {
|
|
53
|
+
get: () => Promise<VueVoxApiResponse<HelloResponse>>;
|
|
54
|
+
};
|
|
55
|
+
spaces: {
|
|
56
|
+
list: (listOptions?: ListSpacesOptions) => Promise<VueVoxApiResponse<SpacesListResponse>>;
|
|
57
|
+
paginate: (listOptions?: ListSpacesOptions) => AsyncGenerator<{
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
description: string | null;
|
|
61
|
+
createdAt: string;
|
|
62
|
+
updatedAt: string;
|
|
63
|
+
}, any, any>;
|
|
64
|
+
};
|
|
65
|
+
calls: {
|
|
66
|
+
list: (listOptions?: ListCallsOptions) => Promise<VueVoxApiResponse<CallsListResponse>>;
|
|
67
|
+
get: (callId: string) => Promise<VueVoxApiResponse<CallDetailResponse>>;
|
|
68
|
+
paginate: (listOptions?: ListCallsOptions) => AsyncGenerator<{
|
|
69
|
+
id: string;
|
|
70
|
+
space: components["schemas"]["ResourceSummary"];
|
|
71
|
+
lead: components["schemas"]["LeadSummary"];
|
|
72
|
+
agent: components["schemas"]["ResourceSummary"];
|
|
73
|
+
duration: number;
|
|
74
|
+
score: number | null;
|
|
75
|
+
sentiment: string | null;
|
|
76
|
+
analysisStatus: string;
|
|
77
|
+
queueStatus: string | null;
|
|
78
|
+
createdAt: string;
|
|
79
|
+
updatedAt: string;
|
|
80
|
+
}, any, any>;
|
|
81
|
+
};
|
|
82
|
+
leads: {
|
|
83
|
+
list: (listOptions?: ListLeadsOptions) => Promise<VueVoxApiResponse<LeadsListResponse>>;
|
|
84
|
+
get: (leadId: string) => Promise<VueVoxApiResponse<LeadDetailResponse>>;
|
|
85
|
+
paginate: (listOptions?: ListLeadsOptions) => AsyncGenerator<{
|
|
86
|
+
id: string;
|
|
87
|
+
firstName: string;
|
|
88
|
+
lastName: string;
|
|
89
|
+
email: string | null;
|
|
90
|
+
phone: string | null;
|
|
91
|
+
space: components["schemas"]["ResourceSummary"];
|
|
92
|
+
createdAt: string;
|
|
93
|
+
updatedAt: string;
|
|
94
|
+
}, any, any>;
|
|
95
|
+
};
|
|
19
96
|
raw: import("openapi-fetch").Client<paths, `${string}/${string}`>;
|
|
20
97
|
};
|
|
21
|
-
export {};
|
|
98
|
+
export type { CallDetailResponse, CallsListResponse, CallSummary, HelloResponse, Lead, LeadDetailResponse, LeadsListResponse, Space, SpacesListResponse };
|
package/dist/client.js
CHANGED
|
@@ -4,12 +4,15 @@ export function createVueVoxClient(options) {
|
|
|
4
4
|
const baseUrl = trimTrailingSlash(options.baseUrl ?? "https://api.vuevox.com");
|
|
5
5
|
const fetchFn = options.fetch ?? fetch;
|
|
6
6
|
const raw = createClient({ baseUrl, fetch: fetchFn });
|
|
7
|
+
const retries = options.retries ?? 0;
|
|
8
|
+
const retryBaseDelayMs = options.retryBaseDelayMs ?? 250;
|
|
9
|
+
const retryMaxDelayMs = options.retryMaxDelayMs ?? 2_000;
|
|
7
10
|
let cachedToken = null;
|
|
8
11
|
async function getAccessToken() {
|
|
9
12
|
if (cachedToken && Date.now() < cachedToken.expiresAt - 30_000) {
|
|
10
13
|
return cachedToken.accessToken;
|
|
11
14
|
}
|
|
12
|
-
const
|
|
15
|
+
const result = await requestJson("POST", "/oauth/token", {
|
|
13
16
|
method: "POST",
|
|
14
17
|
headers: {
|
|
15
18
|
"Content-Type": "application/json",
|
|
@@ -21,51 +24,88 @@ export function createVueVoxClient(options) {
|
|
|
21
24
|
scope: formatScope(options.scope),
|
|
22
25
|
}),
|
|
23
26
|
});
|
|
24
|
-
const body =
|
|
25
|
-
if (!response.ok) {
|
|
26
|
-
const error = isErrorResponse(body) ? body.error : null;
|
|
27
|
-
throw new VueVoxApiError(response.status, error?.code ?? "token_request_failed", error?.message ?? "VueVox token request failed.", isErrorResponse(body) ? body : undefined);
|
|
28
|
-
}
|
|
29
|
-
if (!isTokenResponse(body)) {
|
|
30
|
-
throw new VueVoxApiError(response.status, "invalid_token_response", "VueVox returned an invalid token response.");
|
|
31
|
-
}
|
|
27
|
+
const body = result.data;
|
|
32
28
|
cachedToken = {
|
|
33
29
|
accessToken: body.access_token,
|
|
34
30
|
expiresAt: Date.now() + body.expires_in * 1000,
|
|
35
31
|
};
|
|
36
32
|
return cachedToken.accessToken;
|
|
37
33
|
}
|
|
38
|
-
async function
|
|
34
|
+
async function getHello() {
|
|
35
|
+
return apiGet("/v1/hello");
|
|
36
|
+
}
|
|
37
|
+
async function listSpaces(listOptions = {}) {
|
|
38
|
+
return apiGet("/v1/spaces", listOptions);
|
|
39
|
+
}
|
|
40
|
+
async function listCalls(listOptions = {}) {
|
|
41
|
+
return apiGet("/v1/calls", listOptions);
|
|
42
|
+
}
|
|
43
|
+
async function getCall(callId) {
|
|
44
|
+
return apiGet(`/v1/calls/${encodeURIComponent(callId)}`);
|
|
45
|
+
}
|
|
46
|
+
async function listLeads(listOptions = {}) {
|
|
47
|
+
return apiGet("/v1/leads", listOptions);
|
|
48
|
+
}
|
|
49
|
+
async function getLead(leadId) {
|
|
50
|
+
return apiGet(`/v1/leads/${encodeURIComponent(leadId)}`);
|
|
51
|
+
}
|
|
52
|
+
async function apiGet(path, query) {
|
|
39
53
|
const accessToken = await getAccessToken();
|
|
40
|
-
const
|
|
54
|
+
const result = await requestJson("GET", path, {
|
|
55
|
+
method: "GET",
|
|
41
56
|
headers: {
|
|
42
57
|
Authorization: `Bearer ${accessToken}`,
|
|
43
58
|
},
|
|
59
|
+
query,
|
|
44
60
|
});
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
return withMetadata(result.data, result.response, result.requestId);
|
|
62
|
+
}
|
|
63
|
+
async function requestJson(method, path, init) {
|
|
64
|
+
for (let attempt = 0;; attempt++) {
|
|
65
|
+
const response = await fetchFn(buildUrl(baseUrl, path, init.query), init);
|
|
66
|
+
const body = await parseJson(response);
|
|
67
|
+
const requestId = getRequestId(response, body);
|
|
68
|
+
const retryAfter = retryAfterSeconds(response);
|
|
69
|
+
notifyResponse(options, method, path, response, requestId, retryAfter);
|
|
70
|
+
if (response.ok) {
|
|
71
|
+
if (body === null || isErrorResponse(body)) {
|
|
72
|
+
throw new VueVoxApiError(response.status, "invalid_response", "VueVox returned an invalid response.", undefined, requestId, retryAfter);
|
|
73
|
+
}
|
|
74
|
+
return { data: body, requestId, response };
|
|
75
|
+
}
|
|
76
|
+
if (attempt < retries && shouldRetry(response.status)) {
|
|
77
|
+
await sleep(retryDelayMs(attempt, retryAfter));
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const error = isErrorResponse(body) ? body.error : null;
|
|
81
|
+
throw new VueVoxApiError(response.status, error?.code ?? "api_request_failed", error?.message ?? "VueVox API request failed.", isErrorResponse(body) ? body : undefined, requestId, retryAfter);
|
|
47
82
|
}
|
|
48
|
-
return data;
|
|
49
83
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
params: {
|
|
54
|
-
query: options,
|
|
55
|
-
},
|
|
56
|
-
headers: {
|
|
57
|
-
Authorization: `Bearer ${accessToken}`,
|
|
58
|
-
},
|
|
59
|
-
});
|
|
60
|
-
if (error) {
|
|
61
|
-
throw new VueVoxApiError(response.status, error.error.code, error.error.message, error);
|
|
84
|
+
function retryDelayMs(attempt, retryAfter) {
|
|
85
|
+
if (retryAfter !== undefined) {
|
|
86
|
+
return retryAfter * 1000;
|
|
62
87
|
}
|
|
63
|
-
return
|
|
88
|
+
return Math.min(retryBaseDelayMs * 2 ** attempt, retryMaxDelayMs);
|
|
64
89
|
}
|
|
65
90
|
return {
|
|
66
91
|
getAccessToken,
|
|
67
|
-
hello
|
|
68
|
-
|
|
92
|
+
hello: {
|
|
93
|
+
get: getHello,
|
|
94
|
+
},
|
|
95
|
+
spaces: {
|
|
96
|
+
list: listSpaces,
|
|
97
|
+
paginate: (listOptions = {}) => paginate(listSpaces, listOptions),
|
|
98
|
+
},
|
|
99
|
+
calls: {
|
|
100
|
+
list: listCalls,
|
|
101
|
+
get: getCall,
|
|
102
|
+
paginate: (listOptions = {}) => paginate(listCalls, listOptions),
|
|
103
|
+
},
|
|
104
|
+
leads: {
|
|
105
|
+
list: listLeads,
|
|
106
|
+
get: getLead,
|
|
107
|
+
paginate: (listOptions = {}) => paginate(listLeads, listOptions),
|
|
108
|
+
},
|
|
69
109
|
raw,
|
|
70
110
|
};
|
|
71
111
|
}
|
|
@@ -78,6 +118,15 @@ function formatScope(scope) {
|
|
|
78
118
|
function trimTrailingSlash(value) {
|
|
79
119
|
return value.replace(/\/+$/, "");
|
|
80
120
|
}
|
|
121
|
+
function buildUrl(baseUrl, path, query) {
|
|
122
|
+
const url = new URL(`${baseUrl}${path}`);
|
|
123
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
124
|
+
if ((typeof value === "string" || typeof value === "number") && value !== "") {
|
|
125
|
+
url.searchParams.set(key, String(value));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return url.toString();
|
|
129
|
+
}
|
|
81
130
|
async function parseJson(response) {
|
|
82
131
|
try {
|
|
83
132
|
return (await response.json());
|
|
@@ -87,8 +136,61 @@ async function parseJson(response) {
|
|
|
87
136
|
}
|
|
88
137
|
}
|
|
89
138
|
function isTokenResponse(value) {
|
|
90
|
-
return
|
|
139
|
+
return isObject(value) && "access_token" in value;
|
|
91
140
|
}
|
|
92
141
|
function isErrorResponse(value) {
|
|
93
|
-
return
|
|
142
|
+
return isObject(value) && "error" in value;
|
|
143
|
+
}
|
|
144
|
+
function getRequestId(response, body) {
|
|
145
|
+
return response.headers.get("X-Request-Id") ?? (isErrorBody(body) ? body.error.requestId : undefined);
|
|
146
|
+
}
|
|
147
|
+
function isErrorBody(value) {
|
|
148
|
+
return isObject(value) && "error" in value;
|
|
149
|
+
}
|
|
150
|
+
function isObject(value) {
|
|
151
|
+
return typeof value === "object" && value !== null;
|
|
152
|
+
}
|
|
153
|
+
function withMetadata(data, response, requestId) {
|
|
154
|
+
return {
|
|
155
|
+
data,
|
|
156
|
+
requestId,
|
|
157
|
+
status: response.status,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function notifyResponse(options, method, path, response, requestId, retryAfter) {
|
|
161
|
+
options.onResponse?.({
|
|
162
|
+
method,
|
|
163
|
+
path,
|
|
164
|
+
requestId,
|
|
165
|
+
retryAfter,
|
|
166
|
+
status: response.status,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async function* paginate(list, listOptions) {
|
|
170
|
+
let cursor = listOptions.cursor;
|
|
171
|
+
do {
|
|
172
|
+
const response = await list({ ...listOptions, cursor });
|
|
173
|
+
for (const item of response.data.data) {
|
|
174
|
+
yield item;
|
|
175
|
+
}
|
|
176
|
+
cursor = response.data.pagination.nextCursor ?? undefined;
|
|
177
|
+
} while (cursor);
|
|
178
|
+
}
|
|
179
|
+
function shouldRetry(status) {
|
|
180
|
+
return [429, 500, 502, 503, 504].includes(status);
|
|
181
|
+
}
|
|
182
|
+
function retryAfterSeconds(response) {
|
|
183
|
+
const value = response.headers.get("Retry-After");
|
|
184
|
+
if (!value) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
const seconds = Number(value);
|
|
188
|
+
if (Number.isFinite(seconds)) {
|
|
189
|
+
return Math.max(0, seconds);
|
|
190
|
+
}
|
|
191
|
+
const timestamp = Date.parse(value);
|
|
192
|
+
return Number.isNaN(timestamp) ? undefined : Math.max(0, Math.ceil((timestamp - Date.now()) / 1000));
|
|
193
|
+
}
|
|
194
|
+
function sleep(ms) {
|
|
195
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
94
196
|
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ export type VueVoxErrorResponse = components["schemas"]["ErrorResponse"];
|
|
|
3
3
|
export declare class VueVoxApiError extends Error {
|
|
4
4
|
readonly status: number;
|
|
5
5
|
readonly code: string;
|
|
6
|
+
readonly details?: Record<string, unknown>;
|
|
7
|
+
readonly isRateLimited: boolean;
|
|
8
|
+
readonly requestId?: string;
|
|
9
|
+
readonly retryAfter?: number;
|
|
6
10
|
readonly response?: VueVoxErrorResponse;
|
|
7
|
-
constructor(status: number, code: string, message: string, response?: VueVoxErrorResponse);
|
|
11
|
+
constructor(status: number, code: string, message: string, response?: VueVoxErrorResponse, requestId?: string, retryAfter?: number);
|
|
8
12
|
}
|
package/dist/errors.js
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
export class VueVoxApiError extends Error {
|
|
2
2
|
status;
|
|
3
3
|
code;
|
|
4
|
+
details;
|
|
5
|
+
isRateLimited;
|
|
6
|
+
requestId;
|
|
7
|
+
retryAfter;
|
|
4
8
|
response;
|
|
5
|
-
constructor(status, code, message, response) {
|
|
9
|
+
constructor(status, code, message, response, requestId, retryAfter) {
|
|
6
10
|
super(message);
|
|
7
11
|
this.name = "VueVoxApiError";
|
|
8
12
|
this.status = status;
|
|
9
13
|
this.code = code;
|
|
14
|
+
this.details = response?.error.details;
|
|
15
|
+
this.isRateLimited = status === 429 || code === "rate_limited";
|
|
16
|
+
this.requestId = requestId ?? response?.error.requestId;
|
|
17
|
+
this.retryAfter = retryAfter;
|
|
10
18
|
this.response = response;
|
|
11
19
|
}
|
|
12
20
|
}
|
|
@@ -64,6 +64,86 @@ export interface paths {
|
|
|
64
64
|
patch?: never;
|
|
65
65
|
trace?: never;
|
|
66
66
|
};
|
|
67
|
+
"/v1/calls": {
|
|
68
|
+
parameters: {
|
|
69
|
+
query?: never;
|
|
70
|
+
header?: never;
|
|
71
|
+
path?: never;
|
|
72
|
+
cookie?: never;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* List organization calls
|
|
76
|
+
* @description Returns calls for the API client's organization using cursor pagination. List responses do not expose audio storage paths or transcripts.
|
|
77
|
+
*/
|
|
78
|
+
get: operations["listCalls"];
|
|
79
|
+
put?: never;
|
|
80
|
+
post?: never;
|
|
81
|
+
delete?: never;
|
|
82
|
+
options?: never;
|
|
83
|
+
head?: never;
|
|
84
|
+
patch?: never;
|
|
85
|
+
trace?: never;
|
|
86
|
+
};
|
|
87
|
+
"/v1/calls/{callId}": {
|
|
88
|
+
parameters: {
|
|
89
|
+
query?: never;
|
|
90
|
+
header?: never;
|
|
91
|
+
path?: never;
|
|
92
|
+
cookie?: never;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Get a call
|
|
96
|
+
* @description Returns a single organization-scoped call with transcript and analysis details.
|
|
97
|
+
*/
|
|
98
|
+
get: operations["getCall"];
|
|
99
|
+
put?: never;
|
|
100
|
+
post?: never;
|
|
101
|
+
delete?: never;
|
|
102
|
+
options?: never;
|
|
103
|
+
head?: never;
|
|
104
|
+
patch?: never;
|
|
105
|
+
trace?: never;
|
|
106
|
+
};
|
|
107
|
+
"/v1/leads": {
|
|
108
|
+
parameters: {
|
|
109
|
+
query?: never;
|
|
110
|
+
header?: never;
|
|
111
|
+
path?: never;
|
|
112
|
+
cookie?: never;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* List organization leads
|
|
116
|
+
* @description Returns leads for the API client's organization using cursor pagination. The leads:read scope includes email and phone contact details.
|
|
117
|
+
*/
|
|
118
|
+
get: operations["listLeads"];
|
|
119
|
+
put?: never;
|
|
120
|
+
post?: never;
|
|
121
|
+
delete?: never;
|
|
122
|
+
options?: never;
|
|
123
|
+
head?: never;
|
|
124
|
+
patch?: never;
|
|
125
|
+
trace?: never;
|
|
126
|
+
};
|
|
127
|
+
"/v1/leads/{leadId}": {
|
|
128
|
+
parameters: {
|
|
129
|
+
query?: never;
|
|
130
|
+
header?: never;
|
|
131
|
+
path?: never;
|
|
132
|
+
cookie?: never;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Get a lead
|
|
136
|
+
* @description Returns a single organization-scoped lead with contact details.
|
|
137
|
+
*/
|
|
138
|
+
get: operations["getLead"];
|
|
139
|
+
put?: never;
|
|
140
|
+
post?: never;
|
|
141
|
+
delete?: never;
|
|
142
|
+
options?: never;
|
|
143
|
+
head?: never;
|
|
144
|
+
patch?: never;
|
|
145
|
+
trace?: never;
|
|
146
|
+
};
|
|
67
147
|
}
|
|
68
148
|
export type webhooks = Record<string, never>;
|
|
69
149
|
export interface components {
|
|
@@ -75,7 +155,7 @@ export interface components {
|
|
|
75
155
|
client_secret: string;
|
|
76
156
|
/**
|
|
77
157
|
* @description Space-separated scopes requested for the access token.
|
|
78
|
-
* @example hello:read
|
|
158
|
+
* @example hello:read spaces:read calls:read leads:read
|
|
79
159
|
*/
|
|
80
160
|
scope?: string;
|
|
81
161
|
};
|
|
@@ -85,7 +165,7 @@ export interface components {
|
|
|
85
165
|
token_type: "Bearer";
|
|
86
166
|
/** @example 3600 */
|
|
87
167
|
expires_in: number;
|
|
88
|
-
/** @example hello:read */
|
|
168
|
+
/** @example hello:read spaces:read calls:read leads:read */
|
|
89
169
|
scope: string;
|
|
90
170
|
};
|
|
91
171
|
HelloResponse: {
|
|
@@ -108,6 +188,81 @@ export interface components {
|
|
|
108
188
|
data: components["schemas"]["Space"][];
|
|
109
189
|
pagination: components["schemas"]["CursorPagination"];
|
|
110
190
|
};
|
|
191
|
+
ResourceSummary: {
|
|
192
|
+
/** Format: uuid */
|
|
193
|
+
id: string;
|
|
194
|
+
name: string;
|
|
195
|
+
} | null;
|
|
196
|
+
LeadSummary: {
|
|
197
|
+
/** Format: uuid */
|
|
198
|
+
id: string;
|
|
199
|
+
firstName: string;
|
|
200
|
+
lastName: string;
|
|
201
|
+
} | null;
|
|
202
|
+
CallSummary: {
|
|
203
|
+
/** Format: uuid */
|
|
204
|
+
id: string;
|
|
205
|
+
space: components["schemas"]["ResourceSummary"];
|
|
206
|
+
lead: components["schemas"]["LeadSummary"];
|
|
207
|
+
agent: components["schemas"]["ResourceSummary"];
|
|
208
|
+
/** @description Call duration in seconds. */
|
|
209
|
+
duration: number;
|
|
210
|
+
score: number | null;
|
|
211
|
+
sentiment: string | null;
|
|
212
|
+
/** @example completed */
|
|
213
|
+
analysisStatus: string;
|
|
214
|
+
/** @example processing */
|
|
215
|
+
queueStatus: string | null;
|
|
216
|
+
/** Format: date-time */
|
|
217
|
+
createdAt: string;
|
|
218
|
+
/** Format: date-time */
|
|
219
|
+
updatedAt: string;
|
|
220
|
+
};
|
|
221
|
+
CallDetail: components["schemas"]["CallSummary"] & {
|
|
222
|
+
transcript: {
|
|
223
|
+
[key: string]: unknown;
|
|
224
|
+
}[] | null;
|
|
225
|
+
analysis: components["schemas"]["CallAnalysis"];
|
|
226
|
+
};
|
|
227
|
+
CallAnalysis: {
|
|
228
|
+
summary: string | null;
|
|
229
|
+
totalScore: number;
|
|
230
|
+
totalMax: number;
|
|
231
|
+
sentiment: string;
|
|
232
|
+
objectiveMet: boolean;
|
|
233
|
+
objectiveNotes: string | null;
|
|
234
|
+
detectedTags: string[] | null;
|
|
235
|
+
strengths: string[] | null;
|
|
236
|
+
weaknesses: string[] | null;
|
|
237
|
+
} | null;
|
|
238
|
+
CallsListResponse: {
|
|
239
|
+
data: components["schemas"]["CallSummary"][];
|
|
240
|
+
pagination: components["schemas"]["CursorPagination"];
|
|
241
|
+
};
|
|
242
|
+
CallDetailResponse: {
|
|
243
|
+
data: components["schemas"]["CallDetail"];
|
|
244
|
+
};
|
|
245
|
+
Lead: {
|
|
246
|
+
/** Format: uuid */
|
|
247
|
+
id: string;
|
|
248
|
+
firstName: string;
|
|
249
|
+
lastName: string;
|
|
250
|
+
/** Format: email */
|
|
251
|
+
email: string | null;
|
|
252
|
+
phone: string | null;
|
|
253
|
+
space: components["schemas"]["ResourceSummary"];
|
|
254
|
+
/** Format: date-time */
|
|
255
|
+
createdAt: string;
|
|
256
|
+
/** Format: date-time */
|
|
257
|
+
updatedAt: string;
|
|
258
|
+
};
|
|
259
|
+
LeadsListResponse: {
|
|
260
|
+
data: components["schemas"]["Lead"][];
|
|
261
|
+
pagination: components["schemas"]["CursorPagination"];
|
|
262
|
+
};
|
|
263
|
+
LeadDetailResponse: {
|
|
264
|
+
data: components["schemas"]["Lead"];
|
|
265
|
+
};
|
|
111
266
|
CursorPagination: {
|
|
112
267
|
/** @example 50 */
|
|
113
268
|
limit: number;
|
|
@@ -306,4 +461,276 @@ export interface operations {
|
|
|
306
461
|
};
|
|
307
462
|
};
|
|
308
463
|
};
|
|
464
|
+
listCalls: {
|
|
465
|
+
parameters: {
|
|
466
|
+
query?: {
|
|
467
|
+
/** @description Number of calls to return. Defaults to 50. Maximum is 100. */
|
|
468
|
+
limit?: number;
|
|
469
|
+
/** @description Opaque cursor from the previous response's pagination.nextCursor value. */
|
|
470
|
+
cursor?: string;
|
|
471
|
+
/** @description Filter calls to a space ID. */
|
|
472
|
+
spaceId?: string;
|
|
473
|
+
/** @description Filter calls to a lead ID. */
|
|
474
|
+
leadId?: string;
|
|
475
|
+
/** @description Filter calls to an agent ID. */
|
|
476
|
+
agentId?: string;
|
|
477
|
+
/** @description Return calls created at or after this timestamp. */
|
|
478
|
+
createdAfter?: string;
|
|
479
|
+
/** @description Return calls created at or before this timestamp. */
|
|
480
|
+
createdBefore?: string;
|
|
481
|
+
};
|
|
482
|
+
header?: never;
|
|
483
|
+
path?: never;
|
|
484
|
+
cookie?: never;
|
|
485
|
+
};
|
|
486
|
+
requestBody?: never;
|
|
487
|
+
responses: {
|
|
488
|
+
/** @description Paginated calls response. */
|
|
489
|
+
200: {
|
|
490
|
+
headers: {
|
|
491
|
+
[name: string]: unknown;
|
|
492
|
+
};
|
|
493
|
+
content: {
|
|
494
|
+
"application/json": components["schemas"]["CallsListResponse"];
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
/** @description Bearer token is missing, invalid, or expired. */
|
|
498
|
+
401: {
|
|
499
|
+
headers: {
|
|
500
|
+
[name: string]: unknown;
|
|
501
|
+
};
|
|
502
|
+
content: {
|
|
503
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
/** @description Bearer token does not include the required scope. */
|
|
507
|
+
403: {
|
|
508
|
+
headers: {
|
|
509
|
+
[name: string]: unknown;
|
|
510
|
+
};
|
|
511
|
+
content: {
|
|
512
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
513
|
+
};
|
|
514
|
+
};
|
|
515
|
+
/** @description Query parameters failed validation. */
|
|
516
|
+
422: {
|
|
517
|
+
headers: {
|
|
518
|
+
[name: string]: unknown;
|
|
519
|
+
};
|
|
520
|
+
content: {
|
|
521
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
/** @description Per-client rate limit exceeded. */
|
|
525
|
+
429: {
|
|
526
|
+
headers: {
|
|
527
|
+
/** @description Seconds to wait before retrying. */
|
|
528
|
+
"Retry-After"?: string;
|
|
529
|
+
/** @description Request limit per minute for this API client. */
|
|
530
|
+
"X-RateLimit-Limit"?: string;
|
|
531
|
+
[name: string]: unknown;
|
|
532
|
+
};
|
|
533
|
+
content: {
|
|
534
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
535
|
+
};
|
|
536
|
+
};
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
getCall: {
|
|
540
|
+
parameters: {
|
|
541
|
+
query?: never;
|
|
542
|
+
header?: never;
|
|
543
|
+
path: {
|
|
544
|
+
/** @description Call ID. */
|
|
545
|
+
callId: string;
|
|
546
|
+
};
|
|
547
|
+
cookie?: never;
|
|
548
|
+
};
|
|
549
|
+
requestBody?: never;
|
|
550
|
+
responses: {
|
|
551
|
+
/** @description Call detail response. */
|
|
552
|
+
200: {
|
|
553
|
+
headers: {
|
|
554
|
+
[name: string]: unknown;
|
|
555
|
+
};
|
|
556
|
+
content: {
|
|
557
|
+
"application/json": components["schemas"]["CallDetailResponse"];
|
|
558
|
+
};
|
|
559
|
+
};
|
|
560
|
+
/** @description Bearer token is missing, invalid, or expired. */
|
|
561
|
+
401: {
|
|
562
|
+
headers: {
|
|
563
|
+
[name: string]: unknown;
|
|
564
|
+
};
|
|
565
|
+
content: {
|
|
566
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
567
|
+
};
|
|
568
|
+
};
|
|
569
|
+
/** @description Bearer token does not include the required scope. */
|
|
570
|
+
403: {
|
|
571
|
+
headers: {
|
|
572
|
+
[name: string]: unknown;
|
|
573
|
+
};
|
|
574
|
+
content: {
|
|
575
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
576
|
+
};
|
|
577
|
+
};
|
|
578
|
+
/** @description Call was not found in the API client's organization. */
|
|
579
|
+
404: {
|
|
580
|
+
headers: {
|
|
581
|
+
[name: string]: unknown;
|
|
582
|
+
};
|
|
583
|
+
content: {
|
|
584
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
585
|
+
};
|
|
586
|
+
};
|
|
587
|
+
/** @description Per-client rate limit exceeded. */
|
|
588
|
+
429: {
|
|
589
|
+
headers: {
|
|
590
|
+
/** @description Seconds to wait before retrying. */
|
|
591
|
+
"Retry-After"?: string;
|
|
592
|
+
/** @description Request limit per minute for this API client. */
|
|
593
|
+
"X-RateLimit-Limit"?: string;
|
|
594
|
+
[name: string]: unknown;
|
|
595
|
+
};
|
|
596
|
+
content: {
|
|
597
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
598
|
+
};
|
|
599
|
+
};
|
|
600
|
+
};
|
|
601
|
+
};
|
|
602
|
+
listLeads: {
|
|
603
|
+
parameters: {
|
|
604
|
+
query?: {
|
|
605
|
+
/** @description Number of leads to return. Defaults to 50. Maximum is 100. */
|
|
606
|
+
limit?: number;
|
|
607
|
+
/** @description Opaque cursor from the previous response's pagination.nextCursor value. */
|
|
608
|
+
cursor?: string;
|
|
609
|
+
/** @description Filter leads to a space ID. */
|
|
610
|
+
spaceId?: string;
|
|
611
|
+
/** @description Return leads created at or after this timestamp. */
|
|
612
|
+
createdAfter?: string;
|
|
613
|
+
/** @description Return leads created at or before this timestamp. */
|
|
614
|
+
createdBefore?: string;
|
|
615
|
+
};
|
|
616
|
+
header?: never;
|
|
617
|
+
path?: never;
|
|
618
|
+
cookie?: never;
|
|
619
|
+
};
|
|
620
|
+
requestBody?: never;
|
|
621
|
+
responses: {
|
|
622
|
+
/** @description Paginated leads response. */
|
|
623
|
+
200: {
|
|
624
|
+
headers: {
|
|
625
|
+
[name: string]: unknown;
|
|
626
|
+
};
|
|
627
|
+
content: {
|
|
628
|
+
"application/json": components["schemas"]["LeadsListResponse"];
|
|
629
|
+
};
|
|
630
|
+
};
|
|
631
|
+
/** @description Bearer token is missing, invalid, or expired. */
|
|
632
|
+
401: {
|
|
633
|
+
headers: {
|
|
634
|
+
[name: string]: unknown;
|
|
635
|
+
};
|
|
636
|
+
content: {
|
|
637
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
638
|
+
};
|
|
639
|
+
};
|
|
640
|
+
/** @description Bearer token does not include the required scope. */
|
|
641
|
+
403: {
|
|
642
|
+
headers: {
|
|
643
|
+
[name: string]: unknown;
|
|
644
|
+
};
|
|
645
|
+
content: {
|
|
646
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
647
|
+
};
|
|
648
|
+
};
|
|
649
|
+
/** @description Query parameters failed validation. */
|
|
650
|
+
422: {
|
|
651
|
+
headers: {
|
|
652
|
+
[name: string]: unknown;
|
|
653
|
+
};
|
|
654
|
+
content: {
|
|
655
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
656
|
+
};
|
|
657
|
+
};
|
|
658
|
+
/** @description Per-client rate limit exceeded. */
|
|
659
|
+
429: {
|
|
660
|
+
headers: {
|
|
661
|
+
/** @description Seconds to wait before retrying. */
|
|
662
|
+
"Retry-After"?: string;
|
|
663
|
+
/** @description Request limit per minute for this API client. */
|
|
664
|
+
"X-RateLimit-Limit"?: string;
|
|
665
|
+
[name: string]: unknown;
|
|
666
|
+
};
|
|
667
|
+
content: {
|
|
668
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
669
|
+
};
|
|
670
|
+
};
|
|
671
|
+
};
|
|
672
|
+
};
|
|
673
|
+
getLead: {
|
|
674
|
+
parameters: {
|
|
675
|
+
query?: never;
|
|
676
|
+
header?: never;
|
|
677
|
+
path: {
|
|
678
|
+
/** @description Lead ID. */
|
|
679
|
+
leadId: string;
|
|
680
|
+
};
|
|
681
|
+
cookie?: never;
|
|
682
|
+
};
|
|
683
|
+
requestBody?: never;
|
|
684
|
+
responses: {
|
|
685
|
+
/** @description Lead detail response. */
|
|
686
|
+
200: {
|
|
687
|
+
headers: {
|
|
688
|
+
[name: string]: unknown;
|
|
689
|
+
};
|
|
690
|
+
content: {
|
|
691
|
+
"application/json": components["schemas"]["LeadDetailResponse"];
|
|
692
|
+
};
|
|
693
|
+
};
|
|
694
|
+
/** @description Bearer token is missing, invalid, or expired. */
|
|
695
|
+
401: {
|
|
696
|
+
headers: {
|
|
697
|
+
[name: string]: unknown;
|
|
698
|
+
};
|
|
699
|
+
content: {
|
|
700
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
701
|
+
};
|
|
702
|
+
};
|
|
703
|
+
/** @description Bearer token does not include the required scope. */
|
|
704
|
+
403: {
|
|
705
|
+
headers: {
|
|
706
|
+
[name: string]: unknown;
|
|
707
|
+
};
|
|
708
|
+
content: {
|
|
709
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
/** @description Lead was not found in the API client's organization. */
|
|
713
|
+
404: {
|
|
714
|
+
headers: {
|
|
715
|
+
[name: string]: unknown;
|
|
716
|
+
};
|
|
717
|
+
content: {
|
|
718
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
719
|
+
};
|
|
720
|
+
};
|
|
721
|
+
/** @description Per-client rate limit exceeded. */
|
|
722
|
+
429: {
|
|
723
|
+
headers: {
|
|
724
|
+
/** @description Seconds to wait before retrying. */
|
|
725
|
+
"Retry-After"?: string;
|
|
726
|
+
/** @description Request limit per minute for this API client. */
|
|
727
|
+
"X-RateLimit-Limit"?: string;
|
|
728
|
+
[name: string]: unknown;
|
|
729
|
+
};
|
|
730
|
+
content: {
|
|
731
|
+
"application/json": components["schemas"]["ErrorResponse"];
|
|
732
|
+
};
|
|
733
|
+
};
|
|
734
|
+
};
|
|
735
|
+
};
|
|
309
736
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { createVueVoxClient } from "./client.js";
|
|
2
|
-
export type { ListSpacesOptions, VueVoxClientOptions } from "./client.js";
|
|
2
|
+
export type { CallDetailResponse, CallsListResponse, CallSummary, HelloResponse, Lead, LeadDetailResponse, LeadsListResponse, ListCallsOptions, ListLeadsOptions, ListSpacesOptions, Space, SpacesListResponse, VueVoxApiResponse, VueVoxClientOptions, VueVoxResponseEvent, VueVoxResponseMetadata, } from "./client.js";
|
|
3
3
|
export { VueVoxApiError } from "./errors.js";
|
|
4
4
|
export type { VueVoxErrorResponse } from "./errors.js";
|