@signalhousellc/sdk 1.0.51 → 1.0.53

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/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@signalhousellc/sdk",
3
- "version": "1.0.51",
3
+ "version": "1.0.53",
4
4
  "description": "Signal House SDK for use with the Signal House platform",
5
5
  "type": "module",
6
6
  "main": "src/SignalHouseSDK.js",
7
7
  "exports": {
8
- ".": "./src/SignalHouseSDK.js"
8
+ ".": "./src/SignalHouseSDK.js",
9
+ "./voice-browser": "./src/domains/voice/browser/index.js"
9
10
  },
10
11
  "files": [
11
12
  "src/",
@@ -15,5 +16,13 @@
15
16
  "license": "ISC",
16
17
  "dependencies": {
17
18
  "axios": "^1.13.5"
19
+ },
20
+ "peerDependencies": {
21
+ "jssip": "^3.13.0"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "jssip": {
25
+ "optional": true
26
+ }
18
27
  }
19
28
  }
@@ -22,6 +22,7 @@ import { Subscriptions } from "./domains/Subscriptions.js";
22
22
  import { Users } from "./domains/Users.js";
23
23
  import { Notifications } from "./domains/Notifications.js";
24
24
  import { Webhooks } from "./domains/Webhooks.js";
25
+ import { Voice } from "./domains/Voice.js";
25
26
 
26
27
  export class SignalHouseSDK {
27
28
  /**
@@ -29,6 +30,7 @@ export class SignalHouseSDK {
29
30
  * @param {Object} config - The configuration object for initializing the SDK
30
31
  * @param {string} config.apiKey - The API key for authenticating requests to the SignalHouse API
31
32
  * @param {string} config.baseUrl - The base URL for the SignalHouse API (e.g., "https://api.signalhouse.com")
33
+ * @param {boolean} [config.enableAdmin=false] - Enable admin-scoped behaviors on domains that support them.
32
34
  * @throws {Error} Throws an error if the API key or base URL is missing from the configuration
33
35
  * @returns {SignalHouseSDK} An instance of the SignalHouseSDK
34
36
  */
@@ -66,6 +68,9 @@ export class SignalHouseSDK {
66
68
  this.users = new Users(client, this.enableAdmin);
67
69
  this.notifications = new Notifications(client, this.enableAdmin);
68
70
  this.webhooks = new Webhooks(client, this.enableAdmin);
71
+ // Voice domain targets the voice-backend service under /voice. Available
72
+ // like any other domain; gating (if any) will be decided later.
73
+ this.voice = new Voice(client, this.enableAdmin);
69
74
  }
70
75
 
71
76
  /**
@@ -58,6 +58,37 @@ export class Auth {
58
58
  return this.client(`/auth/verify-email`, { method: "POST", body: { token }, ...options });
59
59
  }
60
60
 
61
+ /**
62
+ * Request a password-reset link be emailed to the given address (public). Always resolves
63
+ * successfully regardless of whether an account exists for the email, so it cannot be used to
64
+ * enumerate registered emails.
65
+ * @async
66
+ * @roles public
67
+ * @param {Object} params
68
+ * @param {string} params.email - The email address to send a reset link to
69
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
70
+ * @returns {Promise<Object>} The response from the server ({ success: true })
71
+ */
72
+ async forgotPassword({ email, options = {} }) {
73
+ this.client._require({ email });
74
+ return this.client(`/auth/forgot-password`, { method: "POST", body: { email }, ...options });
75
+ }
76
+
77
+ /**
78
+ * Reset a password using the single-use token from a password-reset email link (public)
79
+ * @async
80
+ * @roles public
81
+ * @param {Object} params
82
+ * @param {string} params.token - The single-use reset token from the email link
83
+ * @param {string} params.password - The new password to set (min 8 characters)
84
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
85
+ * @returns {Promise<Object>} The response from the server ({ success: true })
86
+ */
87
+ async resetPasswordWithToken({ token, password, options = {} }) {
88
+ this.client._require({ token, password });
89
+ return this.client(`/auth/reset-password`, { method: "POST", body: { token, password }, ...options });
90
+ }
91
+
61
92
  /**
62
93
  * Resend the account verification email to the authenticated caller
63
94
  * @async
@@ -115,4 +146,19 @@ export class Auth {
115
146
  async logoutAll({ options = {} } = {}) {
116
147
  return this.client(`/auth/logout-all`, { method: "POST", ...options });
117
148
  }
149
+
150
+ /**
151
+ * Mint a single-use, short-lived external-link token for the authenticated caller. The token is
152
+ * handed to the GHL/Shopify backend so it can link the caller's existing V2 group to its tenant.
153
+ * @async
154
+ * @roles admin, developer, billing, user
155
+ * @param {Object} params
156
+ * @param {string} params.product - The external system to link to ("ghl" or "shopify")
157
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
158
+ * @returns {Promise<Object>} The response from the server ({ token })
159
+ */
160
+ async requestExternalLinkToken({ product, options = {} }) {
161
+ this.client._require({ product });
162
+ return this.client(`/auth/external-link-token`, { method: "POST", body: { product }, ...options });
163
+ }
118
164
  }
