@divyacon/piece-twilio 0.0.0-stage → 0.1.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.
Files changed (63) hide show
  1. package/LICENSE.MIT-AP +24 -0
  2. package/README.md +8 -2
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +63 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/action/download-recording-media.d.ts +6 -0
  8. package/dist/lib/action/download-recording-media.d.ts.map +1 -0
  9. package/dist/lib/action/download-recording-media.js +77 -0
  10. package/dist/lib/action/download-recording-media.js.map +1 -0
  11. package/dist/lib/action/get-message.d.ts +4 -0
  12. package/dist/lib/action/get-message.d.ts.map +1 -0
  13. package/dist/lib/action/get-message.js +36 -0
  14. package/dist/lib/action/get-message.js.map +1 -0
  15. package/dist/lib/action/make-call.d.ts +10 -0
  16. package/dist/lib/action/make-call.d.ts.map +1 -0
  17. package/dist/lib/action/make-call.js +98 -0
  18. package/dist/lib/action/make-call.js.map +1 -0
  19. package/dist/lib/action/phone-number-lookup.d.ts +4 -0
  20. package/dist/lib/action/phone-number-lookup.d.ts.map +1 -0
  21. package/dist/lib/action/phone-number-lookup.js +44 -0
  22. package/dist/lib/action/phone-number-lookup.js.map +1 -0
  23. package/dist/lib/action/send-sms.d.ts +6 -0
  24. package/dist/lib/action/send-sms.d.ts.map +1 -0
  25. package/dist/lib/action/send-sms.js +44 -0
  26. package/dist/lib/action/send-sms.js.map +1 -0
  27. package/dist/lib/common/index.d.ts +9 -0
  28. package/dist/lib/common/index.d.ts.map +1 -0
  29. package/dist/lib/common/index.js +56 -0
  30. package/dist/lib/common/index.js.map +1 -0
  31. package/dist/lib/trigger/new-call.d.ts +3 -0
  32. package/dist/lib/trigger/new-call.d.ts.map +1 -0
  33. package/dist/lib/trigger/new-call.js +135 -0
  34. package/dist/lib/trigger/new-call.js.map +1 -0
  35. package/dist/lib/trigger/new-incoming-sms.d.ts +11 -0
  36. package/dist/lib/trigger/new-incoming-sms.d.ts.map +1 -0
  37. package/dist/lib/trigger/new-incoming-sms.js +108 -0
  38. package/dist/lib/trigger/new-incoming-sms.js.map +1 -0
  39. package/dist/lib/trigger/new-phone-number.d.ts +3 -0
  40. package/dist/lib/trigger/new-phone-number.d.ts.map +1 -0
  41. package/dist/lib/trigger/new-phone-number.js +113 -0
  42. package/dist/lib/trigger/new-phone-number.js.map +1 -0
  43. package/dist/lib/trigger/new-recording.d.ts +3 -0
  44. package/dist/lib/trigger/new-recording.d.ts.map +1 -0
  45. package/dist/lib/trigger/new-recording.js +123 -0
  46. package/dist/lib/trigger/new-recording.js.map +1 -0
  47. package/dist/lib/trigger/new-transcription.d.ts +3 -0
  48. package/dist/lib/trigger/new-transcription.d.ts.map +1 -0
  49. package/dist/lib/trigger/new-transcription.js +112 -0
  50. package/dist/lib/trigger/new-transcription.js.map +1 -0
  51. package/package.json +43 -3
  52. package/src/index.ts +63 -0
  53. package/src/lib/action/download-recording-media.ts +74 -0
  54. package/src/lib/action/get-message.ts +35 -0
  55. package/src/lib/action/make-call.ts +101 -0
  56. package/src/lib/action/phone-number-lookup.ts +39 -0
  57. package/src/lib/action/send-sms.ts +41 -0
  58. package/src/lib/common/index.ts +69 -0
  59. package/src/lib/trigger/new-call.ts +156 -0
  60. package/src/lib/trigger/new-incoming-sms.ts +123 -0
  61. package/src/lib/trigger/new-phone-number.ts +149 -0
  62. package/src/lib/trigger/new-recording.ts +140 -0
  63. package/src/lib/trigger/new-transcription.ts +140 -0
