@sponson/adapters 0.9.3 → 0.10.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.
@@ -0,0 +1,141 @@
1
+ # yaml-language-server: $schema=../../../schema/recipe.schema.json
2
+ # Twilio REST API (2010-04-01) recipes: a TwiML Application per preview. Format and checklist:
3
+ # docs/adr/0020-recipes.md, CONTRIBUTING.md "Adding a recipe".
4
+ provider: twilio
5
+ title: Twilio
6
+ category: webhooks
7
+ verified_on: "2026-10-12"
8
+ docs:
9
+ - title: Requests to Twilio's APIs (authentication, form-encoded parameters)
10
+ url: https://www.twilio.com/docs/usage/requests-to-twilio
11
+ - title: Applications resource (TwiML Apps)
12
+ url: https://www.twilio.com/docs/usage/api/applications
13
+ - title: Access tokens (Voice grant, outgoingApplicationSid)
14
+ url: https://www.twilio.com/docs/iam/access-tokens
15
+ - title: API keys
16
+ url: https://www.twilio.com/docs/iam/api-keys
17
+ - title: Twilio's OpenAPI document for the 2010-04-01 API (Applications paths and schema)
18
+ url: https://raw.githubusercontent.com/twilio/twilio-oai/main/spec/json/twilio_api_v2010.json
19
+ api:
20
+ base_url: https://api.twilio.com
21
+ base_url_env: TWILIO_API_URL
22
+ # An API key's SID as the user and its secret as the password (TW1); the Account SID and Auth Token work the same way.
23
+ auth: { basic: { user_env: TWILIO_API_KEY, password_env: TWILIO_API_SECRET } }
24
+ encoding: form
25
+ credential:
26
+ url: "https://www.twilio.com/docs/iam/api-keys"
27
+ scope: "A Standard API key (Console > Account > API keys & tokens); its SID goes in TWILIO_API_KEY and its secret in TWILIO_API_SECRET."
28
+ source: "https://www.twilio.com/docs/usage/requests-to-twilio"
29
+ detect:
30
+ deps: [twilio]
31
+ env: ["TWILIO_*"]
32
+ starter:
33
+ - op: twiml_app
34
+ preview_url: url
35
+ values: { name: "sponson-${ctx.env}-${ctx.scope}" }
36
+ check: [voice_path]
37
+ where:
38
+ account_sid: "the Account SID (`AC…`) on the Twilio Console's home page"
39
+ assumptions:
40
+ - id: TW1
41
+ verified: true
42
+ text: "Requests authenticate with HTTP Basic: an API key's SID as the user name and its secret as the password, or the Account SID and the Auth Token. Request parameters are form-encoded (`application/x-www-form-urlencoded`)."
43
+ source: https://www.twilio.com/docs/usage/requests-to-twilio
44
+ - id: TW2
45
+ verified: true
46
+ text: "A TwiML Application is a set of URLs Twilio fetches TwiML from, 'most commonly used for the Voice SDKs to handle outbound calls': a Voice SDK access token's Voice grant names it as `outgoingApplicationSid` ('The SID of the TwiML App that Twilio will look to when making outgoing calls'), so each preview's tokens can name the preview's own app. A phone number can also be assigned an application instead of its own URLs."
47
+ source: https://www.twilio.com/docs/usage/api/applications
48
+ - id: TW3
49
+ verified: true
50
+ text: "`POST /2010-04-01/Accounts/{AccountSid}/Applications.json` creates an application from `FriendlyName` (up to 64 characters), `VoiceUrl`, `VoiceMethod`, `StatusCallback`, `SmsUrl`, `SmsMethod` and more, answering 201; `GET …/Applications.json` lists them (`applications`, filterable by `FriendlyName`); `GET` and `POST …/Applications/{Sid}.json` read and update one; `DELETE` answers 204 and unassigns it from any phone number using it. An account holds at most 1000 applications."
51
+ source: https://www.twilio.com/docs/usage/api/applications
52
+ - id: TW4
53
+ verified: true
54
+ text: "Parameters are written in PascalCase (`FriendlyName`, `VoiceUrl`) and answers name the same fields in snake_case (`friendly_name`, `voice_url`, `voice_method`, `sms_url`, `sms_method`, `status_callback`), with the object's id in `sid` (`AP…`); paths end in `.json`."
55
+ source: https://raw.githubusercontent.com/twilio/twilio-oai/main/spec/json/twilio_api_v2010.json
56
+ - id: TW5
57
+ verified: false
58
+ text: "Twilio does not require a FriendlyName to be unique (the documentation does not say); the recipe gives each preview its own, and two applications of the same name make `find` refuse with PARAM_INVALID. The list filtered by `FriendlyName` fits in its first page."
59
+ - id: TW6
60
+ verified: false
61
+ text: "Twilio answers the URLs and methods as they were written, so an unchanged application hashes the same on every plan."
62
+ - id: TW7
63
+ verified: true
64
+ text: "A phone number has one `sms_url` and one `voice_url` (or one `sms_application_sid` / `voice_application_sid`, single strings): pointing a shared number at a preview takes it from every other environment, so a number is not per-preview state and the recipe does not manage numbers. Inbound SMS or calls per preview need a number per preview (bought and, for US SMS, A2P-registered) assigned to the preview's application."
65
+ source: https://raw.githubusercontent.com/twilio/twilio-oai/main/spec/json/twilio_api_v2010.json
66
+ ops:
67
+ twiml_app:
68
+ kind: resource
69
+ title: TwiML Application
70
+ summary: "A TwiML Application per preview whose voice (and optionally messaging and status callback) URLs are the preview's own, `url` + a path: the Voice SDK tokens the preview issues name it (`outgoingApplicationSid`, TW2), so outgoing calls from that preview reach that preview's handlers. Identified by its FriendlyName (`name`), so a new preview URL updates it in place. A console edit of a URL or method is drift. Phone numbers are not managed (TW7)."
71
+ covers: [twilio-twiml-app]
72
+ params:
73
+ account_sid:
74
+ type: string
75
+ required: true
76
+ pattern: "^AC[0-9A-Za-z]{32}$"
77
+ description: The account (or subaccount) the application belongs to (`AC` and 32 hexadecimal characters on Twilio; the example is a placeholder).
78
+ example: ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
79
+ name:
80
+ type: string
81
+ required: true
82
+ pattern: "^.{1,64}$"
83
+ description: "The application's FriendlyName and identity: unique per preview, such as `sponson-${ctx.env}-${ctx.scope}`."
84
+ example: "sponson-${ctx.env}-${ctx.scope}"
85
+ url:
86
+ type: string
87
+ required: true
88
+ pattern: "^https://\\S*[^/]$"
89
+ description: "The preview's base URL, without a trailing slash: usually `{ from: <deploy line>.preview_url }`."
90
+ example: https://pr-42.preview.example.com
91
+ voice_path:
92
+ type: string
93
+ default: /api/twilio/voice
94
+ pattern: "^/\\S*$"
95
+ description: "Where the app answers with TwiML for a call, appended to `url` (`VoiceUrl`)."
96
+ voice_method:
97
+ type: string
98
+ default: POST
99
+ enum: [GET, POST]
100
+ description: How Twilio requests the voice URL.
101
+ sms_path:
102
+ type: string
103
+ pattern: "^/\\S*$"
104
+ description: "Where the app answers an incoming message, appended to `url` (`SmsUrl`), for a number assigned to this application; unset leaves it empty."
105
+ status_callback_path:
106
+ type: string
107
+ pattern: "^/\\S*$"
108
+ description: "Where Twilio posts call status changes, appended to `url` (`StatusCallback`); unset leaves it empty."
109
+ http:
110
+ find:
111
+ path: "/2010-04-01/Accounts/{account_sid}/Applications.json?FriendlyName={name}"
112
+ list_path: /applications
113
+ match: { friendly_name: { param: name } }
114
+ read: { path: "/2010-04-01/Accounts/{account_sid}/Applications/{id}.json" }
115
+ create:
116
+ path: "/2010-04-01/Accounts/{account_sid}/Applications.json"
117
+ send_fields: false
118
+ body:
119
+ FriendlyName: { param: name }
120
+ VoiceUrl: { join: [{ param: url }, { param: voice_path }] }
121
+ VoiceMethod: { param: voice_method }
122
+ SmsUrl: { join: [{ param: url }, { param: sms_path }] }
123
+ StatusCallback: { join: [{ param: url }, { param: status_callback_path }] }
124
+ update:
125
+ method: POST
126
+ send_fields: false
127
+ body:
128
+ VoiceUrl: { join: [{ param: url }, { param: voice_path }] }
129
+ VoiceMethod: { param: voice_method }
130
+ SmsUrl: { join: [{ param: url }, { param: sms_path }] }
131
+ StatusCallback: { join: [{ param: url }, { param: status_callback_path }] }
132
+ id_path: /sid
133
+ fields:
134
+ voice_url: { join: [{ param: url }, { param: voice_path }] }
135
+ voice_method: { param: voice_method }
136
+ sms_url: { join: [{ param: url }, { param: sms_path }] }
137
+ status_callback: { join: [{ param: url }, { param: status_callback_path }] }
138
+ sim:
139
+ write_fields: { FriendlyName: friendly_name, VoiceUrl: voice_url, VoiceMethod: voice_method, SmsUrl: sms_url, StatusCallback: status_callback }
140
+ live:
141
+ params: { account_sid: SPONSON_LIVE_TWILIO_ACCOUNT_SID }