diff --git a/CHANGES.md b/CHANGES.md index 30a45b40b..65ae3c880 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,30 @@ twilio-node changelog ===================== +[2025-01-31] Version 5.5.0 +-------------------------- +**Library - Fix** +- [PR #1061](https://github.com/twilio/twilio-node/pull/1061): validate Twilio signatures with escaped and unescaped query string values fixes #1059. Thanks to [@leon19](https://github.com/leon19)! + +**Api** +- Add open-api file tag to `conference/call recordings` and `recording_transcriptions`. + +**Events** +- Add support for subaccount subscriptions (beta) + +**Insights** +- add new region to conference APIs + +**Lookups** +- Add new `parnter_sub_id` query parameter to the lookup request + +**Messaging** +- Adds validity period Default value in service resource documentation + +**Twiml** +- Convert Twiml Attribute `speechModel` of type enum to string **(breaking change)** + + [2025-01-28] Version 5.4.3 -------------------------- **Library - Fix** diff --git a/src/rest/content/v1/content.ts b/src/rest/content/v1/content.ts index d1bb85c32..3d3ccffd0 100644 --- a/src/rest/content/v1/content.ts +++ b/src/rest/content/v1/content.ts @@ -216,15 +216,6 @@ export class TwilioQuickReply { "actions": Array; } -/** - * twilio/schedule templates allow us to send a message with a schedule with different time slots - */ -export class TwilioSchedule { - "id": string; - "title": string; - "timeSlots": string; -} - /** * Type containing only plain text-based content */ @@ -246,7 +237,6 @@ export class Types { "twilio/catalog"?: TwilioCatalog | null; "twilio/carousel"?: TwilioCarousel | null; "twilio/flows"?: TwilioFlows | null; - "twilio/schedule"?: TwilioSchedule | null; "whatsapp/card"?: WhatsappCard | null; "whatsapp/authentication"?: WhatsappAuthentication | null; } diff --git a/src/rest/conversations/v1/addressConfiguration.ts b/src/rest/conversations/v1/addressConfiguration.ts index bb518b64b..8b6105c72 100644 --- a/src/rest/conversations/v1/addressConfiguration.ts +++ b/src/rest/conversations/v1/addressConfiguration.ts @@ -33,8 +33,7 @@ export type AddressConfigurationType = | "messenger" | "gbm" | "email" - | "rcs" - | "apple"; + | "rcs"; /** * Options to pass to update a AddressConfigurationInstance diff --git a/src/rest/events/v1/subscription.ts b/src/rest/events/v1/subscription.ts index 3bc2774a7..d33103b81 100644 --- a/src/rest/events/v1/subscription.ts +++ b/src/rest/events/v1/subscription.ts @@ -29,8 +29,6 @@ export interface SubscriptionContextUpdateOptions { description?: string; /** The SID of the sink that events selected by this subscription should be sent to. Sink must be active for the subscription to be created. */ sinkSid?: string; - /** Receive events from all children accounts in the parent account subscription. */ - receiveEventsFromSubaccounts?: boolean; } /** @@ -43,8 +41,6 @@ export interface SubscriptionListInstanceCreateOptions { sinkSid: string; /** An array of objects containing the subscribed Event Types */ types: Array; - /** Receive events from all children accounts in the parent account subscription. */ - receiveEventsFromSubaccounts?: boolean; } /** * Options to pass to each @@ -237,10 +233,6 @@ export class SubscriptionContextImpl implements SubscriptionContext { if (params["description"] !== undefined) data["Description"] = params["description"]; if (params["sinkSid"] !== undefined) data["SinkSid"] = params["sinkSid"]; - if (params["receiveEventsFromSubaccounts"] !== undefined) - data["ReceiveEventsFromSubaccounts"] = serialize.bool( - params["receiveEventsFromSubaccounts"] - ); const headers: any = {}; headers["Content-Type"] = "application/x-www-form-urlencoded"; @@ -298,7 +290,6 @@ interface SubscriptionResource { sink_sid: string; url: string; links: Record; - receive_events_from_subaccounts: boolean; } export class SubscriptionInstance { @@ -318,7 +309,6 @@ export class SubscriptionInstance { this.sinkSid = payload.sink_sid; this.url = payload.url; this.links = payload.links; - this.receiveEventsFromSubaccounts = payload.receive_events_from_subaccounts; this._solution = { sid: sid || this.sid }; } @@ -355,10 +345,6 @@ export class SubscriptionInstance { * Contains a dictionary of URL links to nested resources of this Subscription. */ links: Record; - /** - * Receive events from all children accounts in the parent account subscription. - */ - receiveEventsFromSubaccounts: boolean; private get _proxy(): SubscriptionContext { this._context = @@ -445,7 +431,6 @@ export class SubscriptionInstance { sinkSid: this.sinkSid, url: this.url, links: this.links, - receiveEventsFromSubaccounts: this.receiveEventsFromSubaccounts, }; } @@ -595,10 +580,6 @@ export function SubscriptionListInstance( data["Types"] = serialize.map(params["types"], (e: any) => serialize.object(e) ); - if (params["receiveEventsFromSubaccounts"] !== undefined) - data["ReceiveEventsFromSubaccounts"] = serialize.bool( - params["receiveEventsFromSubaccounts"] - ); const headers: any = {}; headers["Content-Type"] = "application/x-www-form-urlencoded"; diff --git a/src/rest/iam/V1.ts b/src/rest/iam/V1.ts index 30b75755c..28484249f 100644 --- a/src/rest/iam/V1.ts +++ b/src/rest/iam/V1.ts @@ -16,7 +16,7 @@ import IamBase from "../IamBase"; import Version from "../../base/Version"; import { ApiKeyListInstance } from "./v1/apiKey"; import { GetApiKeysListInstance } from "./v1/getApiKeys"; -import { NewApiKeyListInstance } from "./v1/newApiKey"; +import { KeyListInstance } from "./v1/key"; export default class V1 extends Version { /** @@ -32,8 +32,8 @@ export default class V1 extends Version { protected _apiKey?: ApiKeyListInstance; /** getApiKeys - { Twilio.Iam.V1.GetApiKeysListInstance } resource */ protected _getApiKeys?: GetApiKeysListInstance; - /** newApiKey - { Twilio.Iam.V1.NewApiKeyListInstance } resource */ - protected _newApiKey?: NewApiKeyListInstance; + /** keys - { Twilio.Iam.V1.KeyListInstance } resource */ + protected _keys?: KeyListInstance; /** Getter for apiKey resource */ get apiKey(): ApiKeyListInstance { @@ -47,9 +47,9 @@ export default class V1 extends Version { return this._getApiKeys; } - /** Getter for newApiKey resource */ - get newApiKey(): NewApiKeyListInstance { - this._newApiKey = this._newApiKey || NewApiKeyListInstance(this); - return this._newApiKey; + /** Getter for keys resource */ + get keys(): KeyListInstance { + this._keys = this._keys || KeyListInstance(this); + return this._keys; } } diff --git a/src/rest/iam/v1/key.ts b/src/rest/iam/v1/key.ts new file mode 100644 index 000000000..36a8f4faa --- /dev/null +++ b/src/rest/iam/v1/key.ts @@ -0,0 +1,194 @@ +/* + * This code was generated by + * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ + * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ + * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ + * + * Twilio - Iam + * This is the public Twilio REST API. + * + * NOTE: This class is auto generated by OpenAPI Generator. + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { inspect, InspectOptions } from "util"; +import V1 from "../V1"; +const deserialize = require("../../../base/deserialize"); +const serialize = require("../../../base/serialize"); +import { isValidPathParam } from "../../../base/utility"; + +export type KeyKeytype = "restricted"; + +/** + * Options to pass to create a KeyInstance + */ +export interface KeyListInstanceCreateOptions { + /** The SID of the [Account](https://www.twilio.com/docs/iam/api/account) that created the Payments resource. */ + accountSid: string; + /** A descriptive string that you create to describe the resource. It can be up to 64 characters long. */ + friendlyName?: string; + /** */ + keyType?: KeyKeytype; + /** The \\\\`Policy\\\\` object is a collection that specifies the allowed Twilio permissions for the restricted key. For more information on the permissions available with restricted API keys, refer to the [Twilio documentation](https://www.twilio.com/docs/iam/api-keys/restricted-api-keys#permissions-available-with-restricted-api-keys). */ + policy?: any; +} + +export interface KeySolution {} + +export interface KeyListInstance { + _version: V1; + _solution: KeySolution; + _uri: string; + + /** + * Create a KeyInstance + * + * @param params - Parameter for request + * @param callback - Callback to handle processed record + * + * @returns Resolves to processed KeyInstance + */ + create( + params: KeyListInstanceCreateOptions, + callback?: (error: Error | null, item?: KeyInstance) => any + ): Promise; + + /** + * Provide a user-friendly representation + */ + toJSON(): any; + [inspect.custom](_depth: any, options: InspectOptions): any; +} + +export function KeyListInstance(version: V1): KeyListInstance { + const instance = {} as KeyListInstance; + + instance._version = version; + instance._solution = {}; + instance._uri = `/Keys`; + + instance.create = function create( + params: KeyListInstanceCreateOptions, + callback?: (error: Error | null, items: KeyInstance) => any + ): Promise { + if (params === null || params === undefined) { + throw new Error('Required parameter "params" missing.'); + } + + if (params["accountSid"] === null || params["accountSid"] === undefined) { + throw new Error("Required parameter \"params['accountSid']\" missing."); + } + + let data: any = {}; + + data["AccountSid"] = params["accountSid"]; + if (params["friendlyName"] !== undefined) + data["FriendlyName"] = params["friendlyName"]; + if (params["keyType"] !== undefined) data["KeyType"] = params["keyType"]; + if (params["policy"] !== undefined) + data["Policy"] = serialize.object(params["policy"]); + + const headers: any = {}; + headers["Content-Type"] = "application/x-www-form-urlencoded"; + headers["Accept"] = "application/json"; + + let operationVersion = version, + operationPromise = operationVersion.create({ + uri: instance._uri, + method: "post", + data, + headers, + }); + + operationPromise = operationPromise.then( + (payload) => new KeyInstance(operationVersion, payload) + ); + + operationPromise = instance._version.setPromiseCallback( + operationPromise, + callback + ); + return operationPromise; + }; + + instance.toJSON = function toJSON() { + return instance._solution; + }; + + instance[inspect.custom] = function inspectImpl( + _depth: any, + options: InspectOptions + ) { + return inspect(instance.toJSON(), options); + }; + + return instance; +} + +interface KeyPayload extends KeyResource {} + +interface KeyResource { + sid: string; + friendly_name: string; + date_created: Date; + date_updated: Date; + secret: string; + policy: any; +} + +export class KeyInstance { + constructor(protected _version: V1, payload: KeyResource) { + this.sid = payload.sid; + this.friendlyName = payload.friendly_name; + this.dateCreated = deserialize.rfc2822DateTime(payload.date_created); + this.dateUpdated = deserialize.rfc2822DateTime(payload.date_updated); + this.secret = payload.secret; + this.policy = payload.policy; + } + + /** + * The unique string that that we created to identify the NewKey resource. You will use this as the basic-auth `user` when authenticating to the API. + */ + sid: string; + /** + * The string that you assigned to describe the resource. + */ + friendlyName: string; + /** + * The date and time in GMT that the API Key was created specified in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + */ + dateCreated: Date; + /** + * The date and time in GMT that the new API Key was last updated specified in [RFC 2822](https://www.ietf.org/rfc/rfc2822.txt) format. + */ + dateUpdated: Date; + /** + * The secret your application uses to sign Access Tokens and to authenticate to the REST API (you will use this as the basic-auth `password`). **Note that for security reasons, this field is ONLY returned when the API Key is first created.** + */ + secret: string; + /** + * Collection of allow assertions. + */ + policy: any; + + /** + * Provide a user-friendly representation + * + * @returns Object + */ + toJSON() { + return { + sid: this.sid, + friendlyName: this.friendlyName, + dateCreated: this.dateCreated, + dateUpdated: this.dateUpdated, + secret: this.secret, + policy: this.policy, + }; + } + + [inspect.custom](_depth: any, options: InspectOptions) { + return inspect(this.toJSON(), options); + } +} diff --git a/src/rest/insights/v1/conference.ts b/src/rest/insights/v1/conference.ts index 9d171541f..b3fbd394f 100644 --- a/src/rest/insights/v1/conference.ts +++ b/src/rest/insights/v1/conference.ts @@ -38,7 +38,6 @@ export type ConferenceProcessingState = "complete" | "in_progress" | "timeout"; export type ConferenceRegion = | "us1" - | "us2" | "au1" | "br1" | "ie1" diff --git a/src/rest/lookups/v2/phoneNumber.ts b/src/rest/lookups/v2/phoneNumber.ts index cd0e83c7e..954a6749b 100644 --- a/src/rest/lookups/v2/phoneNumber.ts +++ b/src/rest/lookups/v2/phoneNumber.ts @@ -58,8 +58,6 @@ export interface PhoneNumberContextFetchOptions { lastVerifiedDate?: string; /** The unique identifier associated with a verification process through verify API. This query parameter is only used (optionally) for pre_fill package requests. */ verificationSid?: string; - /** The optional partnerSubId parameter to provide context for your sub-accounts, tenantIDs, sender IDs or other segmentation, enhancing the accuracy of the risk analysis. */ - partnerSubId?: string; } export interface PhoneNumberContext { @@ -149,8 +147,6 @@ export class PhoneNumberContextImpl implements PhoneNumberContext { data["LastVerifiedDate"] = params["lastVerifiedDate"]; if (params["verificationSid"] !== undefined) data["VerificationSid"] = params["verificationSid"]; - if (params["partnerSubId"] !== undefined) - data["PartnerSubId"] = params["partnerSubId"]; const headers: any = {}; headers["Accept"] = "application/json"; diff --git a/src/rest/numbers/V1.ts b/src/rest/numbers/V1.ts index af82776f7..148a24ce4 100644 --- a/src/rest/numbers/V1.ts +++ b/src/rest/numbers/V1.ts @@ -21,8 +21,8 @@ import { PortingPortInPhoneNumberListInstance } from "./v1/portingPortInPhoneNum import { PortingPortabilityListInstance } from "./v1/portingPortability"; import { PortingWebhookConfigurationListInstance } from "./v1/portingWebhookConfiguration"; import { PortingWebhookConfigurationDeleteListInstance } from "./v1/portingWebhookConfigurationDelete"; -import { PortingWebhookConfigurationFetchListInstance } from "./v1/portingWebhookConfigurationFetch"; import { SigningRequestConfigurationListInstance } from "./v1/signingRequestConfiguration"; +import { WebhookListInstance } from "./v1/webhook"; export default class V1 extends Version { /** @@ -48,10 +48,10 @@ export default class V1 extends Version { protected _portingWebhookConfigurations?: PortingWebhookConfigurationListInstance; /** portingWebhookConfigurationsDelete - { Twilio.Numbers.V1.PortingWebhookConfigurationDeleteListInstance } resource */ protected _portingWebhookConfigurationsDelete?: PortingWebhookConfigurationDeleteListInstance; - /** portingWebhookConfigurationFetch - { Twilio.Numbers.V1.PortingWebhookConfigurationFetchListInstance } resource */ - protected _portingWebhookConfigurationFetch?: PortingWebhookConfigurationFetchListInstance; /** signingRequestConfigurations - { Twilio.Numbers.V1.SigningRequestConfigurationListInstance } resource */ protected _signingRequestConfigurations?: SigningRequestConfigurationListInstance; + /** webhook - { Twilio.Numbers.V1.WebhookListInstance } resource */ + protected _webhook?: WebhookListInstance; /** Getter for bulkEligibilities resource */ get bulkEligibilities(): BulkEligibilityListInstance { @@ -104,14 +104,6 @@ export default class V1 extends Version { return this._portingWebhookConfigurationsDelete; } - /** Getter for portingWebhookConfigurationFetch resource */ - get portingWebhookConfigurationFetch(): PortingWebhookConfigurationFetchListInstance { - this._portingWebhookConfigurationFetch = - this._portingWebhookConfigurationFetch || - PortingWebhookConfigurationFetchListInstance(this); - return this._portingWebhookConfigurationFetch; - } - /** Getter for signingRequestConfigurations resource */ get signingRequestConfigurations(): SigningRequestConfigurationListInstance { this._signingRequestConfigurations = @@ -119,4 +111,10 @@ export default class V1 extends Version { SigningRequestConfigurationListInstance(this); return this._signingRequestConfigurations; } + + /** Getter for webhook resource */ + get webhook(): WebhookListInstance { + this._webhook = this._webhook || WebhookListInstance(this); + return this._webhook; + } } diff --git a/src/rest/numbers/v1/webhook.ts b/src/rest/numbers/v1/webhook.ts new file mode 100644 index 000000000..f48c9294e --- /dev/null +++ b/src/rest/numbers/v1/webhook.ts @@ -0,0 +1,160 @@ +/* + * This code was generated by + * ___ _ _ _ _ _ _ ____ ____ ____ _ ____ ____ _ _ ____ ____ ____ ___ __ __ + * | | | | | | | | | __ | | |__| | __ | __ |___ |\ | |___ |__/ |__| | | | |__/ + * | |_|_| | |___ | |__| |__| | | | |__] |___ | \| |___ | \ | | | |__| | \ + * + * Twilio - Numbers + * This is the public Twilio REST API. + * + * NOTE: This class is auto generated by OpenAPI Generator. + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { inspect, InspectOptions } from "util"; +import V1 from "../V1"; +const deserialize = require("../../../base/deserialize"); +const serialize = require("../../../base/serialize"); +import { isValidPathParam } from "../../../base/utility"; + +export interface WebhookSolution {} + +export interface WebhookListInstance { + _version: V1; + _solution: WebhookSolution; + _uri: string; + + /** + * Fetch a WebhookInstance + * + * @param callback - Callback to handle processed record + * + * @returns Resolves to processed WebhookInstance + */ + fetch( + callback?: (error: Error | null, item?: WebhookInstance) => any + ): Promise; + + /** + * Provide a user-friendly representation + */ + toJSON(): any; + [inspect.custom](_depth: any, options: InspectOptions): any; +} + +export function WebhookListInstance(version: V1): WebhookListInstance { + const instance = {} as WebhookListInstance; + + instance._version = version; + instance._solution = {}; + instance._uri = `/Porting/Configuration/Webhook`; + + instance.fetch = function fetch( + callback?: (error: Error | null, items: WebhookInstance) => any + ): Promise { + const headers: any = {}; + headers["Accept"] = "application/json"; + + let operationVersion = version, + operationPromise = operationVersion.fetch({ + uri: instance._uri, + method: "get", + headers, + }); + + operationPromise = operationPromise.then( + (payload) => new WebhookInstance(operationVersion, payload) + ); + + operationPromise = instance._version.setPromiseCallback( + operationPromise, + callback + ); + return operationPromise; + }; + + instance.toJSON = function toJSON() { + return instance._solution; + }; + + instance[inspect.custom] = function inspectImpl( + _depth: any, + options: InspectOptions + ) { + return inspect(instance.toJSON(), options); + }; + + return instance; +} + +interface WebhookPayload extends WebhookResource {} + +interface WebhookResource { + url: string; + port_in_target_url: string; + port_out_target_url: string; + notifications_of: Array; + port_in_target_date_created: Date; + port_out_target_date_created: Date; +} + +export class WebhookInstance { + constructor(protected _version: V1, payload: WebhookResource) { + this.url = payload.url; + this.portInTargetUrl = payload.port_in_target_url; + this.portOutTargetUrl = payload.port_out_target_url; + this.notificationsOf = payload.notifications_of; + this.portInTargetDateCreated = deserialize.iso8601DateTime( + payload.port_in_target_date_created + ); + this.portOutTargetDateCreated = deserialize.iso8601DateTime( + payload.port_out_target_date_created + ); + } + + /** + * The URL of the webhook configuration request + */ + url: string; + /** + * The complete webhook url that will be called when a notification event for port in request or port in phone number happens + */ + portInTargetUrl: string; + /** + * The complete webhook url that will be called when a notification event for a port out phone number happens. + */ + portOutTargetUrl: string; + /** + * A list to filter what notification events to receive for this account and its sub accounts. If it is an empty list, then it means that there are no filters for the notifications events to send in each webhook and all events will get sent. + */ + notificationsOf: Array; + /** + * Creation date for the port in webhook configuration + */ + portInTargetDateCreated: Date; + /** + * Creation date for the port out webhook configuration + */ + portOutTargetDateCreated: Date; + + /** + * Provide a user-friendly representation + * + * @returns Object + */ + toJSON() { + return { + url: this.url, + portInTargetUrl: this.portInTargetUrl, + portOutTargetUrl: this.portOutTargetUrl, + notificationsOf: this.notificationsOf, + portInTargetDateCreated: this.portInTargetDateCreated, + portOutTargetDateCreated: this.portOutTargetDateCreated, + }; + } + + [inspect.custom](_depth: any, options: InspectOptions) { + return inspect(this.toJSON(), options); + } +} diff --git a/src/twiml/VoiceResponse.ts b/src/twiml/VoiceResponse.ts index 707e80586..8df14b41d 100644 --- a/src/twiml/VoiceResponse.ts +++ b/src/twiml/VoiceResponse.ts @@ -539,13 +539,6 @@ namespace VoiceResponse { | "cmn-Hant-TW" | "zu-ZA"; - type GatherSpeechModel = - | "default" - | "numbers_and_commands" - | "phone_call" - | "experimental_conversations" - | "experimental_utterances"; - type NumberEvent = "initiated" | "ringing" | "answered" | "completed"; type PayBankAccountType = @@ -1426,7 +1419,7 @@ namespace VoiceResponse { /** profanityFilter - Profanity Filter on speech */ profanityFilter?: boolean; /** speechModel - Specify the model that is best suited for your use case */ - speechModel?: GatherSpeechModel; + speechModel?: string; /** speechTimeout - Time to wait to gather speech input and it should be either auto or a positive integer. */ speechTimeout?: string; /** timeout - Time to wait to gather input */