@@ -53,6 +53,42 @@
53
53
  * @property {string} [altBusinessIdType] - The type of the alternative business identifier ("NONE", "DUNS", "LEI", "GIIN")
54
54
  * @property {string} [brandRelationship] - Not in use - reserved for future use
55
55
  * @property {string} [businessContactEmail] - The email address of the business contact for the brand (required if entityType is PUBLIC_PROFIT or NON_PROFIT)
56
+ * @property {Object} [tollFree] - Toll-Free editable fields, used when updating a Toll-Free brand. Optional sub-fields: legalEntityType, businessRegistrationType, taxId, countryCode, supportPhone, taxIdIssuingCountry, businessDBA. (Toll-Free brands sync to Infobip; only DCA_PENDING/DCA_ACTIVE brands are editable and subgroupId is immutable.)
57
+ */
58
+
59
+ /**
60
+ * @typedef {Object} TollFreeBrandDetails
61
+ * @property {string} businessRegistrationType - The business registration type (required, one of EIN, CBN, NEQ, PROVINCIAL_NUMBER, CRN, VAT, ACN, ABN, BRN, SIREN, SIRET, NZBN, UST_IDNR, CIF, NIF, CNPJ, UID, OTHER)
62
+ * @property {string} legalEntityType - The legal entity type (required, one of PRIVATE_COMPANY, PUBLIC_COMPANY, NON_PROFIT, GOVERNMENT, SOLE_PROPRIETOR)
63
+ * @property {string} taxId - The business tax identifier (required, at most 50 characters)
64
+ * @property {string} countryCode - The business country code (required, 2-letter ISO code)
65
+ * @property {string} supportPhone - The customer-support phone number (required, at most 20 characters)
66
+ * @property {string} [taxIdIssuingCountry] - The country that issued the tax ID (optional, 2-letter ISO code)
67
+ * @property {string} [businessDBA] - The business "doing business as" name (optional, at most 255 characters)
68
+ */
69
+
70
+ /**
71
+ * @typedef {Object} CreateTollFreeBrandData
72
+ * @property {string} subgroupId - The ID of the subgroup to create the brand under (required, exactly 8 characters)
73
+ * @property {string} displayName - The display name for the brand (required, at most 255 characters)
74
+ * @property {string} companyName - The company name for the brand (required, at most 255 characters)
75
+ * @property {string} street - The street address of the primary contact for the brand (required, at most 255 characters)
76
+ * @property {string} city - The city of the primary contact for the brand (required, at most 100 characters)
77
+ * @property {string} state - The state of the primary contact for the brand (required, at most 20 characters; must be a valid 2-letter US state code when country is "US")
78
+ * @property {string} postalCode - The postal code of the primary contact for the brand (required, at most 10 characters)
79
+ * @property {string} email - The email address of the primary contact for the brand (required, valid email, at most 100 characters)
80
+ * @property {string} firstName - The first name of the primary contact for the brand (required, at most 100 characters)
81
+ * @property {string} lastName - The last name of the primary contact for the brand (required, at most 100 characters)
82
+ * @property {string} website - The website URL for the brand (required, valid URL, at most 255 characters)
83
+ * @property {TollFreeBrandDetails} tollFree - The Toll-Free brand details (required)
84
+ * @property {string} [referenceId] - A unique reference for the brand (optional, at most 50 characters)
85
+ * @property {Array<string>} [tag] - An array of tags to associate with the brand (optional)
86
+ * @property {boolean} [mock] - Whether to create the brand in the mock environment (for testing purposes only)
87
+ * @property {string} [optInLink] - A URL linking to the opt-in flow for the brand (optional, valid URL, at most 255 characters)
88
+ * @property {string} [privacyPolicyLink] - A URL linking to the privacy policy for the brand (optional, valid URL, at most 255 characters)
89
+ * @property {string} [termsAndConditionsLink] - A URL linking to the terms and conditions for the brand (optional, valid URL, at most 255 characters)
90
+ * @property {string} [landingId] - The ID of the landing page associated with the brand (optional)
91
+ * @property {string} [country] - The country code of the primary contact for the brand (optional, 2-letter code; when "US", state must be a valid 2-letter US state code)
56
92
  */