@@ -0,0 +1,156 @@
1
+ import { createTrigger, TriggerStrategy, PiecePropValueSchema, AppConnectionValueForAuthProperty } from '@agnocon/pieces-framework';
2
+ import { twilioAuth } from '../..';
3
+ import { AuthenticationType, DedupeStrategy, httpClient, HttpMethod, Polling, pollingHelper } from '@agnocon/pieces-common';
4
+
5
+ interface Call {
6
+ sid: string;
7
+ status: string;
8
+ direction: string;
9
+ from: string;
10
+ to: string;
11
+ start_time: string;
12
+ end_time: string;
13
+ duration: string;
14
+ price: string;
15
+ price_unit: string;
16
+ date_created:string
17
+ }
18
+
19
+ interface CallsResponse {
20
+ calls: Call[];
21
+ next_page_uri:string
22
+
23
+ }
24
+
25
+
26
+ const polling: Polling<
27
+ AppConnectionValueForAuthProperty<typeof twilioAuth>,
28
+ Record<string, unknown>
29
+ > = {
30
+ strategy: DedupeStrategy.TIMEBASED,
31
+ async items({ auth, lastFetchEpochMS }) {
32
+ const isTest = lastFetchEpochMS === 0;
33
+ const account_sid = auth.username;
34
+ const auth_token = auth.password;
35
+
36
+ let currentUri:
37
+ | string
38
+ | null = `/2010-04-01/Accounts/${account_sid}/Calls.json?PageSize=${
39
+ isTest ? 1 : 1000
40
+ }`;
41
+
42
+ const results = [];
43
+ let stop = false;
44
+
45
+ do {
46
+ const response: any = await httpClient.sendRequest({
47
+ method: HttpMethod.GET,
48
+ url: `https://api.twilio.com${currentUri}`,
49
+ authentication: {
50
+ type: AuthenticationType.BASIC,
51
+ username: account_sid,
52
+ password: auth_token,
53
+ },
54
+ });
55
+
56
+ const payload = response.body as CallsResponse;
57
+
58
+ const calls = payload.calls ?? [];
59
+
60
+ for (const call of calls) {
61
+ const ts = new Date(call.date_created).getTime();
62
+
63
+ if(call.status !== 'completed') continue;
64
+
65
+ if (isTest || ts > lastFetchEpochMS) {
66
+ results.push(call);
67
+ } else {
68
+ stop = true;
69
+ break;
70
+ }
71
+ }
72
+
73
+ if (isTest) break;
74
+ currentUri = payload?.next_page_uri ?? null;
75
+ } while (currentUri && !stop);
76
+
77
+ return results.map((call) => {
78
+ return {
79
+ epochMilliSeconds: new Date(call.date_created).getTime(),
80
+ data: call,
81
+ };
82
+ });
83
+ },
84
+ };
85
+
86
+ export const twilioNewCall = createTrigger({
87
+ auth: twilioAuth,
88
+ name: 'new_call',
89
+ displayName: 'New Call',
90
+ description: 'Triggers when a call completes (incoming or outgoing).',
91
+ aiMetadata: {
92
+ description: 'Fires when a voice call reaches completed status on the Twilio account, for both inbound and outbound calls. Each event represents one finished call with its direction, participants, duration, and status.',
93
+ },
94
+ props: {},
95
+ sampleData:{
96
+ "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
97
+ "answered_by": "machine_start",
98
+ "api_version": "2010-04-01",
99
+ "caller_name": "callerid1",
100
+ "date_created": "Fri, 18 Oct 2019 17:00:00 +0000",
101
+ "date_updated": "Fri, 18 Oct 2019 17:01:00 +0000",
102
+ "direction": "outbound-api",
103
+ "duration": "4",
104
+ "end_time": "Fri, 18 Oct 2019 17:03:00 +0000",
105
+ "forwarded_from": "calledvia1",
106
+ "from": "+13051416799",
107
+ "from_formatted": "(305) 141-6799",
108
+ "group_sid": "GPdeadbeefdeadbeefdeadbeefdeadbeef",
109
+ "parent_call_sid": "CAdeadbeefdeadbeefdeadbeefdeadbeef",
110
+ "phone_number_sid": "PNdeadbeefdeadbeefdeadbeefdeadbeef",
111
+ "price": "-0.200",
112
+ "price_unit": "USD",
113
+ "sid": "CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
114
+ "start_time": "Fri, 18 Oct 2019 17:02:00 +0000",
115
+ "status": "completed",
116
+ "subresource_uris": {
117
+ "notifications": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Notifications.json",
118
+ "recordings": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings.json",
119
+ "payments": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Payments.json",
120
+ "events": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Events.json",
121
+ "siprec": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Siprec.json",
122
+ "streams": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Streams.json",
123
+ "transcriptions": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Transcriptions.json",
124
+ "user_defined_message_subscriptions": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/UserDefinedMessageSubscriptions.json",
125
+ "user_defined_messages": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/UserDefinedMessages.json"
126
+ },
127
+ "to": "+13051913581",
128
+ "to_formatted": "(305) 191-3581",
129
+ "trunk_sid": "TKdeadbeefdeadbeefdeadbeefdeadbeef",
130
+ "uri": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json",
131
+ "queue_time": "1000"
132
+ },
133
+ type: TriggerStrategy.POLLING,
134
+
135
+
136
+ async onEnable(context) {
137
+ await pollingHelper.onEnable(polling, {
138
+ auth: context.auth,
139
+ store: context.store,
140
+ propsValue: context.propsValue,
141
+ });
142
+ },
143
+ async onDisable(context) {
144
+ await pollingHelper.onDisable(polling, {
145
+ auth: context.auth,
146
+ store: context.store,
147
+ propsValue: context.propsValue,
148
+ });
149
+ },
150
+ async test(context) {
151
+ return await pollingHelper.test(polling, context);
152
+ },
153
+ async run(context) {
154
+ return await pollingHelper.poll(polling, context);
155
+ },
156
+ });
@@ -0,0 +1,123 @@
1
+ import { createTrigger, TriggerStrategy } from '@agnocon/pieces-framework';
2
+ import {
3
+ HttpMethod,
4
+ HttpResponse,
5
+ httpClient,
6
+ AuthenticationType,
7
+ } from '@agnocon/pieces-common';
8
+ import { callTwilioApi, twilioCommon } from '../common';
9
+ import { twilioAuth } from '../..';
10
+
11
+ export const twilioNewIncomingSms = createTrigger({
12
+ auth: twilioAuth,
13
+ name: 'new_incoming_sms',
14
+ displayName: 'New Incoming SMS',
15
+ description: 'Triggers when a new SMS message is received',
16
+ aiMetadata: {
17
+ description: 'Fires when an inbound SMS message is received on the specified Twilio phone number. Each event represents one incoming text message with its sender, body, and metadata.',
18
+ },
19
+ props: {
20
+ phone_number: twilioCommon.phone_number,
21
+ },
22
+ sampleData: {
23
+ body: 'Hello',
24
+ num_segments: '1',
25
+ direction: 'inbound',
26
+ from: '+12184191735',
27
+ date_updated: 'Wed, 08 Feb 2023 01:40:51 +0000',
28
+ price: null,
29
+ error_message: null,
30
+ uri: '/2010-04-01/Accounts/ACc0ea1238d61fe90d78a69a3de71d45619/Messages/SM8c3920d3f2ac481ba83e639a69dadd63.json',
31
+ account_sid: 'ACc0ea716d61fe90d78a123a3de71d45619',
32
+ num_media: '0',
33
+ to: '+12184191735',
34
+ date_created: 'Wed, 08 Feb 2023 01:40:50 +0000',
35
+ status: 'failed',
36
+ sid: 'SM8c3920d3f2ac481ba83e639a69dadd63',
37
+ date_sent: 'Wed, 08 Feb 2023 01:40:51 +0000',
38
+ messaging_service_sid: 'MG88e323e6a88ce67ba3bf12e1bcb7e0b8',
39
+ error_code: 21211,
40
+ price_unit: 'USD',
41
+ api_version: '2010-04-01',
42
+ subresource_uris: {
43
+ media:
44
+ '/2010-04-01/Accounts/ACc0ea716d61fe90d78a69a3de71d45619/Messages/SM8c3920d3f2ac481ba83e639a69dadd63/Media.json',
45
+ feedback:
46
+ '/2010-04-01/Accounts/ACc0ea716d61fe90d78a69a3de71d45619/Messages/SM8c3920d3f2ac481ba83e639a69dadd63/Feedback.json',
47
+ },
48
+ },
49
+ // Twilio API only allows one webhook per phone number, so we need to poll
50
+ type: TriggerStrategy.POLLING,
51
+ async onEnable(context) {
52
+ const { phone_number } = context.propsValue;
53
+ const account_sid = context.auth.username;
54
+ const auth_token = context.auth.password;
55
+ const response = await callTwilioApi<MessagePaginationResponse>(
56
+ HttpMethod.GET,
57
+ `Messages.json?PageSize=20&To=${phone_number}`,
58
+ { account_sid, auth_token },
59
+ {}
60
+ );
61
+ await context.store.put<LastMessage>('_new_incoming_sms_trigger', {
62
+ lastMessageId:
63
+ response.body.messages.length === 0
64
+ ? null
65
+ : response.body.messages[0].sid,
66
+ });
67
+ },
68
+ async onDisable(context) {
69
+ await context.store.put('_new_incoming_sms_trigger', null);
70
+ },
71
+ async run(context) {
72
+ const account_sid = context.auth.username;
73
+ const auth_token = context.auth.password;
74
+ const newMessages: unknown[] = [];
75
+ const lastMessage = await context.store.get<LastMessage>(
76
+ '_new_incoming_sms_trigger'
77
+ );
78
+ let currentUri:
79
+ | string
80
+ | null = `2010-04-01/Accounts/${account_sid}/Messages.json?PageSize=20&To=${context.propsValue.phone_number}`;
81
+ let firstMessageId = undefined;
82
+ while (currentUri !== undefined && currentUri !== null) {
83
+ const res: HttpResponse<MessagePaginationResponse> =
84
+ await httpClient.sendRequest<MessagePaginationResponse>({
85
+ method: HttpMethod.GET,
86
+ url: `https://api.twilio.com/${currentUri}`,
87
+ authentication: {
88
+ type: AuthenticationType.BASIC,
89
+ username: account_sid,
90
+ password: auth_token,
91
+ },
92
+ });
93
+ const messages = res.body.messages;
94
+ if (!firstMessageId && messages.length > 0) {
95
+ firstMessageId = messages[0].sid;
96
+ }
97
+ currentUri = res.body.next_page_uri;
98
+ for (let i = 0; i < messages.length; i++) {
99
+ const message = messages[i];
100
+ if (message.sid === lastMessage?.lastMessageId) {
101
+ currentUri = null;
102
+ break;
103
+ }
104
+ if (message.direction === 'inbound') {
105
+ newMessages.push(message);
106
+ }
107
+ }
108
+ }
109
+ await context.store.put<LastMessage>('_new_incoming_sms_trigger', {
110
+ lastMessageId: firstMessageId ?? lastMessage!.lastMessageId,
111
+ });
112
+ return newMessages;
113
+ },
114
+ });
115
+
116
+ interface LastMessage {
117
+ lastMessageId: string | null;
118
+ }
119
+
120
+ interface MessagePaginationResponse {
121
+ messages: { sid: string; to: string; status: string; direction: string }[];
122
+ next_page_uri: string;
123
+ }
@@ -0,0 +1,149 @@
1
+ import {
2
+ AppConnectionValueForAuthProperty,
3
+ createTrigger,
4
+ PiecePropValueSchema,
5
+ TriggerStrategy,
6
+ } from '@agnocon/pieces-framework';
7
+ import {
8
+ AuthenticationType,
9
+ DedupeStrategy,
10
+ httpClient,
11
+ HttpMethod,
12
+ Polling,
13
+ pollingHelper,
14
+ } from '@agnocon/pieces-common';
15
+ import { twilioAuth } from '../..';
16
+
17
+ // The full structure of an IncomingPhoneNumber object from the Twilio API
18
+ interface TwilioPhoneNumber {
19
+ sid: string;
20
+ account_sid: string;
21
+ friendly_name: string;
22
+ phone_number: string;
23
+ voice_url: string;
24
+ voice_method: string;
25
+ sms_url: string;
26
+ sms_method: string;
27
+ date_created: string;
28
+ date_updated: string;
29
+ capabilities: {
30
+ voice: boolean;
31
+ sms: boolean;
32
+ mms: boolean;
33
+ };
34
+ uri: string;
35
+ }
36
+
37
+ interface IncomingPhoneNumbersResponse {
38
+ incoming_phone_numbers: TwilioPhoneNumber[];
39
+ next_page_uri:string
40
+ }
41
+
42
+ const polling: Polling<
43
+ AppConnectionValueForAuthProperty<typeof twilioAuth>,
44
+ Record<string, unknown>
45
+ > = {
46
+ strategy: DedupeStrategy.TIMEBASED,
47
+ async items({ auth, lastFetchEpochMS }) {
48
+ const isTest = lastFetchEpochMS === 0;
49
+ const account_sid = auth.username;
50
+ const auth_token = auth.password;
51
+
52
+ let currentUri:
53
+ | string
54
+ | null = `/2010-04-01/Accounts/${account_sid}/IncomingPhoneNumbers.json?PageSize=${
55
+ isTest ? 10 : 1000
56
+ }`;
57
+
58
+ const results = [];
59
+ let stop = false;
60
+
61
+ do {
62
+ const response: any = await httpClient.sendRequest({
63
+ method: HttpMethod.GET,
64
+ url: `https://api.twilio.com${currentUri}`,
65
+ authentication: {
66
+ type: AuthenticationType.BASIC,
67
+ username: account_sid,
68
+ password: auth_token,
69
+ },
70
+ });
71
+
72
+ const payload = response.body as IncomingPhoneNumbersResponse;
73
+
74
+ const numbers = payload.incoming_phone_numbers ?? [];
75
+
76
+ for (const num of numbers) {
77
+ const ts = new Date(num.date_created).getTime();
78
+
79
+ if (isTest || ts > lastFetchEpochMS) {
80
+ results.push(num);
81
+ } else {
82
+ stop = true;
83
+ break;
84
+ }
85
+ }
86
+
87
+ if (isTest) break;
88
+ currentUri = payload?.next_page_uri ?? null;
89
+ } while (currentUri && !stop);
90
+
91
+ return results.map((num) => {
92
+ return {
93
+ epochMilliSeconds: new Date(num.date_created).getTime(),
94
+ data: num,
95
+ };
96
+ });
97
+ },
98
+ };
99
+
100
+ export const twilioNewPhoneNumber = createTrigger({
101
+ auth: twilioAuth,
102
+ name: 'new_phone_number',
103
+ displayName: 'New Phone Number',
104
+ description: 'Triggers when you add a new phone number to your account.',
105
+ aiMetadata: {
106
+ description: 'Fires when a new phone number is provisioned on the Twilio account. Each event represents one newly added incoming phone number with its capabilities and configuration.',
107
+ },
108
+ props: {},
109
+ sampleData: {
110
+ sid: 'PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
111
+ account_sid: 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
112
+ friendly_name: '(555) 123-4567',
113
+ phone_number: '+15551234567',
114
+ voice_url: 'https://demo.twilio.com/welcome/voice/',
115
+ voice_method: 'POST',
116
+ sms_url: 'https://demo.twilio.com/welcome/sms/',
117
+ sms_method: 'POST',
118
+ date_created: '2025-08-28T11:44:10+00:00',
119
+ date_updated: '2025-08-28T11:44:10+00:00',
120
+ capabilities: {
121
+ voice: true,
122
+ sms: true,
123
+ mms: true,
124
+ },
125
+ uri: '/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/IncomingPhoneNumbers/PNXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.json',
126
+ },
127
+ type: TriggerStrategy.POLLING,
128
+
129
+ async onEnable(context) {
130
+ await pollingHelper.onEnable(polling, {
131
+ auth: context.auth,
132
+ store: context.store,
133
+ propsValue: context.propsValue,
134
+ });
135
+ },
136
+ async onDisable(context) {
137
+ await pollingHelper.onDisable(polling, {
138
+ auth: context.auth,
139
+ store: context.store,
140
+ propsValue: context.propsValue,
141
+ });
142
+ },
143
+ async test(context) {
144
+ return await pollingHelper.test(polling, context);
145
+ },
146
+ async run(context) {
147
+ return await pollingHelper.poll(polling, context);
148
+ },
149
+ });
@@ -0,0 +1,140 @@
1
+ import { AppConnectionValueForAuthProperty, createTrigger, PiecePropValueSchema, TriggerStrategy } from '@agnocon/pieces-framework';
2
+ import { AuthenticationType, DedupeStrategy, httpClient, HttpMethod, Polling, pollingHelper } from '@agnocon/pieces-common';
3
+ import { twilioAuth } from '../..';
4
+
5
+ interface Recording {
6
+ sid: string;
7
+ status: string;
8
+ date_created: string;
9
+ call_sid: string;
10
+ duration: string;
11
+ source: string;
12
+ price: string;
13
+ price_unit: string;
14
+ }
15
+
16
+ interface RecordingsResponse {
17
+ recordings: Recording[];
18
+ next_page_uri:string
19
+
20
+ }
21
+
22
+
23
+ const polling: Polling<
24
+ AppConnectionValueForAuthProperty<typeof twilioAuth>,
25
+ Record<string, unknown>
26
+ > = {
27
+ strategy: DedupeStrategy.TIMEBASED,
28
+ async items({ auth, lastFetchEpochMS }) {
29
+ const isTest = lastFetchEpochMS === 0;
30
+ const account_sid = auth.username;
31
+ const auth_token = auth.password;
32
+
33
+ let currentUri:
34
+ | string
35
+ | null = `/2010-04-01/Accounts/${account_sid}/Recordings.json?PageSize=${
36
+ isTest ? 10 : 1000
37
+ }`;
38
+
39
+ const results = [];
40
+ let stop = false;
41
+
42
+ do {
43
+ const response: any = await httpClient.sendRequest({
44
+ method: HttpMethod.GET,
45
+ url: `https://api.twilio.com${currentUri}`,
46
+ authentication: {
47
+ type: AuthenticationType.BASIC,
48
+ username: account_sid,
49
+ password: auth_token,
50
+ },
51
+ });
52
+
53
+ const payload = response.body as RecordingsResponse;
54
+
55
+ const recordings = payload.recordings ?? [];
56
+
57
+ for (const recording of recordings) {
58
+ const ts = new Date(recording.date_created).getTime();
59
+
60
+ if (isTest || ts > lastFetchEpochMS) {
61
+ results.push(recording);
62
+ } else {
63
+ stop = true;
64
+ break;
65
+ }
66
+ }
67
+
68
+ if (isTest) break;
69
+ currentUri = payload?.next_page_uri ?? null;
70
+ } while (currentUri && !stop);
71
+
72
+ return results.map((recording) => {
73
+ return {
74
+ epochMilliSeconds: new Date(recording.date_created).getTime(),
75
+ data: recording,
76
+ };
77
+ });
78
+ },
79
+ };
80
+
81
+ export const twilioNewRecording = createTrigger({
82
+ auth: twilioAuth,
83
+ name: 'new_recording',
84
+ displayName: 'New Recording',
85
+ description: 'Triggers when a new call recording is completed and available.',
86
+ aiMetadata: {
87
+ description: 'Fires when a new call recording becomes available on the Twilio account. Each event represents one completed recording, including its call SID, duration, and status.',
88
+ },
89
+ props: {},
90
+ sampleData: {
91
+ "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
92
+ "api_version": "2010-04-01",
93
+ "call_sid": "CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
94
+ "conference_sid": "CFaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
95
+ "channels": 1,
96
+ "date_created": "Fri, 14 Oct 2016 21:56:34 +0000",
97
+ "date_updated": "Fri, 14 Oct 2016 21:56:38 +0000",
98
+ "start_time": "Fri, 14 Oct 2016 21:56:34 +0000",
99
+ "price": "0.04",
100
+ "price_unit": "USD",
101
+ "duration": "4",
102
+ "sid": "REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
103
+ "source": "StartConferenceRecordingAPI",
104
+ "status": "completed",
105
+ "error_code": null,
106
+ "uri": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json",
107
+ "subresource_uris": {
108
+ "add_on_results": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/AddOnResults.json",
109
+ "transcriptions": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Transcriptions.json"
110
+ },
111
+ "encryption_details": {
112
+ "encryption_public_key_sid": "CRaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
113
+ "encryption_cek": "OV4h6zrsxMIW7h0Zfqwfn6TI2GCNl54KALlg8wn8YB8KYZhXt6HlgvBWAmQTlfYVeLWydMiCewY0YkDDT1xmNe5huEo9vjuKBS5OmYK4CZkSx1NVv3XOGrZHpd2Pl/5WJHVhUK//AUO87uh5qnUP2E0KoLh1nyCLeGcEkXU0RfpPn/6nxjof/n6m6OzZOyeIRK4Oed5+rEtjqFDfqT0EVKjs6JAxv+f0DCc1xYRHl2yV8bahUPVKs+bHYdy4PVszFKa76M/Uae4jFA9Lv233JqWcxj+K2UoghuGhAFbV/JQIIswY2CBYI8JlVSifSqNEl9vvsTJ8bkVMm3MKbG2P7Q==",
114
+ "encryption_iv": "8I2hhNIYNTrwxfHk"
115
+ },
116
+ "media_url": "http://api.twilio.com/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings/REaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
117
+ },
118
+ type: TriggerStrategy.POLLING,
119
+
120
+ async onEnable(context) {
121
+ await pollingHelper.onEnable(polling, {
122
+ auth: context.auth,
123
+ store: context.store,
124
+ propsValue: context.propsValue,
125
+ });
126
+ },
127
+ async onDisable(context) {
128
+ await pollingHelper.onDisable(polling, {
129
+ auth: context.auth,
130
+ store: context.store,
131
+ propsValue: context.propsValue,
132
+ });
133
+ },
134
+ async test(context) {
135
+ return await pollingHelper.test(polling, context);
136
+ },
137
+ async run(context) {
138
+ return await pollingHelper.poll(polling, context);
139
+ },
140
+ });