@spekoai/sdk 0.4.3 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +88 -0
  3. package/dist/index.d.ts +3 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -0
  6. package/dist/lib/client.d.ts +13 -1
  7. package/dist/lib/client.d.ts.map +1 -1
  8. package/dist/lib/client.js +22 -2
  9. package/dist/lib/http.d.ts +12 -4
  10. package/dist/lib/http.d.ts.map +1 -1
  11. package/dist/lib/http.js +31 -14
  12. package/dist/lib/resources/agents.d.ts +12 -2
  13. package/dist/lib/resources/agents.d.ts.map +1 -1
  14. package/dist/lib/resources/agents.js +12 -4
  15. package/dist/lib/resources/calls.d.ts +19 -1
  16. package/dist/lib/resources/calls.d.ts.map +1 -1
  17. package/dist/lib/resources/calls.js +22 -0
  18. package/dist/lib/resources/knowledge-bases.d.ts +1 -1
  19. package/dist/lib/resources/knowledge-bases.js +1 -1
  20. package/dist/lib/resources/phone-numbers.d.ts +2 -1
  21. package/dist/lib/resources/phone-numbers.d.ts.map +1 -1
  22. package/dist/lib/resources/phone-numbers.js +2 -1
  23. package/dist/lib/resources/realtime.d.ts +3 -5
  24. package/dist/lib/resources/realtime.d.ts.map +1 -1
  25. package/dist/lib/resources/realtime.js +829 -91
  26. package/dist/lib/resources/sessions.d.ts +53 -0
  27. package/dist/lib/resources/sessions.d.ts.map +1 -0
  28. package/dist/lib/resources/sessions.js +166 -0
  29. package/dist/lib/resources/sms.d.ts +80 -0
  30. package/dist/lib/resources/sms.d.ts.map +1 -0
  31. package/dist/lib/resources/sms.js +152 -0
  32. package/dist/lib/resources/synthesize.d.ts.map +1 -1
  33. package/dist/lib/resources/synthesize.js +12 -6
  34. package/dist/lib/resources/transcribe.d.ts.map +1 -1
  35. package/dist/lib/resources/transcribe.js +9 -2
  36. package/dist/lib/resources/voice.d.ts +283 -1
  37. package/dist/lib/resources/voice.d.ts.map +1 -1
  38. package/dist/lib/resources/voice.js +345 -0
  39. package/dist/lib/resources/webhooks.d.ts +25 -0
  40. package/dist/lib/resources/webhooks.d.ts.map +1 -0
  41. package/dist/lib/resources/webhooks.js +46 -0
  42. package/dist/lib/types/index.d.ts +998 -9
  43. package/dist/lib/types/index.d.ts.map +1 -1
  44. package/dist/lib/voice-contract.d.ts +280 -0
  45. package/dist/lib/voice-contract.d.ts.map +1 -0
  46. package/dist/lib/voice-contract.js +115 -0
  47. package/package.json +2 -1
  48. package/src/index.ts +212 -0
  49. package/src/lib/client.ts +169 -0
  50. package/src/lib/errors.ts +28 -0
  51. package/src/lib/http.ts +442 -0
  52. package/src/lib/resources/agents.ts +211 -0
  53. package/src/lib/resources/callbacks.ts +40 -0
  54. package/src/lib/resources/calls.ts +113 -0
  55. package/src/lib/resources/complete.ts +63 -0
  56. package/src/lib/resources/credits.ts +41 -0
  57. package/src/lib/resources/knowledge-bases.ts +199 -0
  58. package/src/lib/resources/phone-numbers.ts +109 -0
  59. package/src/lib/resources/realtime-globals.d.ts +31 -0
  60. package/src/lib/resources/realtime.spec.ts +565 -0
  61. package/src/lib/resources/realtime.ts +1169 -0
  62. package/src/lib/resources/sessions.ts +191 -0
  63. package/src/lib/resources/sms.ts +214 -0
  64. package/src/lib/resources/synthesize.ts +101 -0
  65. package/src/lib/resources/transcribe.ts +91 -0
  66. package/src/lib/resources/usage.ts +24 -0
  67. package/src/lib/resources/voice.ts +426 -0
  68. package/src/lib/resources/voices.ts +32 -0
  69. package/src/lib/resources/webhooks.ts +67 -0
  70. package/src/lib/types/index.ts +2409 -0
  71. package/src/lib/voice-contract.ts +358 -0