57
93
 
58
94
  export class Brands {
@@ -73,11 +109,12 @@ export class Brands {
73
109
  * @param {number} [params.page] - The page number for pagination
74
110
  * @param {number} [params.limit] - The number of items per page
75
111
  * @param {string} [params.status] - The status of the brand to filter by (PENDING_CREATION, PENDING_APPROVAL, UNVERIFIED, VERIFIED, VETTED_VERIFIED, PENDING_DELETE, DELETED)
112
+ * @param {string} [params.registrationType] - Filter by registration type ("TEN_DLC" or "TOLL_FREE")
76
113
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
77
114
  * @returns {Promise<Array>} The response from the server
78
115
  */
79
- async getBrands({ id, subgroupId, groupId, page, limit, status, options = {} }) {
80
- const filters = { id, subgroupId, groupId, page, limit, status };
116
+ async getBrands({ id, subgroupId, groupId, page, limit, status, registrationType, options = {} }) {
117
+ const filters = { id, subgroupId, groupId, page, limit, status, registrationType };
81
118
  const queryString = this.client._getQueryString(filters);
82
119
  return this.client(`/brand${queryString}`, { method: "GET", ...options });
83
120
  }
@@ -113,6 +150,21 @@ export class Brands {
113
150
  return this.client(`/brand`, { method: "POST", body: brandData, ...options });
114
151
  }
115
152
 
153
+ /**
154
+ * Create a new Toll-Free (TFN) brand
155
+ * @async
156
+ * @roles api, admin, developer, billing, user
157
+ * @param {Object} params - The parameters for creating the toll-free brand
158
+ * @param {CreateTollFreeBrandData} params.brandData - The data for the toll-free brand to be created (see CreateTollFreeBrandData typedef for details; TFN-specific fields live under brandData.tollFree, and registrationType is forced server-side by the route)
159
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
160
+ * @throws {Error} Throws an error if the brandData parameter is missing
161
+ * @returns {Promise<Object>} The response from the server
162
+ */
163
+ async createTollFreeBrand({ brandData, options = {} }) {
164
+ this.client._require({ brandData });
165
+ return this.client(`/brand/toll-free`, { method: "POST", body: brandData, ...options });
166
+ }
167
+
116
168
  /**
117
169
  * Transfer one or more brands to a different subgroup
118
170
  * @async
@@ -64,6 +64,41 @@
64
64
  * @property {string} [privacyPolicyLink] - A URL linking to the privacy policy for the campaign (optional, must be at most 2048 characters if provided)
65
65
  * @property {string} [termsAndConditionsLink] - A URL linking to the terms and conditions for the campaign (optional, must be at most 2048 characters if provided)
66
66
  * @property {string} [embeddedLinkSample] - A sample of the embedded link used in the campaign (optional, must be at most 255 characters if provided)
67
+ * @property {Object} [tollFree] - Toll-Free editable fields, used when updating a Toll-Free campaign. Mirrors the CreateTollFreeCampaignData `tollFree` object with every field optional (useCase, messageVolume, programSummary (≤500), exampleMessage, customerCareEmail, optInImageURLs, optIns, multiNumberReason (≤500)). Phone numbers cannot be changed via update — Toll-Free numbers are locked to their campaign.
68
+ */
69
+
70
+ /**
71
+ * @typedef {Object} TollFreeOptIn
72
+ * @property {string} [callToAction] - The opt-in call-to-action text for this channel (optional, at most 2048 characters)
73
+ * @property {string} [url] - The opt-in web URL (web channel only, optional, at most 2048 characters)
74
+ * @property {Array<string>} [keywords] - The opt-in keywords (keyword channel only, optional)
75
+ */
76
+
77
+ /**
78
+ * @typedef {Object} TollFreeCampaignDetails
79
+ * @property {string} useCase - The Toll-Free use case (required, e.g. TWO_FA, GENERAL_MARKETING, HEALTHCARE, MIXED — one of the Toll-Free use-case values)
80
+ * @property {string} messageVolume - The estimated monthly message volume tier (required, one of TEN, HUNDRED, THOUSAND, TEN_THOUSAND, HUNDRED_THOUSAND, TWO_HUNDRED_FIFTY_THOUSAND, FIVE_HUNDRED_THOUSAND, SEVEN_HUNDRED_FIFTY_THOUSAND, ONE_MILLION, FIVE_MILLION, TEN_MILLION_PLUS)
81
+ * @property {string} programSummary - A summary of the messaging program (required, at most 500 characters)
82
+ * @property {string} exampleMessage - An example message (required, at most 4096 characters; stored verbatim, no STOP/HELP appended by the server)
83
+ * @property {string} customerCareEmail - A customer-care contact email (required, valid email)
84
+ * @property {Array<string>} optInImageURLs - URLs to opt-in proof images (required, at least one, each at most 2048 characters)
85
+ * @property {Object} [optIns] - Opt-in method details. Each channel is optional.
86
+ * @property {TollFreeOptIn} [optIns.verbal] - Verbal opt-in details
87
+ * @property {TollFreeOptIn} [optIns.web] - Online (web) opt-in details
88
+ * @property {TollFreeOptIn} [optIns.keyword] - Keyword opt-in details
89
+ * @property {TollFreeOptIn} [optIns.interactiveVoiceResponse] - IVR opt-in details
90
+ * @property {string} [multiNumberReason] - Internally-stored reason the customer requested more than one Toll-Free number on the campaign (optional, at most 500 characters). Required when more than one phone number is assigned; captured for Signal House review only and never sent to the carrier.
91
+ */
92
+
93
+ /**
94
+ * @typedef {Object} CreateTollFreeCampaignData
95
+ * @property {string} brandId - The ID of the Toll-Free brand associated with the campaign (required, at least 7 characters)
96
+ * @property {TollFreeCampaignDetails} tollFree - The Toll-Free campaign details (required)
97
+ * @property {string} [privacyPolicyLink] - A URL linking to the privacy policy (optional, at most 2048 characters)
98
+ * @property {string} [termsAndConditionsLink] - A URL linking to the terms and conditions (optional, at most 2048 characters)
99
+ * @property {string} [tag] - A tag for the campaign (optional, at most 255 characters)
100
+ * @property {boolean} [autoRenewal=true] - Whether the campaign should auto-renew (optional, defaults to true)
101
+ * @property {Array<string>} phoneNumbers - The Toll-Free numbers to assign to the campaign (required, at least 1 and at most 5, each at least 10 digits and digits only). Numbers are locked to the campaign once assigned and cannot be moved or added afterward.
67
102
  */
68
103
 
69
104
  export class Campaigns {
@@ -133,11 +168,12 @@ export class Campaigns {
133
168
  * @param {string} [params.search] - Search term to filter campaigns by campaignId or brandId
134
169
  * @param {string} [params.sortBy] - Field to sort by (e.g. "createdAt", "campaignId", "brandId", "groupId", "subgroupId", "usecase", "status")
135
170
  * @param {string} [params.sortOrder] - Sort direction ("asc" or "desc")
171
+ * @param {string} [params.registrationType] - Filter by registration type ("TEN_DLC" or "TOLL_FREE")
136
172
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
137
173
  * @returns {Promise<Array|Object>} The response from the server - array when unpaginated, or { data, total, page, limit, totalPages } when paginated
138
174
  */
139
- async getCampaigns({ id, brandId, subgroupId, groupId, page, limit, status, search, sortBy, sortOrder, options = {} }) {
140
- const filters = { id, brandId, subgroupId, groupId, page, limit, status, search, sortBy, sortOrder };
175
+ async getCampaigns({ id, brandId, subgroupId, groupId, page, limit, status, search, sortBy, sortOrder, registrationType, options = {} }) {
176
+ const filters = { id, brandId, subgroupId, groupId, page, limit, status, search, sortBy, sortOrder, registrationType };
141
177
  const queryString = this.client._getQueryString(filters);
142
178
  return this.client(`/campaign${queryString}`, { method: "GET", ...options });
143
179
  }
@@ -157,6 +193,21 @@ export class Campaigns {
157
193
  return this.client(`/campaign`, { method: "POST", body: campaignData, ...options });
158
194
  }
159
195
 
196
+ /**
197
+ * Create a new Toll-Free (TFN) campaign and submit it for Signal House review
198
+ * @async
199
+ * @roles api, admin, developer, user
200
+ * @param {Object} params - The parameters for creating the toll-free campaign
201
+ * @param {CreateTollFreeCampaignData} params.campaignData - The data for the toll-free campaign to be created (see CreateTollFreeCampaignData typedef for details)
202
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
203
+ * @throws {Error} Throws an error if the campaignData parameter is missing
204
+ * @returns {Promise<Object>} The response from the server
205
+ */
206
+ async createTollFreeCampaign({ campaignData, options = {} }) {
207
+ this.client._require({ campaignData });
208
+ return this.client(`/campaign/toll-free`, { method: "POST", body: campaignData, ...options });
209
+ }
210
+
160
211
  /**
161
212
  * Update an existing campaign
162
213
  * @async
@@ -52,6 +52,30 @@ export class Groups {
52
52
  const safeGroupId = encodeURIComponent(groupId);
53
53
  return this.client(`/group/${safeGroupId}`, { method: "DELETE", ...options });
54
54
  },
55
+
56
+ /**
57
+ * Link an external tenant (GHL/Shopify) to a V2 group (server-to-server). Exchanges a
58
+ * single-use link token for a canonical group, adopting an empty portal group, repointing
59
+ * to an existing group, or flagging for manual review.
60
+ * @async
61
+ * @roles signalhouse
62
+ * @param {Object} params - The parameters for linking an external account
63
+ * @param {string} params.linkToken - The single-use external-link token minted by the portal user
64
+ * @param {string} params.externalSystem - The external system ("ghl" or "shopify")
65
+ * @param {string} params.externalId - The external tenant identifier
66
+ * @param {string} [params.existingGroupId] - An existing V2 group ID to repoint to, if any
67
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
68
+ * @throws {Error} Throws an error if linkToken, externalSystem, or externalId is missing
69
+ * @returns {Promise<Object>} - The link outcome ({ status, canonicalGroupId, ... })
70
+ */
71
+ linkExternal: async ({ linkToken, externalSystem, externalId, existingGroupId, options = {} }) => {
72
+ this.client._require({ linkToken, externalSystem, externalId });
73
+ return this.client(`/group/link-external`, {
74
+ method: "POST",
75
+ body: { linkToken, externalSystem, externalId, ...(existingGroupId ? { existingGroupId } : {}) },
76
+ ...options,
77
+ });
78
+ },
55
79
  };
56
80
  }
57
81
  }
@@ -111,6 +111,45 @@ export class Numbers {
111
111
  return this.client(`/number`, { method: "POST", body: { phoneNumbers, subgroupId }, ...options });
112
112
  }
113
113
 
114
+ /**
115
+ * Purchase one or more Toll-Free numbers via the asynchronous resource-request flow.
116
+ *
117
+ * Toll-Free numbers are ordered by quantity (not picked individually) and provisioned asynchronously;
118
+ * per-number completion is delivered via webhook/polling, not in this response. The returned `orderId`
119
+ * can be polled with {@link Numbers#getTollFreeOrderStatus} for the order's outcome.
120
+ * @async
121
+ * @roles api, admin, developer, billing, user
122
+ * @param {Object} params - The parameters for purchasing toll-free numbers
123
+ * @param {number} params.quantity - The number of toll-free numbers to purchase (1-10)
124
+ * @param {string} params.subgroupId - The subgroup the purchased numbers are assigned to
125
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
126
+ * @throws {Error} Throws an error if the quantity or subgroupId parameter is missing
127
+ * @returns {Promise<Object>} A promise that resolves to `{ message, orderId }` once the request is queued.
128
+ */
129
+ async purchaseTollFreeNumbers({ quantity, subgroupId, options = {} }) {
130
+ this.client._require({ quantity, subgroupId });
131
+ return this.client(`/number/toll-free`, { method: "POST", body: { quantity, subgroupId }, ...options });
132
+ }
133
+
134
+ /**
135
+ * Read the outcome of a Toll-Free number purchase by the `orderId` returned from
136
+ * {@link Numbers#purchaseTollFreeNumbers}. Reports per-number status as ready / provisioning / failed
137
+ * counts (plus failure reasons) so a client can poll until the order reaches a terminal state. The
138
+ * provisioned numbers themselves appear in the regular numbers list as they materialize.
139
+ * @async
140
+ * @roles api, admin, developer, billing, user
141
+ * @param {Object} params - The parameters for reading the order status
142
+ * @param {string} params.orderId - The order id returned by `purchaseTollFreeNumbers`
143
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
144
+ * @throws {Error} Throws an error if the orderId parameter is missing
145
+ * @returns {Promise<Object>} A promise that resolves to `{ orderId, counts: { ready, provisioning, failed }, failures: [{ reason }] }`.
146
+ */
147
+ async getTollFreeOrderStatus({ orderId, options = {} }) {
148
+ this.client._require({ orderId });
149
+ const safeOrderId = encodeURIComponent(orderId);
150
+ return this.client(`/number/toll-free/order/${safeOrderId}`, { method: "GET", ...options });
151
+ }
152
+
114
153
  /**
115
154
  * Update an existing phone number's details (e.g., setting a friendly name)
116
155
  * @async
@@ -0,0 +1,26 @@
1
+ import { SipTrunks } from "./voice/SipTrunks.js";
2
+ import { SipProfiles } from "./voice/SipProfiles.js";
3
+ import { Calls } from "./voice/Calls.js";
4
+ import { Tokens } from "./voice/Tokens.js";
5
+
6
+ /**
7
+ * Voice domain — wraps the voice-backend service (mounted under /voice on the
8
+ * platform host). Groups all voice-service sub-resources under a single
9
+ * namespace, accessed via `sdk.voice.*`.
10
+ *
11
+ * Sub-resources:
12
+ * - `sdk.voice.sipTrunks` — SIP trunk (peer-to-peer connections to PBX/carrier).
13
+ * - `sdk.voice.sipProfiles` — SIP profile / endpoint (single registerable UA).
14
+ * - `sdk.voice.calls` — Outbound call origination + call log queries.
15
+ * - `sdk.voice.tokens` — Mint ephemeral SIP credentials for the browser voice SDK.
16
+ */
17
+ export class Voice {
18
+ constructor(client, enableAdmin) {
19
+ this.client = client;
20
+ this.enableAdmin = enableAdmin;
21
+ this.sipTrunks = new SipTrunks(client, enableAdmin);
22
+ this.sipProfiles = new SipProfiles(client, enableAdmin);
23
+ this.calls = new Calls(client, enableAdmin);
24
+ this.tokens = new Tokens(client, enableAdmin);
25
+ }
26
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * @typedef {Object} CreateCallData
3
+ * @property {string} to - Destination phone number in E.164 format (e.g. "+15551234567") or SIP URI.
4
+ * @property {string} from - Caller ID to present on the outbound leg. Must be an account-owned phone number when not using a SIP trunk.
5
+ * @property {string} [sip_trunk_id] - Route via a configured SIP trunk. Mutually exclusive with `sip_profile_id` and `to_identity` for the trunk path.
6
+ * @property {string} [sip_profile_id] - Two-leg-with-bridge: ring this persistent SIP profile first, then dial `to` and bridge. Mutually exclusive with `to_identity`.
7
+ * @property {string} [to_identity] - Two-leg-with-bridge: ring the SDK-registered identity by logical name (the value passed to `tokens.create({identity})`), then dial `to` and bridge. Mutually exclusive with `sip_profile_id`.
8
+ * @property {string} [answer_url] - Webhook URL fetched on call answer; returns call-control instructions.
9
+ * @property {"GET"|"POST"} [answer_method] - HTTP method for `answer_url`. Defaults to POST.
10
+ * @property {string} [status_callback] - Webhook URL for call status updates (QUEUED, RINGING, ANSWERED, COMPLETED, FAILED).
11
+ * @property {"GET"|"POST"} [status_callback_method] - HTTP method for `status_callback`. Defaults to POST.
12
+ * @property {boolean} [recording_enabled] - Record both legs of the call. Defaults to false.
13
+ * @property {boolean} [transcription_enabled] - Transcribe the recording. Defaults to false.
14
+ * @property {string} [ivr_flow_id] - Route the call into an AI IVR flow on answer instead of webhook control.
15
+ * @property {Object} [metadata] - Free-form metadata persisted on the call log.
16
+ */
17
+
18
+ /**
19
+ * @typedef {Object} ListCallsFilters
20
+ * @property {number} [page] - Page number (1-indexed). Defaults to 1.
21
+ * @property {number} [limit] - Page size (1-100). Defaults to 20.
22
+ * @property {"QUEUED"|"RINGING"|"IN_PROGRESS"|"COMPLETED"|"FAILED"|"BUSY"|"NO_ANSWER"|"CANCELED"} [status] - Filter by call status.
23
+ * @property {"INBOUND"|"OUTBOUND"} [direction] - Filter by call direction.
24
+ * @property {string} [from] - Filter by caller number.
25
+ * @property {string} [to] - Filter by destination number.
26
+ * @property {string} [date_from] - ISO-8601 lower bound on start_time.
27
+ * @property {string} [date_to] - ISO-8601 upper bound on start_time.
28
+ */
29
+
30
+ /**
31
+ * Voice calls. REST API for placing outbound calls and inspecting call logs.
32
+ * Wraps voice-backend's `/voice/v1/calls` surface. Accessed via `sdk.voice.calls`.
33
+ *
34
+ * Origination modes:
35
+ * - **Single-leg** (no trunk/profile/identity): Twilio-style direct outbound — dial `to` from caller-ID `from`. Customer's `from` must be an account-owned number.
36
+ * - **SIP trunk** (`sip_trunk_id`): Route via a configured trunk; the trunk's auth/ACL governs caller-ID rules.
37
+ * - **Two-leg-with-bridge** (`sip_profile_id` OR `to_identity`): Ring the SDK-registered endpoint first, then dial `to` and bridge. `to_identity` resolves to the most recently-minted unexpired ephemeral identity for that name.
38
+ */
39
+ export class Calls {
40
+ constructor(client, enableAdmin) {
41
+ this.client = client;
42
+ this.enableAdmin = enableAdmin;
43
+ }
44
+
45
+ /**
46
+ * Create an outbound call.
47
+ * @async
48
+ * @roles api, admin, developer, billing, user
49
+ * @param {Object} params - Request parameters.
50
+ * @param {CreateCallData} params.callData - The call to place.
51
+ * @param {import('../../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request.
52
+ * @throws {Error} If callData is missing.
53
+ * @returns {Promise<Object>} The created call: `{ call_id, status, direction, from, to, created_at }`.
54
+ */
55
+ async create({ callData, options = {} }) {
56
+ this.client._require({ callData });
57
+ return this.client(`/voice/v1/calls`, { method: "POST", body: callData, ...options });
58
+ }
59
+
60
+ /**
61
+ * List call logs for the current account, paginated and filterable.
62
+ * @async
63
+ * @roles api, admin, developer, billing, user
64
+ * @param {Object} [params] - Request parameters.
65
+ * @param {ListCallsFilters} [params.filters] - Optional filters.
66
+ * @param {import('../../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request.
67
+ * @returns {Promise<Object>} `{ calls: [...], total, page, limit }`.
68
+ */
69
+ async list({ filters = {}, options = {} } = {}) {
70
+ const query = new URLSearchParams();
71
+ for (const [k, v] of Object.entries(filters)) {
72
+ if (v !== undefined && v !== null && v !== "") query.set(k, String(v));
73
+ }
74
+ const qs = query.toString();
75
+ const path = qs ? `/voice/v1/calls?${qs}` : `/voice/v1/calls`;
76
+ return this.client(path, { method: "GET", ...options });
77
+ }
78
+
79
+ /**
80
+ * Get a single call log by ID.
81
+ * @async
82
+ * @roles api, admin, developer, billing, user
83
+ * @param {Object} params - Request parameters.
84
+ * @param {string} params.id - The call log UUID (the value returned as `call_id` from `create`).
85
+ * @param {import('../../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request.
86
+ * @throws {Error} If id is missing.
87
+ * @returns {Promise<Object>} The call log.
88
+ */
89
+ async get({ id, options = {} }) {
90
+ this.client._require({ id });
91
+ const safeId = encodeURIComponent(id);
92
+ return this.client(`/voice/v1/calls/${safeId}`, { method: "GET", ...options });
93
+ }
94
+
95
+ /**
96
+ * Hang up an in-progress call.
97
+ * @async
98
+ * @roles api, admin, developer, billing, user
99
+ * @param {Object} params - Request parameters.
100
+ * @param {string} params.id - The call log UUID.
101
+ * @param {"NORMAL"|"BUSY"|"NO_ANSWER"|"REJECTED"} [params.reason] - Hangup reason recorded on the call log. Defaults to NORMAL.
102
+ * @param {import('../../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request.
103
+ * @throws {Error} If id is missing.
104
+ * @returns {Promise<Object>} `{ success: boolean, message: string }`.
105
+ */
106
+ async hangup({ id, reason, options = {} }) {
107
+ this.client._require({ id });
108
+ const safeId = encodeURIComponent(id);
109
+ const body = reason ? { reason } : {};
110
+ return this.client(`/voice/v1/calls/${safeId}/hangup`, { method: "POST", body, ...options });
111
+ }
112
+ }