@vuevox/sdk 0.3.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 +64 -30
- package/dist/client.d.ts +68 -3
- package/dist/client.js +114 -39
- package/dist/errors.d.ts +4 -1
- package/dist/errors.js +7 -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,16 +35,20 @@ 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.data.message);
|
|
41
|
-
console.log(hello.requestId);
|
|
41
|
+
const hello = await vuevox.hello.get();
|
|
42
|
+
console.log(hello.data.message, hello.requestId);
|
|
42
43
|
|
|
43
|
-
const spaces = await vuevox.
|
|
44
|
-
console.log(spaces.data.data);
|
|
45
|
-
|
|
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);
|
|
46
52
|
```
|
|
47
53
|
|
|
48
54
|
The SDK requests and caches a short-lived access token using client credentials, then sends it as a bearer token for API calls.
|
|
@@ -52,10 +58,10 @@ The SDK requests and caches a short-lived access token using client credentials,
|
|
|
52
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.
|
|
53
59
|
|
|
54
60
|
```ts
|
|
55
|
-
const
|
|
61
|
+
const call = await vuevox.calls.get("call-id");
|
|
56
62
|
|
|
57
|
-
console.log(
|
|
58
|
-
console.log(
|
|
63
|
+
console.log(call.requestId);
|
|
64
|
+
console.log(call.data.data.transcript);
|
|
59
65
|
```
|
|
60
66
|
|
|
61
67
|
For centralized logging, pass `onResponse`. The hook runs for every SDK-managed HTTP response, including the token request.
|
|
@@ -64,7 +70,7 @@ For centralized logging, pass `onResponse`. The hook runs for every SDK-managed
|
|
|
64
70
|
const vuevox = createVueVoxClient({
|
|
65
71
|
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
66
72
|
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
67
|
-
scope: ["
|
|
73
|
+
scope: ["calls:read"],
|
|
68
74
|
onResponse: ({ method, path, status, requestId }) => {
|
|
69
75
|
console.log({ method, path, status, requestId });
|
|
70
76
|
},
|
|
@@ -73,7 +79,7 @@ const vuevox = createVueVoxClient({
|
|
|
73
79
|
|
|
74
80
|
## Error Handling
|
|
75
81
|
|
|
76
|
-
API errors throw `VueVoxApiError`. The SDK exposes `error.requestId`
|
|
82
|
+
API errors throw `VueVoxApiError`. The SDK exposes `error.requestId`, `error.details`, `error.retryAfter`, and `error.isRateLimited`.
|
|
77
83
|
|
|
78
84
|
```ts
|
|
79
85
|
import { VueVoxApiError, createVueVoxClient } from "@vuevox/sdk";
|
|
@@ -81,11 +87,11 @@ import { VueVoxApiError, createVueVoxClient } from "@vuevox/sdk";
|
|
|
81
87
|
const vuevox = createVueVoxClient({
|
|
82
88
|
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
83
89
|
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
84
|
-
scope: ["
|
|
90
|
+
scope: ["calls:read"],
|
|
85
91
|
});
|
|
86
92
|
|
|
87
93
|
try {
|
|
88
|
-
await vuevox.
|
|
94
|
+
await vuevox.calls.list({ limit: 50 });
|
|
89
95
|
} catch (error) {
|
|
90
96
|
if (error instanceof VueVoxApiError) {
|
|
91
97
|
console.error(error.status, error.code, error.message, error.requestId);
|
|
@@ -104,6 +110,49 @@ invalid_client
|
|
|
104
110
|
invalid_scope
|
|
105
111
|
insufficient_scope
|
|
106
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
|
+
});
|
|
107
156
|
```
|
|
108
157
|
|
|
109
158
|
## Token Behavior
|
|
@@ -130,7 +179,7 @@ const vuevox = createVueVoxClient({
|
|
|
130
179
|
baseUrl: "https://api.vuevox.com",
|
|
131
180
|
clientId: process.env.VUEVOX_CLIENT_ID!,
|
|
132
181
|
clientSecret: process.env.VUEVOX_CLIENT_SECRET!,
|
|
133
|
-
scope: ["
|
|
182
|
+
scope: ["calls:read"],
|
|
134
183
|
});
|
|
135
184
|
```
|
|
136
185
|
|
|
@@ -145,18 +194,3 @@ const { data, error } = await vuevox.raw.GET("/v1/hello", {
|
|
|
145
194
|
},
|
|
146
195
|
});
|
|
147
196
|
```
|
|
148
|
-
|
|
149
|
-
## Pagination
|
|
150
|
-
|
|
151
|
-
List endpoints use cursor pagination.
|
|
152
|
-
|
|
153
|
-
```ts
|
|
154
|
-
const firstPage = await vuevox.listSpaces({ limit: 50 });
|
|
155
|
-
|
|
156
|
-
if (firstPage.data.pagination.nextCursor) {
|
|
157
|
-
const secondPage = await vuevox.listSpaces({
|
|
158
|
-
limit: 50,
|
|
159
|
-
cursor: firstPage.data.pagination.nextCursor,
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
```
|
package/dist/client.d.ts
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
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
|
+
}
|
|
8
27
|
export interface VueVoxResponseMetadata {
|
|
9
28
|
requestId?: string;
|
|
10
29
|
status: number;
|
|
@@ -15,6 +34,7 @@ export interface VueVoxApiResponse<T> extends VueVoxResponseMetadata {
|
|
|
15
34
|
export interface VueVoxResponseEvent extends VueVoxResponseMetadata {
|
|
16
35
|
method: string;
|
|
17
36
|
path: string;
|
|
37
|
+
retryAfter?: number;
|
|
18
38
|
}
|
|
19
39
|
export interface VueVoxClientOptions {
|
|
20
40
|
baseUrl?: string;
|
|
@@ -23,11 +43,56 @@ export interface VueVoxClientOptions {
|
|
|
23
43
|
scope?: string | string[];
|
|
24
44
|
fetch?: typeof fetch;
|
|
25
45
|
onResponse?: (event: VueVoxResponseEvent) => void;
|
|
46
|
+
retries?: number;
|
|
47
|
+
retryBaseDelayMs?: number;
|
|
48
|
+
retryMaxDelayMs?: number;
|
|
26
49
|
}
|
|
27
50
|
export declare function createVueVoxClient(options: VueVoxClientOptions): {
|
|
28
51
|
getAccessToken: () => Promise<string>;
|
|
29
|
-
hello:
|
|
30
|
-
|
|
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
|
+
};
|
|
31
96
|
raw: import("openapi-fetch").Client<paths, `${string}/${string}`>;
|
|
32
97
|
};
|
|
33
|
-
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,57 +24,88 @@ export function createVueVoxClient(options) {
|
|
|
21
24
|
scope: formatScope(options.scope),
|
|
22
25
|
}),
|
|
23
26
|
});
|
|
24
|
-
const body =
|
|
25
|
-
const requestId = getRequestId(response, body);
|
|
26
|
-
notifyResponse(options, "POST", "/oauth/token", response, requestId);
|
|
27
|
-
if (!response.ok) {
|
|
28
|
-
const error = isErrorResponse(body) ? body.error : null;
|
|
29
|
-
throw new VueVoxApiError(response.status, error?.code ?? "token_request_failed", error?.message ?? "VueVox token request failed.", isErrorResponse(body) ? body : undefined, requestId);
|
|
30
|
-
}
|
|
31
|
-
if (!isTokenResponse(body)) {
|
|
32
|
-
throw new VueVoxApiError(response.status, "invalid_token_response", "VueVox returned an invalid token response.", undefined, requestId);
|
|
33
|
-
}
|
|
27
|
+
const body = result.data;
|
|
34
28
|
cachedToken = {
|
|
35
29
|
accessToken: body.access_token,
|
|
36
30
|
expiresAt: Date.now() + body.expires_in * 1000,
|
|
37
31
|
};
|
|
38
32
|
return cachedToken.accessToken;
|
|
39
33
|
}
|
|
40
|
-
async function
|
|
41
|
-
|
|
42
|
-
const { data, error, response } = await raw.GET("/v1/hello", {
|
|
43
|
-
headers: {
|
|
44
|
-
Authorization: `Bearer ${accessToken}`,
|
|
45
|
-
},
|
|
46
|
-
});
|
|
47
|
-
const requestId = getRequestId(response, error);
|
|
48
|
-
notifyResponse(options, "GET", "/v1/hello", response, requestId);
|
|
49
|
-
if (error) {
|
|
50
|
-
throw new VueVoxApiError(response.status, error.error.code, error.error.message, error, requestId);
|
|
51
|
-
}
|
|
52
|
-
return withMetadata(data, response, requestId);
|
|
34
|
+
async function getHello() {
|
|
35
|
+
return apiGet("/v1/hello");
|
|
53
36
|
}
|
|
54
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) {
|
|
55
53
|
const accessToken = await getAccessToken();
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
query: listOptions,
|
|
59
|
-
},
|
|
54
|
+
const result = await requestJson("GET", path, {
|
|
55
|
+
method: "GET",
|
|
60
56
|
headers: {
|
|
61
57
|
Authorization: `Bearer ${accessToken}`,
|
|
62
58
|
},
|
|
59
|
+
query,
|
|
63
60
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function retryDelayMs(attempt, retryAfter) {
|
|
85
|
+
if (retryAfter !== undefined) {
|
|
86
|
+
return retryAfter * 1000;
|
|
68
87
|
}
|
|
69
|
-
return
|
|
88
|
+
return Math.min(retryBaseDelayMs * 2 ** attempt, retryMaxDelayMs);
|
|
70
89
|
}
|
|
71
90
|
return {
|
|
72
91
|
getAccessToken,
|
|
73
|
-
hello
|
|
74
|
-
|
|
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
|
+
},
|
|
75
109
|
raw,
|
|
76
110
|
};
|
|
77
111
|
}
|
|
@@ -84,6 +118,15 @@ function formatScope(scope) {
|
|
|
84
118
|
function trimTrailingSlash(value) {
|
|
85
119
|
return value.replace(/\/+$/, "");
|
|
86
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
|
+
}
|
|
87
130
|
async function parseJson(response) {
|
|
88
131
|
try {
|
|
89
132
|
return (await response.json());
|
|
@@ -93,16 +136,19 @@ async function parseJson(response) {
|
|
|
93
136
|
}
|
|
94
137
|
}
|
|
95
138
|
function isTokenResponse(value) {
|
|
96
|
-
return
|
|
139
|
+
return isObject(value) && "access_token" in value;
|
|
97
140
|
}
|
|
98
141
|
function isErrorResponse(value) {
|
|
99
|
-
return
|
|
142
|
+
return isObject(value) && "error" in value;
|
|
100
143
|
}
|
|
101
144
|
function getRequestId(response, body) {
|
|
102
145
|
return response.headers.get("X-Request-Id") ?? (isErrorBody(body) ? body.error.requestId : undefined);
|
|
103
146
|
}
|
|
104
147
|
function isErrorBody(value) {
|
|
105
|
-
return
|
|
148
|
+
return isObject(value) && "error" in value;
|
|
149
|
+
}
|
|
150
|
+
function isObject(value) {
|
|
151
|
+
return typeof value === "object" && value !== null;
|
|
106
152
|
}
|
|
107
153
|
function withMetadata(data, response, requestId) {
|
|
108
154
|
return {
|
|
@@ -111,11 +157,40 @@ function withMetadata(data, response, requestId) {
|
|
|
111
157
|
status: response.status,
|
|
112
158
|
};
|
|
113
159
|
}
|
|
114
|
-
function notifyResponse(options, method, path, response, requestId) {
|
|
160
|
+
function notifyResponse(options, method, path, response, requestId, retryAfter) {
|
|
115
161
|
options.onResponse?.({
|
|
116
162
|
method,
|
|
117
163
|
path,
|
|
118
164
|
requestId,
|
|
165
|
+
retryAfter,
|
|
119
166
|
status: response.status,
|
|
120
167
|
});
|
|
121
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));
|
|
196
|
+
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -3,7 +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;
|
|
6
8
|
readonly requestId?: string;
|
|
9
|
+
readonly retryAfter?: number;
|
|
7
10
|
readonly response?: VueVoxErrorResponse;
|
|
8
|
-
constructor(status: number, code: string, message: string, response?: VueVoxErrorResponse, requestId?: string);
|
|
11
|
+
constructor(status: number, code: string, message: string, response?: VueVoxErrorResponse, requestId?: string, retryAfter?: number);
|
|
9
12
|
}
|
package/dist/errors.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
export class VueVoxApiError extends Error {
|
|
2
2
|
status;
|
|
3
3
|
code;
|
|
4
|
+
details;
|
|
5
|
+
isRateLimited;
|
|
4
6
|
requestId;
|
|
7
|
+
retryAfter;
|
|
5
8
|
response;
|
|
6
|
-
constructor(status, code, message, response, requestId) {
|
|
9
|
+
constructor(status, code, message, response, requestId, retryAfter) {
|
|
7
10
|
super(message);
|
|
8
11
|
this.name = "VueVoxApiError";
|
|
9
12
|
this.status = status;
|
|
10
13
|
this.code = code;
|
|
14
|
+
this.details = response?.error.details;
|
|
15
|
+
this.isRateLimited = status === 429 || code === "rate_limited";
|
|
11
16
|
this.requestId = requestId ?? response?.error.requestId;
|
|
17
|
+
this.retryAfter = retryAfter;
|
|
12
18
|
this.response = response;
|
|
13
19
|
}
|
|
14
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, VueVoxApiResponse, VueVoxClientOptions, VueVoxResponseEvent, VueVoxResponseMetadata, } 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";
|