@@ -0,0 +1,113 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import type {
3
+ BlindTransferParams,
4
+ CallDetail,
5
+ CallEvent,
6
+ CallRecording,
7
+ CallReport,
8
+ CallTransfer,
9
+ CallTransferResponse,
10
+ CancelWarmTransferParams,
11
+ CompleteWarmTransferParams,
12
+ EndCallResult,
13
+ FinalizeCallReportParams,
14
+ FinalizeCallReportResult,
15
+ WarmTransferParams,
16
+ WebJoinParams,
17
+ WebJoinResult,
18
+ } from '../types/index.js';
19
+
20
+ export class Calls {
21
+ constructor(private readonly http: HttpClient) {}
22
+
23
+ get(callId: string): Promise<CallDetail> {
24
+ return this.http.get<CallDetail>(`/v1/calls/${encodeURIComponent(callId)}`);
25
+ }
26
+
27
+ events(callId: string): Promise<{ events: CallEvent[] }> {
28
+ return this.http.get<{ events: CallEvent[] }>(`/v1/calls/${encodeURIComponent(callId)}/events`);
29
+ }
30
+
31
+ report(callId: string): Promise<CallReport> {
32
+ return this.http.get<CallReport>(`/v1/calls/${encodeURIComponent(callId)}/report`);
33
+ }
34
+
35
+ finalizeReport(
36
+ callId: string,
37
+ params: FinalizeCallReportParams = {},
38
+ ): Promise<FinalizeCallReportResult> {
39
+ return this.http.post<FinalizeCallReportResult>(
40
+ `/v1/calls/${encodeURIComponent(callId)}/report/finalize`,
41
+ params,
42
+ );
43
+ }
44
+
45
+ recording(callId: string): Promise<CallRecording> {
46
+ return this.http.get<CallRecording>(`/v1/calls/${encodeURIComponent(callId)}/recording`);
47
+ }
48
+
49
+ /**
50
+ * Browser bridge-in: mint a short-lived token that joins THIS live call's
51
+ * room from a web client (pass `token`/`url` to `@spekoai/client`'s
52
+ * `VoiceConversation.create({ transportToken, transportUrl })`). Once the
53
+ * browser publishes audio the platform bridges it to the phone leg and
54
+ * mutes the agent; when the browser leaves, the agent resumes.
55
+ *
56
+ * Mint at click time — the token is short-TTL and a `409` means the call
57
+ * is no longer live. Concurrent/repeat joins are allowed (rejoin after a
58
+ * drop just calls this again).
59
+ */
60
+ webJoin(callId: string, params: WebJoinParams = {}): Promise<WebJoinResult> {
61
+ return this.http.post<WebJoinResult>(
62
+ `/v1/calls/${encodeURIComponent(callId)}/web-join`,
63
+ params,
64
+ );
65
+ }
66
+
67
+ /**
68
+ * End a live call now (kill switch): tears the room down, which hangs up
69
+ * every leg. Resolves with `status: 'ending'` once teardown is requested,
70
+ * or `status: 'already_ended'` if the call was over.
71
+ */
72
+ end(callId: string): Promise<EndCallResult> {
73
+ return this.http.post<EndCallResult>(`/v1/calls/${encodeURIComponent(callId)}/end`, {});
74
+ }
75
+
76
+ blindTransfer(callId: string, params: BlindTransferParams): Promise<CallTransfer> {
77
+ return this.http.post<CallTransfer>(
78
+ `/v1/calls/${encodeURIComponent(callId)}/transfers/blind`,
79
+ params,
80
+ );
81
+ }
82
+
83
+ warmTransfer(callId: string, params: WarmTransferParams): Promise<CallTransferResponse> {
84
+ return this.http.post<CallTransferResponse>(
85
+ `/v1/calls/${encodeURIComponent(callId)}/transfers/warm`,
86
+ params,
87
+ );
88
+ }
89
+
90
+ completeWarmTransfer(
91
+ callId: string,
92
+ transferId: string,
93
+ params: CompleteWarmTransferParams = {},
94
+ ): Promise<CallTransfer> {
95
+ return this.http.post<CallTransfer>(
96
+ `/v1/calls/${encodeURIComponent(callId)}/transfers/${encodeURIComponent(
97
+ transferId,
98
+ )}/complete`,
99
+ params,
100
+ );
101
+ }
102
+
103
+ cancelWarmTransfer(
104
+ callId: string,
105
+ transferId: string,
106
+ params: CancelWarmTransferParams = {},
107
+ ): Promise<CallTransferResponse> {
108
+ return this.http.post<CallTransferResponse>(
109
+ `/v1/calls/${encodeURIComponent(callId)}/transfers/${encodeURIComponent(transferId)}/cancel`,
110
+ params,
111
+ );
112
+ }
113
+ }
@@ -0,0 +1,63 @@
1
+ import { SpekoApiError } from '../errors.js';
2
+ import type { HttpClient } from '../http.js';
3
+ import type { CompleteParams, CompleteResult, CompleteStreamEvent } from '../types/index.js';
4
+
5
+ export class Complete {
6
+ constructor(private readonly http: HttpClient) {}
7
+
8
+ /**
9
+ * Run an LLM completion. The Speko router picks the best provider for your
10
+ * `(language, region, optimizeFor)` and falls over automatically.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const { text, provider } = await speko.complete({
15
+ * messages: [{ role: 'user', content: 'Hi!' }],
16
+ * intent: { language: 'en' },
17
+ * });
18
+ * ```
19
+ */
20
+ async call(params: CompleteParams, abortSignal?: AbortSignal): Promise<CompleteResult> {
21
+ let done: CompleteResult | undefined;
22
+ for await (const event of this.stream(params, abortSignal)) {
23
+ if (event.type === 'done') {
24
+ done = {
25
+ text: event.text,
26
+ provider: event.provider,
27
+ model: event.model,
28
+ usage: event.usage,
29
+ failoverCount: event.failoverCount,
30
+ scoresRunId: event.scoresRunId,
31
+ ...(event.toolCalls && { toolCalls: event.toolCalls }),
32
+ };
33
+ } else if (event.type === 'error') {
34
+ throw new SpekoApiError(event.error, 200, event.code);
35
+ }
36
+ }
37
+ if (!done) {
38
+ throw new SpekoApiError('Complete stream ended without a done event', 200, 'STREAM_ENDED');
39
+ }
40
+ return done;
41
+ }
42
+
43
+ async *stream(
44
+ params: CompleteParams,
45
+ abortSignal?: AbortSignal,
46
+ ): AsyncIterableIterator<CompleteStreamEvent> {
47
+ const { sessionId, ...body } = params;
48
+ const trimmedSessionId = sessionId?.trim();
49
+ const headers = trimmedSessionId ? { 'x-session-id': trimmedSessionId } : undefined;
50
+ for await (const event of this.http.requestSse(
51
+ 'POST',
52
+ '/v1/complete',
53
+ body,
54
+ abortSignal,
55
+ headers,
56
+ )) {
57
+ yield {
58
+ ...(event.data as Record<string, unknown>),
59
+ type: event.event,
60
+ } as CompleteStreamEvent;
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,41 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import type {
3
+ CreditLedgerPage,
4
+ CreditLedgerQueryParams,
5
+ OrganizationBalance,
6
+ } from '../types/index.js';
7
+
8
+ /**
9
+ * Prepaid credit balance + append-only ledger. Balance is reported in USD.
10
+ */
11
+ export class Credits {
12
+ constructor(private readonly http: HttpClient) {}
13
+
14
+ /**
15
+ * Current credit balance for the caller's organization.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * const { balanceUsd } = await speko.credits.getBalance();
20
+ * if (balanceUsd < 0.5) showLowBalanceBanner();
21
+ * ```
22
+ */
23
+ getBalance(): Promise<OrganizationBalance> {
24
+ return this.http.get<OrganizationBalance>('/v1/credits/balance');
25
+ }
26
+
27
+ /**
28
+ * Most-recent-first page of credit movements (grants, debits, topups,
29
+ * refunds, adjustments). `nextCursor` is the `createdAt` of the last
30
+ * entry on the current page — pass it back as `cursor` to fetch the
31
+ * next page; `null` means no more pages.
32
+ */
33
+ getLedger(params?: CreditLedgerQueryParams): Promise<CreditLedgerPage> {
34
+ const query = new URLSearchParams();
35
+ if (params?.limit) query.set('limit', String(params.limit));
36
+ if (params?.cursor) query.set('cursor', params.cursor);
37
+
38
+ const qs = query.toString();
39
+ return this.http.get<CreditLedgerPage>(`/v1/credits/ledger${qs ? `?${qs}` : ''}`);
40
+ }
41
+ }
@@ -0,0 +1,199 @@
1
+ import { SpekoApiError } from '../errors.js';
2
+ import type { HttpClient } from '../http.js';
3
+ import type {
4
+ KnowledgeBaseCreateParams,
5
+ KnowledgeBaseDocumentCreateParams,
6
+ KnowledgeBaseDocumentCreateResult,
7
+ KnowledgeBaseDocumentPollOptions,
8
+ KnowledgeBaseDocumentRow,
9
+ KnowledgeBaseDocumentUploadParams,
10
+ KnowledgeBaseListParams,
11
+ KnowledgeBaseRow,
12
+ } from '../types/index.js';
13
+
14
+ const DEFAULT_POLL_INTERVAL_MS = 2_000;
15
+ const DEFAULT_POLL_TIMEOUT_MS = 120_000;
16
+
17
+ /**
18
+ * Per-agent knowledge bases. Each KB owns documents that get embedded
19
+ * into a PHALANX tenant so the agent can retrieve relevant chunks
20
+ * during a call. Every agent created via {@link Agents.create}
21
+ * auto-provisions a `Default` KB; additional KBs can be created
22
+ * explicitly with {@link KnowledgeBases.create}.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * const kb = await speko.knowledgeBases.create({
27
+ * agentId: agent.id,
28
+ * name: 'Product FAQ',
29
+ * });
30
+ *
31
+ * const doc = await speko.knowledgeBases.uploadDocument(kb.id, {
32
+ * filename: 'faq.md',
33
+ * contentType: 'text/markdown',
34
+ * data: await readFile('faq.md'),
35
+ * });
36
+ *
37
+ * const ready = await speko.knowledgeBases.pollDocumentReady(kb.id, doc.id);
38
+ * ```
39
+ */
40
+ export class KnowledgeBases {
41
+ constructor(private readonly http: HttpClient) {}
42
+
43
+ create(params: KnowledgeBaseCreateParams): Promise<KnowledgeBaseRow> {
44
+ return this.http.post<KnowledgeBaseRow>('/v1/knowledge-bases', params);
45
+ }
46
+
47
+ list(params: KnowledgeBaseListParams = {}): Promise<KnowledgeBaseRow[]> {
48
+ const query = new URLSearchParams();
49
+ if (params.agentId) query.set('agentId', params.agentId);
50
+ const qs = query.toString();
51
+ return this.http.get<KnowledgeBaseRow[]>(`/v1/knowledge-bases${qs ? `?${qs}` : ''}`);
52
+ }
53
+
54
+ get(kbId: string): Promise<KnowledgeBaseRow> {
55
+ return this.http.get<KnowledgeBaseRow>(`/v1/knowledge-bases/${encodeURIComponent(kbId)}`);
56
+ }
57
+
58
+ delete(kbId: string): Promise<{ deleted: boolean }> {
59
+ return this.http.delete<{ deleted: boolean }>(
60
+ `/v1/knowledge-bases/${encodeURIComponent(kbId)}`,
61
+ );
62
+ }
63
+
64
+ listDocuments(kbId: string): Promise<KnowledgeBaseDocumentRow[]> {
65
+ return this.http.get<KnowledgeBaseDocumentRow[]>(
66
+ `/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents`,
67
+ );
68
+ }
69
+
70
+ getDocument(kbId: string, docId: string): Promise<KnowledgeBaseDocumentRow> {
71
+ return this.http.get<KnowledgeBaseDocumentRow>(
72
+ `/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents/${encodeURIComponent(docId)}`,
73
+ );
74
+ }
75
+
76
+ createDocument(
77
+ kbId: string,
78
+ params: KnowledgeBaseDocumentCreateParams,
79
+ ): Promise<KnowledgeBaseDocumentCreateResult> {
80
+ return this.http.post<KnowledgeBaseDocumentCreateResult>(
81
+ `/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents`,
82
+ params,
83
+ );
84
+ }
85
+
86
+ finalizeDocument(kbId: string, docId: string): Promise<KnowledgeBaseDocumentRow> {
87
+ return this.http.post<KnowledgeBaseDocumentRow>(
88
+ `/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents/${encodeURIComponent(docId)}/finalize`,
89
+ {},
90
+ );
91
+ }
92
+
93
+ deleteDocument(kbId: string, docId: string): Promise<{ deleted: boolean }> {
94
+ return this.http.delete<{ deleted: boolean }>(
95
+ `/v1/knowledge-bases/${encodeURIComponent(kbId)}/documents/${encodeURIComponent(docId)}`,
96
+ );
97
+ }
98
+
99
+ /**
100
+ * Convenience wrapper: register a document, upload its bytes to the
101
+ * signed PUT URL the server mints, then call finalize. Returns the
102
+ * document with status flipped to `processing`. Call
103
+ * {@link pollDocumentReady} to wait for ingest completion.
104
+ *
105
+ * The server's signed upload URL expires 600 seconds after issuance,
106
+ * so do not hold the result of {@link createDocument} for long before
107
+ * uploading. This wrapper performs all three steps back-to-back.
108
+ */
109
+ async uploadDocument(
110
+ kbId: string,
111
+ params: KnowledgeBaseDocumentUploadParams,
112
+ ): Promise<KnowledgeBaseDocumentRow> {
113
+ const sizeBytes = byteLengthOf(params.data);
114
+
115
+ const { document, upload } = await this.createDocument(kbId, {
116
+ filename: params.filename,
117
+ contentType: params.contentType,
118
+ sizeBytes,
119
+ metadata: params.metadata,
120
+ });
121
+
122
+ const putResponse = await fetch(upload.url, {
123
+ method: upload.method,
124
+ headers: upload.headers,
125
+ body: toBodyInit(params.data),
126
+ });
127
+
128
+ if (!putResponse.ok) {
129
+ const text = await safeReadText(putResponse);
130
+ throw new SpekoApiError(
131
+ `Document upload failed: ${putResponse.status} ${text || putResponse.statusText}`,
132
+ putResponse.status,
133
+ 'DOCUMENT_UPLOAD_FAILED',
134
+ );
135
+ }
136
+
137
+ return this.finalizeDocument(kbId, document.id);
138
+ }
139
+
140
+ /**
141
+ * Poll a document until it reaches `ready` or `failed` status, or the
142
+ * timeout elapses. Throws {@link SpekoApiError} on `failed` (with the
143
+ * server's `errorMessage`) or on timeout.
144
+ */
145
+ async pollDocumentReady(
146
+ kbId: string,
147
+ docId: string,
148
+ opts: KnowledgeBaseDocumentPollOptions = {},
149
+ ): Promise<KnowledgeBaseDocumentRow> {
150
+ const intervalMs = opts.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
151
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
152
+ const deadline = Date.now() + timeoutMs;
153
+
154
+ while (Date.now() < deadline) {
155
+ const doc = await this.getDocument(kbId, docId);
156
+ if (doc.status === 'ready') return doc;
157
+ if (doc.status === 'failed') {
158
+ throw new SpekoApiError(
159
+ doc.errorMessage ?? 'Document ingest failed',
160
+ 500,
161
+ 'DOCUMENT_INGEST_FAILED',
162
+ );
163
+ }
164
+ await delay(intervalMs);
165
+ }
166
+
167
+ throw new SpekoApiError(
168
+ `Document ingest timed out after ${timeoutMs}ms`,
169
+ 408,
170
+ 'DOCUMENT_INGEST_TIMEOUT',
171
+ );
172
+ }
173
+ }
174
+
175
+ function byteLengthOf(data: ArrayBuffer | Uint8Array | Blob): number {
176
+ if (data instanceof Blob) return data.size;
177
+ if (data instanceof Uint8Array) return data.byteLength;
178
+ return data.byteLength;
179
+ }
180
+
181
+ function toBodyInit(data: ArrayBuffer | Uint8Array | Blob): Blob | ArrayBuffer {
182
+ if (data instanceof Blob) return data;
183
+ if (data instanceof Uint8Array) {
184
+ return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) as ArrayBuffer;
185
+ }
186
+ return data;
187
+ }
188
+
189
+ async function safeReadText(r: Response): Promise<string> {
190
+ try {
191
+ return await r.text();
192
+ } catch {
193
+ return '';
194
+ }
195
+ }
196
+
197
+ function delay(ms: number): Promise<void> {
198
+ return new Promise((resolve) => setTimeout(resolve, ms));
199
+ }
@@ -0,0 +1,109 @@
1
+ import type { HttpClient } from '../http.js';
2
+ import type {
3
+ AvailablePhoneNumber,
4
+ PhoneNumberCreateParams,
5
+ PhoneNumberImportSipTrunkParams,
6
+ PhoneNumberKybDraftParams,
7
+ PhoneNumberKybOverview,
8
+ PhoneNumberKybSubmission,
9
+ PhoneNumberKybSubmitParams,
10
+ PhoneNumberRow,
11
+ PhoneNumberSearchParams,
12
+ PhoneNumberUpdateParams,
13
+ } from '../types/index.js';
14
+
15
+ /**
16
+ * Phone numbers Speko has provisioned as managed numbers or registered
17
+ * from your own SIP trunk. Each number can be used for outbound dialing
18
+ * and/or inbound, and carries an optional metadata template that's
19
+ * merged into the worker dispatch payload when the number is used.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * // List org's numbers
24
+ * const numbers = await speko.phoneNumbers.list();
25
+ *
26
+ * // Provision a new US local number
27
+ * const num = await speko.phoneNumbers.create({
28
+ * e164: '+12015551234',
29
+ * direction: 'both',
30
+ * label: 'Sales line',
31
+ * dispatchMetadataTemplate: {
32
+ * intent: { language: 'en', optimizeFor: 'latency' },
33
+ * systemPrompt: 'You are a helpful sales agent for Acme.',
34
+ * },
35
+ * });
36
+ * ```
37
+ */
38
+ export class PhoneNumbers {
39
+ constructor(private readonly http: HttpClient) {}
40
+
41
+ list(): Promise<PhoneNumberRow[]> {
42
+ return this.http.get<PhoneNumberRow[]>('/v1/phone-numbers');
43
+ }
44
+
45
+ /**
46
+ * Search the platform-managed pool for orderable US numbers. Filter by area code
47
+ * and/or locality. Results include cost so you can preview "$1 upfront +
48
+ * $1/month" before committing to {@link create}.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const candidates = await speko.phoneNumbers.searchAvailable({ areaCode: '415' });
53
+ * console.log(candidates[0].friendlyName); // "+1 (415) 555-0123"
54
+ * ```
55
+ */
56
+ searchAvailable(params: PhoneNumberSearchParams = {}): Promise<AvailablePhoneNumber[]> {
57
+ const query = new URLSearchParams();
58
+ if (params.areaCode) query.set('areaCode', params.areaCode);
59
+ if (params.locality) query.set('locality', params.locality);
60
+ if (params.limit !== undefined) query.set('limit', String(params.limit));
61
+ const qs = query.toString();
62
+ return this.http.get<AvailablePhoneNumber[]>(
63
+ `/v1/phone-numbers/available${qs ? `?${qs}` : ''}`,
64
+ );
65
+ }
66
+
67
+ get(id: string): Promise<PhoneNumberRow> {
68
+ return this.http.get<PhoneNumberRow>(`/v1/phone-numbers/${encodeURIComponent(id)}`);
69
+ }
70
+
71
+ create(params: PhoneNumberCreateParams): Promise<PhoneNumberRow> {
72
+ return this.http.post<PhoneNumberRow>('/v1/phone-numbers', params);
73
+ }
74
+
75
+ importSipTrunk(params: PhoneNumberImportSipTrunkParams): Promise<PhoneNumberRow> {
76
+ return this.http.post<PhoneNumberRow>('/v1/phone-numbers/import', params);
77
+ }
78
+
79
+ update(id: string, params: PhoneNumberUpdateParams): Promise<PhoneNumberRow> {
80
+ return this.http.patch<PhoneNumberRow>(`/v1/phone-numbers/${encodeURIComponent(id)}`, params);
81
+ }
82
+
83
+ delete(id: string): Promise<{ released: boolean }> {
84
+ return this.http.delete<{ released: boolean }>(`/v1/phone-numbers/${encodeURIComponent(id)}`);
85
+ }
86
+
87
+ /**
88
+ * Read business verification state used to gate managed phone-number purchases.
89
+ * Includes the latest submission plus any SMS 10DLC-derived prefill.
90
+ */
91
+ getKyb(): Promise<PhoneNumberKybOverview> {
92
+ return this.http.get<PhoneNumberKybOverview>('/v1/phone-numbers/kyb');
93
+ }
94
+
95
+ /**
96
+ * Save a draft business verification submission without sending it for review.
97
+ */
98
+ saveKybDraft(params: PhoneNumberKybDraftParams): Promise<PhoneNumberKybSubmission> {
99
+ return this.http.put<PhoneNumberKybSubmission>('/v1/phone-numbers/kyb/draft', params);
100
+ }
101
+
102
+ /**
103
+ * Submit a business declaration for asynchronous review. A current minimal
104
+ * declaration enables purchasing immediately; the legacy full profile remains accepted.
105
+ */
106
+ submitKyb(params: PhoneNumberKybSubmitParams): Promise<PhoneNumberKybSubmission> {
107
+ return this.http.post<PhoneNumberKybSubmission>('/v1/phone-numbers/kyb/submit', params);
108
+ }
109
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Minimal ambient declarations for the WebSocket global. The SDK targets
3
+ * browsers primarily (audio capture needs a MediaStream), but lib.dom.d.ts
4
+ * conflicts with our fetch-with-Uint8Array body calls in http.ts. Declaring
5
+ * just the subset we need sidesteps the conflict.
6
+ */
7
+
8
+ interface WebSocketMessageEvent<T = unknown> {
9
+ readonly data: T;
10
+ }
11
+
12
+ interface WebSocketCloseEvent {
13
+ readonly code: number;
14
+ readonly reason: string;
15
+ }
16
+
17
+ interface WebSocket {
18
+ readonly readyState: 0 | 1 | 2 | 3;
19
+ binaryType: 'arraybuffer' | 'blob';
20
+ send(data: string | ArrayBufferLike | ArrayBufferView | Blob): void;
21
+ close(code?: number, reason?: string): void;
22
+ addEventListener(type: 'message', listener: (evt: WebSocketMessageEvent) => void): void;
23
+ addEventListener(type: 'close', listener: (evt: WebSocketCloseEvent) => void): void;
24
+ addEventListener(type: 'open' | 'error', listener: () => void): void;
25
+ }
26
+
27
+ interface WebSocketConstructor {
28
+ new (url: string, protocols?: string | string[]): WebSocket;
29
+ }
30
+
31
+ declare const WebSocket: WebSocketConstructor;