@drawbridge/drawbridge-utils 0.0.133 → 0.0.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/connections/index.cjs +81 -5
- package/dist/connections/index.d.cts +100 -4
- package/dist/connections/index.d.ts +100 -4
- package/dist/connections/index.js +81 -5
- package/dist/connections/oauth.cjs +8 -2
- package/dist/connections/oauth.d.cts +14 -3
- package/dist/connections/oauth.d.ts +14 -3
- package/dist/connections/oauth.js +8 -2
- package/dist/providers.cjs +81 -5
- package/dist/providers.js +81 -5
- package/dist/twilio.cjs +145 -7
- package/dist/twilio.d.cts +188 -7
- package/dist/twilio.d.ts +188 -7
- package/dist/twilio.js +145 -7
- package/package.json +1 -1
package/dist/twilio.d.ts
CHANGED
|
@@ -70,14 +70,23 @@ const twilio = {
|
|
|
70
70
|
// NUMBER LIFECYCLE, same transport discipline as sms above. Endpoints and
|
|
71
71
|
// parameter names are Twilio's own, from the AvailablePhoneNumbers and
|
|
72
72
|
// IncomingPhoneNumbers resource docs:
|
|
73
|
-
// GET /2010-04-01/Accounts/{AccountSid}/AvailablePhoneNumbers/{CountryCode}/
|
|
74
|
-
// query: SmsEnabled,
|
|
73
|
+
// GET /2010-04-01/Accounts/{AccountSid}/AvailablePhoneNumbers/{CountryCode}/TollFree.json
|
|
74
|
+
// query: SmsEnabled, Contains, PageSize (1-1000)
|
|
75
75
|
// POST /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json
|
|
76
76
|
// body: PhoneNumber (E.164), SmsUrl, SmsMethod
|
|
77
77
|
// DELETE /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers/{Sid}.json
|
|
78
78
|
// Basic auth throughout, like Messages.
|
|
79
|
+
//
|
|
80
|
+
// TOLL-FREE, not Local, and that is a carrier-registration decision rather
|
|
81
|
+
// than an inventory one. A US local number may not send A2P SMS without full
|
|
82
|
+
// 10DLC brand-and-campaign registration; a toll-free number needs only
|
|
83
|
+
// Toll-Free Verification — one API submission per number (see
|
|
84
|
+
// submitVerification below), no TCR brand, no campaign fees. Until a
|
|
85
|
+
// verification is approved, Twilio blocks the number's US-bound messages
|
|
86
|
+
// outright — which is why a purchased number starts `pending` and the send
|
|
87
|
+
// path refuses anything but `verified`.
|
|
79
88
|
|
|
80
|
-
searchNumbers : async ({ accountSid,
|
|
89
|
+
searchNumbers : async ({ accountSid, authToken, contains, country = 'US', cursor, limit = 10, request: request$1 = request }) => {
|
|
81
90
|
|
|
82
91
|
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
83
92
|
|
|
@@ -93,17 +102,17 @@ const twilio = {
|
|
|
93
102
|
|
|
94
103
|
const result = await request$1({
|
|
95
104
|
method : 'GET',
|
|
96
|
-
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/AvailablePhoneNumbers/' + country + '/
|
|
105
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/AvailablePhoneNumbers/' + country + '/TollFree.json',
|
|
97
106
|
headers : {
|
|
98
107
|
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
99
108
|
},
|
|
100
109
|
query : {
|
|
101
110
|
SmsEnabled : true,
|
|
102
111
|
PageSize : limit,
|
|
103
|
-
...( areaCode && { AreaCode : areaCode } ),
|
|
104
112
|
// `Contains` is the vendor's matching-pattern filter — digits
|
|
105
|
-
// match anywhere in the number, so one search box serves "
|
|
106
|
-
//
|
|
113
|
+
// match anywhere in the number, so one search box serves "an 888
|
|
114
|
+
// prefix" and "ends in 7777" alike. (AreaCode is a Local-only
|
|
115
|
+
// filter and went with Local.json.)
|
|
107
116
|
...( contains && { Contains : contains } ),
|
|
108
117
|
...( page && { Page : page } )
|
|
109
118
|
}
|
|
@@ -150,6 +159,73 @@ const twilio = {
|
|
|
150
159
|
|
|
151
160
|
},
|
|
152
161
|
|
|
162
|
+
// THE NUMBER AS TWILIO HOLDS IT NOW. Same IncomingPhoneNumber resource the
|
|
163
|
+
// purchase and release above use (api.twilio.com 2010-04-01, GET
|
|
164
|
+
// /IncomingPhoneNumbers/{sid}.json) — a 404 means the number is no longer
|
|
165
|
+
// on the account, which the health sweep must distinguish from a transient,
|
|
166
|
+
// so it is answered as { gone : true } rather than thrown.
|
|
167
|
+
numberConfig : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
168
|
+
|
|
169
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
170
|
+
if( ! sid ) throw new Error( 'Twilio config read needs the IncomingPhoneNumber sid' );
|
|
171
|
+
|
|
172
|
+
let result;
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
|
|
176
|
+
result = await request$1({
|
|
177
|
+
method : 'GET',
|
|
178
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/IncomingPhoneNumbers/' + sid + '.json',
|
|
179
|
+
headers : {
|
|
180
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
} catch ( error ) {
|
|
185
|
+
|
|
186
|
+
if( error?.status === 404 ) return { gone : true };
|
|
187
|
+
|
|
188
|
+
throw error;
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
gone : false,
|
|
194
|
+
number : result?.phone_number,
|
|
195
|
+
smsMethod : result?.sms_method,
|
|
196
|
+
smsUrl : result?.sms_url,
|
|
197
|
+
status : result?.status
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// RE-POINT AN OWNED NUMBER'S INBOUND WEBHOOK — POST on the same resource,
|
|
203
|
+
// the exact fields purchase sets. The health sweep's repair arm.
|
|
204
|
+
updateNumber : async ({ accountSid, authToken, request: request$1 = request, sid, smsUrl }) => {
|
|
205
|
+
|
|
206
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
207
|
+
if( ! sid ) throw new Error( 'Twilio update needs the IncomingPhoneNumber sid' );
|
|
208
|
+
if( ! smsUrl ) throw new Error( 'Twilio update needs the smsUrl to point the number at' );
|
|
209
|
+
|
|
210
|
+
const result = await request$1({
|
|
211
|
+
method : 'POST',
|
|
212
|
+
type : 'form',
|
|
213
|
+
url : 'https://api.twilio.com/2010-04-01/Accounts/' + accountSid + '/IncomingPhoneNumbers/' + sid + '.json',
|
|
214
|
+
headers : {
|
|
215
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
216
|
+
},
|
|
217
|
+
body : {
|
|
218
|
+
SmsUrl : smsUrl,
|
|
219
|
+
SmsMethod : 'POST'
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
smsUrl : result?.sms_url
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
},
|
|
228
|
+
|
|
153
229
|
releaseNumber : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
154
230
|
|
|
155
231
|
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
@@ -163,6 +239,111 @@ const twilio = {
|
|
|
163
239
|
}
|
|
164
240
|
});
|
|
165
241
|
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
// TOLL-FREE VERIFICATION — the carrier registration that lets a purchased
|
|
245
|
+
// number actually deliver. From the Tollfree Verification resource docs
|
|
246
|
+
// (messaging.twilio.com, docs/messaging/api/tollfree-verification-resource):
|
|
247
|
+
// POST /v1/Tollfree/Verifications
|
|
248
|
+
// required: BusinessName, BusinessWebsite, NotificationEmail,
|
|
249
|
+
// UseCaseCategories (array), UseCaseSummary,
|
|
250
|
+
// ProductionMessageSample, OptInImageUrls (array), OptInType,
|
|
251
|
+
// MessageVolume, TollfreePhoneNumberSid (PN…)
|
|
252
|
+
// GET /v1/Tollfree/Verifications/{Sid}
|
|
253
|
+
// status: PENDING_REVIEW | IN_REVIEW | TWILIO_APPROVED |
|
|
254
|
+
// TWILIO_REJECTED, with rejection_reason beside a rejection.
|
|
255
|
+
// Basic auth, form-encoded, like everything above. There is no status
|
|
256
|
+
// callback on this resource — the caller polls the fetch.
|
|
257
|
+
//
|
|
258
|
+
// THE END BUSINESS'S DETAILS, never the platform's. Twilio rejects ISV
|
|
259
|
+
// submissions carrying the ISV's own identity (Toll-Free Verification for
|
|
260
|
+
// ISVs, support.twilio.com) — so businessName, website and email here are
|
|
261
|
+
// the merchant's, collected at purchase.
|
|
262
|
+
//
|
|
263
|
+
// The use-case fields are PLATFORM facts and live here beside the message
|
|
264
|
+
// composition for the same reason it does: how Drawbridge collects opt-in
|
|
265
|
+
// (its own hosted entry forms) and what its messages look like are
|
|
266
|
+
// properties of sending through Drawbridge, not of any one merchant.
|
|
267
|
+
submitVerification : async ({
|
|
268
|
+
accountSid,
|
|
269
|
+
authToken,
|
|
270
|
+
businessName,
|
|
271
|
+
email,
|
|
272
|
+
numberSid,
|
|
273
|
+
optInImage,
|
|
274
|
+
request: request$1 = request,
|
|
275
|
+
volume,
|
|
276
|
+
website
|
|
277
|
+
}) => {
|
|
278
|
+
|
|
279
|
+
const missing = Object.entries({ accountSid, authToken, businessName, email, numberSid, optInImage, website })
|
|
280
|
+
.filter( ( [ , value ] ) => ! value )
|
|
281
|
+
.map( ( [ name ] ) => name );
|
|
282
|
+
|
|
283
|
+
if( missing.length ) throw new Error( 'Toll-free verification submission missing — ' + missing.join( ', ' ) );
|
|
284
|
+
|
|
285
|
+
// URLSearchParams rather than an object: UseCaseCategories and
|
|
286
|
+
// OptInImageUrls are array parameters, which Twilio takes as REPEATED
|
|
287
|
+
// form keys — an object body would comma-join them into one value.
|
|
288
|
+
const body = new URLSearchParams();
|
|
289
|
+
|
|
290
|
+
body.append( 'BusinessName', businessName );
|
|
291
|
+
body.append( 'BusinessWebsite', website );
|
|
292
|
+
body.append( 'NotificationEmail', email );
|
|
293
|
+
body.append( 'UseCaseCategories', 'MARKETING' );
|
|
294
|
+
body.append( 'UseCaseSummary', 'Prize-draw entry confirmations, winner notifications and campaign updates to consumers who opted in on this business\'s Drawbridge-hosted entry form.' );
|
|
295
|
+
// Mirrors the sms() composition above — newline-separated, brand first,
|
|
296
|
+
// opt-out line appended — so the reviewed sample is the sent shape.
|
|
297
|
+
body.append( 'ProductionMessageSample', businessName + '\nThanks for entering! We\'ll text you here about your entry.\nReply STOP to opt out' );
|
|
298
|
+
body.append( 'OptInImageUrls', optInImage );
|
|
299
|
+
// The entry form is a web form; the phone field is beside the consent
|
|
300
|
+
// language on the merchant's campaign page.
|
|
301
|
+
body.append( 'OptInType', 'WEB_FORM' );
|
|
302
|
+
body.append( 'MessageVolume', volume || '1,000' );
|
|
303
|
+
body.append( 'TollfreePhoneNumberSid', numberSid );
|
|
304
|
+
|
|
305
|
+
const result = await request$1({
|
|
306
|
+
method : 'POST',
|
|
307
|
+
type : 'form',
|
|
308
|
+
url : 'https://messaging.twilio.com/v1/Tollfree/Verifications',
|
|
309
|
+
headers : {
|
|
310
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
311
|
+
},
|
|
312
|
+
body
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
return {
|
|
316
|
+
sid : result?.sid,
|
|
317
|
+
status : result?.status
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
fetchVerification : async ({ accountSid, authToken, request: request$1 = request, sid }) => {
|
|
323
|
+
|
|
324
|
+
if( ! accountSid || ! authToken ) throw new Error( 'Twilio credentials missing — accountSid, authToken' );
|
|
325
|
+
if( ! sid ) throw new Error( 'Twilio verification fetch needs the verification sid' );
|
|
326
|
+
|
|
327
|
+
const result = await request$1({
|
|
328
|
+
method : 'GET',
|
|
329
|
+
url : 'https://messaging.twilio.com/v1/Tollfree/Verifications/' + sid,
|
|
330
|
+
headers : {
|
|
331
|
+
'Authorization' : 'Basic ' + Buffer.from( accountSid + ':' + authToken ).toString( 'base64' )
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// The caller-facing shape is ours; the vendor's vocabulary stays here.
|
|
336
|
+
return {
|
|
337
|
+
// TWILIO_APPROVED → verified, TWILIO_REJECTED → rejected, both
|
|
338
|
+
// review states → pending.
|
|
339
|
+
outcome : result?.status === 'TWILIO_APPROVED'
|
|
340
|
+
? 'approved'
|
|
341
|
+
: result?.status === 'TWILIO_REJECTED'
|
|
342
|
+
? 'rejected'
|
|
343
|
+
: 'pending',
|
|
344
|
+
reason : result?.rejection_reason || null
|
|
345
|
+
};
|
|
346
|
+
|
|
166
347
|
}
|
|
167
348
|
|
|
168
349
|
};
|
package/dist/twilio.js
CHANGED
|
@@ -82,28 +82,37 @@ var twilio = {
|
|
|
82
82
|
// NUMBER LIFECYCLE, same transport discipline as sms above. Endpoints and
|
|
83
83
|
// parameter names are Twilio's own, from the AvailablePhoneNumbers and
|
|
84
84
|
// IncomingPhoneNumbers resource docs:
|
|
85
|
-
// GET /2010-04-01/Accounts/{AccountSid}/AvailablePhoneNumbers/{CountryCode}/
|
|
86
|
-
// query: SmsEnabled,
|
|
85
|
+
// GET /2010-04-01/Accounts/{AccountSid}/AvailablePhoneNumbers/{CountryCode}/TollFree.json
|
|
86
|
+
// query: SmsEnabled, Contains, PageSize (1-1000)
|
|
87
87
|
// POST /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers.json
|
|
88
88
|
// body: PhoneNumber (E.164), SmsUrl, SmsMethod
|
|
89
89
|
// DELETE /2010-04-01/Accounts/{AccountSid}/IncomingPhoneNumbers/{Sid}.json
|
|
90
90
|
// Basic auth throughout, like Messages.
|
|
91
|
-
|
|
91
|
+
//
|
|
92
|
+
// TOLL-FREE, not Local, and that is a carrier-registration decision rather
|
|
93
|
+
// than an inventory one. A US local number may not send A2P SMS without full
|
|
94
|
+
// 10DLC brand-and-campaign registration; a toll-free number needs only
|
|
95
|
+
// Toll-Free Verification — one API submission per number (see
|
|
96
|
+
// submitVerification below), no TCR brand, no campaign fees. Until a
|
|
97
|
+
// verification is approved, Twilio blocks the number's US-bound messages
|
|
98
|
+
// outright — which is why a purchased number starts `pending` and the send
|
|
99
|
+
// path refuses anything but `verified`.
|
|
100
|
+
searchNumbers: async ({ accountSid, authToken, contains, country = "US", cursor, limit = 10, request: request2 = request }) => {
|
|
92
101
|
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
93
102
|
const page = Number(cursor) || 0;
|
|
94
103
|
const result = await request2({
|
|
95
104
|
method: "GET",
|
|
96
|
-
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/AvailablePhoneNumbers/" + country + "/
|
|
105
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/AvailablePhoneNumbers/" + country + "/TollFree.json",
|
|
97
106
|
headers: {
|
|
98
107
|
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
99
108
|
},
|
|
100
109
|
query: {
|
|
101
110
|
SmsEnabled: true,
|
|
102
111
|
PageSize: limit,
|
|
103
|
-
...areaCode && { AreaCode: areaCode },
|
|
104
112
|
// `Contains` is the vendor's matching-pattern filter — digits
|
|
105
|
-
// match anywhere in the number, so one search box serves "
|
|
106
|
-
//
|
|
113
|
+
// match anywhere in the number, so one search box serves "an 888
|
|
114
|
+
// prefix" and "ends in 7777" alike. (AreaCode is a Local-only
|
|
115
|
+
// filter and went with Local.json.)
|
|
107
116
|
...contains && { Contains: contains },
|
|
108
117
|
...page && { Page: page }
|
|
109
118
|
}
|
|
@@ -140,6 +149,57 @@ var twilio = {
|
|
|
140
149
|
sid: result == null ? void 0 : result.sid
|
|
141
150
|
};
|
|
142
151
|
},
|
|
152
|
+
// THE NUMBER AS TWILIO HOLDS IT NOW. Same IncomingPhoneNumber resource the
|
|
153
|
+
// purchase and release above use (api.twilio.com 2010-04-01, GET
|
|
154
|
+
// /IncomingPhoneNumbers/{sid}.json) — a 404 means the number is no longer
|
|
155
|
+
// on the account, which the health sweep must distinguish from a transient,
|
|
156
|
+
// so it is answered as { gone : true } rather than thrown.
|
|
157
|
+
numberConfig: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
158
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
159
|
+
if (!sid) throw new Error("Twilio config read needs the IncomingPhoneNumber sid");
|
|
160
|
+
let result;
|
|
161
|
+
try {
|
|
162
|
+
result = await request2({
|
|
163
|
+
method: "GET",
|
|
164
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/IncomingPhoneNumbers/" + sid + ".json",
|
|
165
|
+
headers: {
|
|
166
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if ((error == null ? void 0 : error.status) === 404) return { gone: true };
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
gone: false,
|
|
175
|
+
number: result == null ? void 0 : result.phone_number,
|
|
176
|
+
smsMethod: result == null ? void 0 : result.sms_method,
|
|
177
|
+
smsUrl: result == null ? void 0 : result.sms_url,
|
|
178
|
+
status: result == null ? void 0 : result.status
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
// RE-POINT AN OWNED NUMBER'S INBOUND WEBHOOK — POST on the same resource,
|
|
182
|
+
// the exact fields purchase sets. The health sweep's repair arm.
|
|
183
|
+
updateNumber: async ({ accountSid, authToken, request: request2 = request, sid, smsUrl }) => {
|
|
184
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
185
|
+
if (!sid) throw new Error("Twilio update needs the IncomingPhoneNumber sid");
|
|
186
|
+
if (!smsUrl) throw new Error("Twilio update needs the smsUrl to point the number at");
|
|
187
|
+
const result = await request2({
|
|
188
|
+
method: "POST",
|
|
189
|
+
type: "form",
|
|
190
|
+
url: "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/IncomingPhoneNumbers/" + sid + ".json",
|
|
191
|
+
headers: {
|
|
192
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
193
|
+
},
|
|
194
|
+
body: {
|
|
195
|
+
SmsUrl: smsUrl,
|
|
196
|
+
SmsMethod: "POST"
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
smsUrl: result == null ? void 0 : result.sms_url
|
|
201
|
+
};
|
|
202
|
+
},
|
|
143
203
|
releaseNumber: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
144
204
|
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
145
205
|
if (!sid) throw new Error("Twilio release needs the IncomingPhoneNumber sid");
|
|
@@ -150,6 +210,84 @@ var twilio = {
|
|
|
150
210
|
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
151
211
|
}
|
|
152
212
|
});
|
|
213
|
+
},
|
|
214
|
+
// TOLL-FREE VERIFICATION — the carrier registration that lets a purchased
|
|
215
|
+
// number actually deliver. From the Tollfree Verification resource docs
|
|
216
|
+
// (messaging.twilio.com, docs/messaging/api/tollfree-verification-resource):
|
|
217
|
+
// POST /v1/Tollfree/Verifications
|
|
218
|
+
// required: BusinessName, BusinessWebsite, NotificationEmail,
|
|
219
|
+
// UseCaseCategories (array), UseCaseSummary,
|
|
220
|
+
// ProductionMessageSample, OptInImageUrls (array), OptInType,
|
|
221
|
+
// MessageVolume, TollfreePhoneNumberSid (PN…)
|
|
222
|
+
// GET /v1/Tollfree/Verifications/{Sid}
|
|
223
|
+
// status: PENDING_REVIEW | IN_REVIEW | TWILIO_APPROVED |
|
|
224
|
+
// TWILIO_REJECTED, with rejection_reason beside a rejection.
|
|
225
|
+
// Basic auth, form-encoded, like everything above. There is no status
|
|
226
|
+
// callback on this resource — the caller polls the fetch.
|
|
227
|
+
//
|
|
228
|
+
// THE END BUSINESS'S DETAILS, never the platform's. Twilio rejects ISV
|
|
229
|
+
// submissions carrying the ISV's own identity (Toll-Free Verification for
|
|
230
|
+
// ISVs, support.twilio.com) — so businessName, website and email here are
|
|
231
|
+
// the merchant's, collected at purchase.
|
|
232
|
+
//
|
|
233
|
+
// The use-case fields are PLATFORM facts and live here beside the message
|
|
234
|
+
// composition for the same reason it does: how Drawbridge collects opt-in
|
|
235
|
+
// (its own hosted entry forms) and what its messages look like are
|
|
236
|
+
// properties of sending through Drawbridge, not of any one merchant.
|
|
237
|
+
submitVerification: async ({
|
|
238
|
+
accountSid,
|
|
239
|
+
authToken,
|
|
240
|
+
businessName,
|
|
241
|
+
email,
|
|
242
|
+
numberSid,
|
|
243
|
+
optInImage,
|
|
244
|
+
request: request2 = request,
|
|
245
|
+
volume,
|
|
246
|
+
website
|
|
247
|
+
}) => {
|
|
248
|
+
const missing = Object.entries({ accountSid, authToken, businessName, email, numberSid, optInImage, website }).filter(([, value]) => !value).map(([name]) => name);
|
|
249
|
+
if (missing.length) throw new Error("Toll-free verification submission missing \u2014 " + missing.join(", "));
|
|
250
|
+
const body = new URLSearchParams();
|
|
251
|
+
body.append("BusinessName", businessName);
|
|
252
|
+
body.append("BusinessWebsite", website);
|
|
253
|
+
body.append("NotificationEmail", email);
|
|
254
|
+
body.append("UseCaseCategories", "MARKETING");
|
|
255
|
+
body.append("UseCaseSummary", "Prize-draw entry confirmations, winner notifications and campaign updates to consumers who opted in on this business's Drawbridge-hosted entry form.");
|
|
256
|
+
body.append("ProductionMessageSample", businessName + "\nThanks for entering! We'll text you here about your entry.\nReply STOP to opt out");
|
|
257
|
+
body.append("OptInImageUrls", optInImage);
|
|
258
|
+
body.append("OptInType", "WEB_FORM");
|
|
259
|
+
body.append("MessageVolume", volume || "1,000");
|
|
260
|
+
body.append("TollfreePhoneNumberSid", numberSid);
|
|
261
|
+
const result = await request2({
|
|
262
|
+
method: "POST",
|
|
263
|
+
type: "form",
|
|
264
|
+
url: "https://messaging.twilio.com/v1/Tollfree/Verifications",
|
|
265
|
+
headers: {
|
|
266
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
267
|
+
},
|
|
268
|
+
body
|
|
269
|
+
});
|
|
270
|
+
return {
|
|
271
|
+
sid: result == null ? void 0 : result.sid,
|
|
272
|
+
status: result == null ? void 0 : result.status
|
|
273
|
+
};
|
|
274
|
+
},
|
|
275
|
+
fetchVerification: async ({ accountSid, authToken, request: request2 = request, sid }) => {
|
|
276
|
+
if (!accountSid || !authToken) throw new Error("Twilio credentials missing \u2014 accountSid, authToken");
|
|
277
|
+
if (!sid) throw new Error("Twilio verification fetch needs the verification sid");
|
|
278
|
+
const result = await request2({
|
|
279
|
+
method: "GET",
|
|
280
|
+
url: "https://messaging.twilio.com/v1/Tollfree/Verifications/" + sid,
|
|
281
|
+
headers: {
|
|
282
|
+
"Authorization": "Basic " + Buffer.from(accountSid + ":" + authToken).toString("base64")
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
return {
|
|
286
|
+
// TWILIO_APPROVED → verified, TWILIO_REJECTED → rejected, both
|
|
287
|
+
// review states → pending.
|
|
288
|
+
outcome: (result == null ? void 0 : result.status) === "TWILIO_APPROVED" ? "approved" : (result == null ? void 0 : result.status) === "TWILIO_REJECTED" ? "rejected" : "pending",
|
|
289
|
+
reason: (result == null ? void 0 : result.rejection_reason) || null
|
|
290
|
+
};
|
|
153
291
|
}
|
|
154
292
|
};
|
|
155
293
|
export {
|
package/package.json
CHANGED