From d5a45341f27f5f2aaec71eb1c811bbfafafb647e Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:25:37 +0100 Subject: [PATCH 01/10] Add base types --- lib/base/Domain.d.ts | 23 ++++++++ lib/base/Page.d.ts | 107 ++++++++++++++++++++++++++++++++++++ lib/base/RequestClient.d.ts | 62 +++++++++++++++++++++ lib/base/RestException.d.ts | 9 +++ lib/base/Version.d.ts | 93 +++++++++++++++++++++++++++++++ lib/base/deserialize.d.ts | 39 +++++++++++++ lib/base/serialize.d.ts | 60 ++++++++++++++++++++ lib/base/values.d.ts | 7 +++ 8 files changed, 400 insertions(+) create mode 100644 lib/base/Domain.d.ts create mode 100644 lib/base/Page.d.ts create mode 100644 lib/base/RequestClient.d.ts create mode 100644 lib/base/RestException.d.ts create mode 100644 lib/base/Version.d.ts create mode 100644 lib/base/deserialize.d.ts create mode 100644 lib/base/serialize.d.ts create mode 100644 lib/base/values.d.ts diff --git a/lib/base/Domain.d.ts b/lib/base/Domain.d.ts new file mode 100644 index 0000000000..2b03fb3c89 --- /dev/null +++ b/lib/base/Domain.d.ts @@ -0,0 +1,23 @@ +import TwilioClient = require('../rest/Twilio'); + +declare class Domain { + constructor(twilio: TwilioClient, baseUrl: string); + + /** + * Turn a uri into an absolute url + * + * @param uri uri to transform + * @return absolute url + */ + absoluteUrl(uri: string): string; + + /** + * Make request to this domain + * + * @param opts request options + * @return request promise + */ + request(opts?: TwilioClient.RequestOptions): Promise; +} + +export = Domain; diff --git a/lib/base/Page.d.ts b/lib/base/Page.d.ts new file mode 100644 index 0000000000..72548e2807 --- /dev/null +++ b/lib/base/Page.d.ts @@ -0,0 +1,107 @@ +import Version = require('./Version'); +import Response = require('../http/response'); + +interface Solution { + +} + +/** + * Base page object to maintain request state. + */ +declare class Page { + /** + * Base page object to maintain request state. + * + * @param version - A twilio version instance + * @param response - The http response + * @param solution - path solution + */ + constructor(version: TVersion, response: Response, solution: Solution); + + /** + * Get the url of the previous page of records + * + * @return url of the previous page + */ + getPreviousPageUrl(): string; + /**w + * Get the url of the next page of records + * + * @return url of the next page + */ + getNextPageUrl(): string; + /** + * Load a list of records + * + * @param resources json payload of records + * @return list of resources + */ + loadInstance(resources: TResource[]): TInstance[]; + /** + * Fetch the next page of records + * + * @return promise that resolves to next page of results + */ + nextPage(): Promise>; + /** + * Fetch the previous page of records + * + * @return promise that resolves to previous page of results + */ + previousPage(): Promise>; + /** + * Parse json response from API + * @throws If non 200 status code is returned + * + * @param response API response + * @return json parsed response + */ + processResponse(response: Response): TPayload; + /** + * Load a page of records + * @throws {Error} If records cannot be deserialized + * + * @param payload json payload + * @return the page of records + */ + loadPage(payload: TPayload): TResource[]; + + /** + * @constant META_KEYS + * @description meta keys returned in a list request + */ + static META_KEYS: [ + 'end', + 'first_page_uri', + 'last_page_uri', + 'next_page_uri', + 'num_pages', + 'page', + 'page_size', + 'previous_page_uri', + 'start', + 'total', + 'uri' + ]; +} + +declare namespace Page { + export interface TwilioResponsePayload { + // DEPRECTATED: end: any; + first_page_uri: string; + // DEPRECTATED: last_page_uri: string; + next_page_uri: string; + // DEPRECTATED: num_pages: number; + page: number; + page_size: number; + previous_page_uri: string; + // DEPRECTATED: start: number; + // DEPRECTATED: total: number; + uri: string; + meta?: { + key?: string; + } + } +} + +export = Page; \ No newline at end of file diff --git a/lib/base/RequestClient.d.ts b/lib/base/RequestClient.d.ts new file mode 100644 index 0000000000..a20f7b3c73 --- /dev/null +++ b/lib/base/RequestClient.d.ts @@ -0,0 +1,62 @@ +import { HttpMethod } from '../interfaces'; +import Response = require('../http/response'); + +declare class RequestClient { + constructor(); + /** + * Make an HTTP request + * @param opts The request options + */ + request(opts: RequestClient.RequestOptions): Promise>; +} + +declare namespace RequestClient { + export interface RequestOptions { + /** + * The HTTP method + */ + method: HttpMethod; + /** + * The request URI + */ + uri: string; + /** + * The username used for auth + */ + username?: string; + /** + * The password used for auth + */ + password?: string; + /** + * The request headers + */ + headers?: Headers; + /** + * The object of params added as query string to the request + */ + params?: TParams; + /** + * The form data that should be submitted + */ + data?: TData; + /** + * The request timeout in milliseconds + */ + timeout?: number; + /** + * Should the client follow redirects + */ + allowRedirects?: boolean; + /** + * Set to true to use the forever-agent + */ + forever?: boolean; + } + + export interface Headers { + [header: string]: string; + } +} + +export = RequestClient; \ No newline at end of file diff --git a/lib/base/RestException.d.ts b/lib/base/RestException.d.ts new file mode 100644 index 0000000000..2a8eb331ec --- /dev/null +++ b/lib/base/RestException.d.ts @@ -0,0 +1,9 @@ +declare class RestException extends Error { + status: number; + message: string; + code: number; + moreInfo: string; + detail: string; +} + +export = RestException; \ No newline at end of file diff --git a/lib/base/Version.d.ts b/lib/base/Version.d.ts new file mode 100644 index 0000000000..6dc03f84f3 --- /dev/null +++ b/lib/base/Version.d.ts @@ -0,0 +1,93 @@ +import Domain = require('./Domain'); +import TwilioClient = require('../rest/Twilio'); + +declare class Version { + constructor(solutelydomain: Domain, version: string); + /** + * Generate absolute url from a uri + * + * @param uri uri to transform + * @return transformed url + */ + absoluteUrl(uri: string): string; + /** + * Generate relative url from a uri + * + * @param uri uri to transform + * @return transformed url + */ + relativeUrl(uri: string): string; + /** + * Make a request against the domain + * + * @param opts request options + * @return promise that resolves to request response + */ + request(opts: TwilioClient.RequestOptions): Promise; + /** + * Fetch a instance of a record + * @throws {Error} If response returns non 2xx status code + * + * @param opts request options + * @return promise that resolves to fetched result + */ + fetch(opts: TwilioClient.RequestOptions): Promise; + /** + * Update a record + * @throws {Error} If response returns non 2xx status code + * + * @param opts request options + * @return promise that resolves to updated result + */ + update(opts: TwilioClient.RequestOptions): Promise; + /** + * Delete a record + * @throws {Error} If response returns a 5xx status + * + * @param opts request options + * @return promise that resolves to true if record was deleted + */ + remove(opts: TwilioClient.RequestOptions): Promise; + /** + * Create a new record + * @throws {Error} If response returns non 2xx or 201 status code + * + * @param opts request options + * @return promise that resolves to created record + */ + create(opts: TwilioClient.RequestOptions): Promise; + /** + * Fetch a page of records + * + * @param opts request options + * @return promise that resolves to page of records + */ + page(opts: TwilioClient.RequestOptions): Promise; + /** + * Process limits for list requests + * + * @param opts Page limit options passed to the request + */ + readLimits(opts: Version.PageLimitOptions): Version.PageLimit; +} + +declare namespace Version { + export interface PageLimitOptions { + /** + * The maximum number of items to fetch + */ + limit: number; + /** + * The maximum number of items to return with every request + */ + pageSize: number; + } + + export interface PageLimit { + limit: number; + pageSize: number; + pageLimit: number; + } +} + +export = Version; \ No newline at end of file diff --git a/lib/base/deserialize.d.ts b/lib/base/deserialize.d.ts new file mode 100644 index 0000000000..be0f3b9445 --- /dev/null +++ b/lib/base/deserialize.d.ts @@ -0,0 +1,39 @@ +/** + * Parse a string into a Date object + * + * @param s date string in YYYY-MM-DD format + * @return Date object + */ +export function iso8601Date(s: string): Date; + +/** + * Parse a string into a Date object + * + * @param s date string in YYYY-MM-DD[T]HH:mm:ss[Z] format + * @return Date object + */ +export function iso8601DateTime(s: string): Date; + +/** + * Parse a string into a Date object + * + * @param s date string in ddd, DD MMM YYYY HH:mm:ss [+0000] format + * @return Date object + */ +export function rfc2822DateTime(s: string): Date; + +/** + * parse a string into a decimal + * + * @param d decimal value as string + * @return number object + */ +export function decimal(d: string): number; + +/** + * Parse a string into a integer + * + * @param i integer value as string + * @return number object + */ +export function integer(i: string): number; \ No newline at end of file diff --git a/lib/base/serialize.d.ts b/lib/base/serialize.d.ts new file mode 100644 index 0000000000..323f0444ed --- /dev/null +++ b/lib/base/serialize.d.ts @@ -0,0 +1,60 @@ +/** + * Turns a Date object into a string if parameter is a Date + * otherwise returns the parameter + * + * @param date date object to format + * @return date formatted in YYYY-MM-DD form + */ +export function iso8601Date(date: Date): string; +export function iso8601Date(data: T): T; + +/** + * Turns a Date object into a string if parameter is a Date + * otherwise returns the parameter + * + * @param date date object to format + * @return date formatted in YYYY-MM-DD[T]HH:mm:ss[Z] form + */ +export function iso8601DateTime(date: Date): string; +export function iso8601DateTime(data: T): T; + +/** + * Turns a map of params int oa flattened map separated by dots + * if the parameter is an object, otherwise returns an empty map + * + * @param m map to transform + * @param prefix to append to each flattened value + * @returns flattened map + */ +export function prefixedCollapsibleMap(m: T, prefix?: string): T; +export function prefixedCollapsibleMap(m: T, prefix?: string): {}; + +/** + * Turns an object into a JSON string if the parameter + * is an object, otherwise returns the passed in object + * + * @param o json object or array + * @returns stringified object + */ +export function object(o: object | Array): string; +export function object(o: T): T; + +/** + * Coerces a boolean literal into a string + * + * @param input boolean or string to be coerced + * @returns a string 'true' or 'false' if passed a boolean, else the value + */ +export function bool(input: boolean): 'true' | 'false'; +export function bool(input: string): string; + +/** + * Maps transform over each element in input if input is an array + * + * @param input array to map transform over, if not an array then it is + * returned as is. + * @returns new array with transform applied to each element. + */ +type MapFunction = (input: TInput) => TOutput; +export function map(input: Array, transform: MapFunction): Array +export function map(input: T, transform?: any): T; \ No newline at end of file diff --git a/lib/base/values.d.ts b/lib/base/values.d.ts new file mode 100644 index 0000000000..9df378aa2a --- /dev/null +++ b/lib/base/values.d.ts @@ -0,0 +1,7 @@ +/** + * Removes all undefined values of an object + * + * @param obj object to filter + * @return object with no undefined values + */ +export function of(obj: TInput): TOutput; \ No newline at end of file From 39968c070e07c7ff4809b980f3a884d764289972 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:26:45 +0100 Subject: [PATCH 02/10] Add basic interfaces and types --- lib/interfaces.d.ts | 78 +++++++++++++++++++++++++++++++++++++++++++++ lib/types.d.ts | 4 +++ 2 files changed, 82 insertions(+) create mode 100644 lib/interfaces.d.ts create mode 100644 lib/types.d.ts diff --git a/lib/interfaces.d.ts b/lib/interfaces.d.ts new file mode 100644 index 0000000000..4627177f0f --- /dev/null +++ b/lib/interfaces.d.ts @@ -0,0 +1,78 @@ +export type HttpMethod = 'get'|'post'|'put'|'patch'|'delete'; + +export type Url = string; + +export type PhoneNumber = string; + +export type Sid = string; + +export interface ListEachOptions { + /** + * Upper limit for the number of records to return. + * each() guarantees never to return more than limit. + * Default is no limit + */ + limit?: number; + /** + * Number of records to fetch per request, + * when not set will use the default value of 50 records. + * If no pageSize is defined but a limit is defined, + * each() will attempt to read the limit with the most efficient + * page size, i.e. min(limit, 1000) + */ + pageSize?: number; + /** + * Function to process each record. If this and a positional + * callback are passed, this one will be used + */ + callback?: (item: TInstance, done: (err?: Error) => void) => void; + /** + * Function to be called upon completion of streaming + */ + done?: (err?: Error) => void; +} + +export interface ListOptions { + /** + * Upper limit for the number of records to return. + * each() guarantees never to return more than limit. + * Default is no limit + */ + limit?: number; + /** + * Number of records to fetch per request, + * when not set will use the default value of 50 records. + * If no pageSize is defined but a limit is defined, + * each() will attempt to read the limit with the most efficient + * page size, i.e. min(limit, 1000) + */ + pageSize?: number; + /** + * Callback to handle list of records + */ + callback?: (items: TInstance[]) => void; +} + +export interface PageOptions { + /** + * PageToken provided by the API + */ + pageToken?: string; + /** + * Page Number, this value is simply for client state + */ + pageNumber?: number; + /** + * Number of records to return, defaults to 50 + */ + pageSize?: number; + /** + * Callback to handle list of records + */ + callback?: (page: TPage) => void; +} + +export interface SomeListInstance { + (): string; + foo(): number; +} diff --git a/lib/types.d.ts b/lib/types.d.ts new file mode 100644 index 0000000000..e7aae3355d --- /dev/null +++ b/lib/types.d.ts @@ -0,0 +1,4 @@ +import * as VoiceResponse from './twiml/VoiceResponse'; +import * as MessagingReponse from './twiml/MessagingResponse'; +import * as FaxResponse from './twiml/FaxResponse'; +export { VoiceResponse, MessagingReponse, FaxResponse }; From aaac0b585f3dc416d51caf82ff9083db2dfe1015 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:27:54 +0100 Subject: [PATCH 03/10] Remove types.d.ts. Not needed --- lib/types.d.ts | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 lib/types.d.ts diff --git a/lib/types.d.ts b/lib/types.d.ts deleted file mode 100644 index e7aae3355d..0000000000 --- a/lib/types.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -import * as VoiceResponse from './twiml/VoiceResponse'; -import * as MessagingReponse from './twiml/MessagingResponse'; -import * as FaxResponse from './twiml/FaxResponse'; -export { VoiceResponse, MessagingReponse, FaxResponse }; From 69cce5bdc6c6aaf6b0e20a61701547d1a4cfb1d9 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:29:25 +0100 Subject: [PATCH 04/10] Remove unnecessary testing code --- lib/interfaces.d.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/interfaces.d.ts b/lib/interfaces.d.ts index 4627177f0f..dcb17aa0bc 100644 --- a/lib/interfaces.d.ts +++ b/lib/interfaces.d.ts @@ -71,8 +71,3 @@ export interface PageOptions { */ callback?: (page: TPage) => void; } - -export interface SomeListInstance { - (): string; - foo(): number; -} From e257ec7a86d47cf8c5c94112491d997a08ce3125 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:31:21 +0100 Subject: [PATCH 05/10] Add HTTP request/response types --- lib/http/request.d.ts | 21 +++++++++++++++++++++ lib/http/response.d.ts | 6 ++++++ 2 files changed, 27 insertions(+) create mode 100644 lib/http/request.d.ts create mode 100644 lib/http/response.d.ts diff --git a/lib/http/request.d.ts b/lib/http/request.d.ts new file mode 100644 index 0000000000..cd57bd1b34 --- /dev/null +++ b/lib/http/request.d.ts @@ -0,0 +1,21 @@ +import { HttpMethod } from '../interfaces'; + +declare class Request { + constructor(opts: RequestOptions); + attributeEqual(lhs: any, rhs: any): boolean; + isEqual(other: Request): boolean; + toString(): string; +} + +declare namespace Request { + export interface RequestOptions { + method?: HttpMethod | '*'; + url?: string; + auth?: string; + params?: string; + data?: TData | '*'; + headers?: object | '*'; + } +} + +export = Request; \ No newline at end of file diff --git a/lib/http/response.d.ts b/lib/http/response.d.ts new file mode 100644 index 0000000000..5760265098 --- /dev/null +++ b/lib/http/response.d.ts @@ -0,0 +1,6 @@ +declare class Response { + constructor(statusCode: number, body: TPayload); + toString(): string; +} + +export = Response; From 34c619db57c6708ff93add6936bb947daeba0432 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:34:10 +0100 Subject: [PATCH 06/10] Add webhook typings --- lib/webhooks/webhooks.d.ts | 109 +++++++++++++++++++++++++++++++++++++ package.json | 5 +- 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 lib/webhooks/webhooks.d.ts diff --git a/lib/webhooks/webhooks.d.ts b/lib/webhooks/webhooks.d.ts new file mode 100644 index 0000000000..f88fb5bbe0 --- /dev/null +++ b/lib/webhooks/webhooks.d.ts @@ -0,0 +1,109 @@ +import { Request, Response } from 'express'; + +type Middleware = ( + request: Request, + response: Response, + next: () => void +) => any; + +export interface RequestValidatorOptions { + /** + * The full URL (with query string) you used to configure the webhook with Twilio - overrides host/protocol options + */ + url: string; + /** + * Manually specify the host name used by Twilio in a number's webhook config + */ + host: string; + /** + * Manually specify the protocol used by Twilio in a number's webhook config + */ + protocol: string; +} + +export interface WebhookOptions { + /** + * Whether or not the middleware should validate the request + * came from Twilio. Default true. If the request does not originate from + * Twilio, we will return a text body and a 403. If there is no configured + * auth token and validate=true, this is an error condition, so we will return + * a 500. + */ + validate: boolean; + /** + * Add helpers to the response object to improve support for XML (TwiML) rendering. Default true. + */ + includeHelpers: boolean; + /** + * Manually specify the host name used by Twilio in a number's webhook config + */ + host: string; + /** + * Manually specify the protocol used by Twilio in a number's webhook config + */ + protocol: string; +} + +/** + * Utility function to validate an incoming request is indeed from Twilio + * + * @param authToken - The auth token, as seen in the Twilio portal + * @param twilioHeader - The value of the X-Twilio-Signature header from the request + * @param url - The full URL (with query string) you configured to handle this request + * @param params - the parameters sent with this request + */ +export function validateRequest( + authToken: string, + twilioHeader: string, + url: string, + params: object +): boolean; + +/** + * Utility function to validate an incoming request is indeed from Twilio (for use with express). + * adapted from https://github.com/crabasa/twiliosig + * + * @param request - An expressjs request object (http://expressjs.com/api.html#req.params) + * @param authToken - The auth token, as seen in the Twilio portal + * @param opts - options for request validation + */ +export function validateExpressRequest( + request: Request, + authToken: string, + opts?: RequestValidatorOptions +): boolean; + +/** + * Express middleware to accompany a Twilio webhook. Provides Twilio + * request validation, and makes the response a little more friendly for our + * TwiML generator. Request validation requires the express.urlencoded middleware + * to have been applied (e.g. app.use(express.urlencoded()); in your app config). + * + * Options: + * - validate: {Boolean} whether or not the middleware should validate the request + * came from Twilio. Default true. If the request does not originate from + * Twilio, we will return a text body and a 403. If there is no configured + * auth token and validate=true, this is an error condition, so we will return + * a 500. + * - includeHelpers: {Boolean} add helpers to the response object to improve support + * for XML (TwiML) rendering. Default true. + * - host: manually specify the host name used by Twilio in a number's webhook config + * - protocol: manually specify the protocol used by Twilio in a number's webhook config + * + * Returns a middleware function. + * + * Examples: + * var webhookMiddleware = twilio.webhook(); + * var webhookMiddleware = twilio.webhook('asdha9dhjasd'); //init with auth token + * var webhookMiddleware = twilio.webhook({ + * validate:false // don't attempt request validation + * }); + * var webhookMiddleware = twilio.webhook({ + * host: 'hook.twilio.com', + * protocol: 'https' + * }); + */ +export function webhook(): Middleware; +export function webhook(opts: WebhookOptions): Middleware; +export function webhook(authToken: string, opts: WebhookOptions): Middleware; +export function webhook(opts: WebhookOptions, authToken: string): Middleware; diff --git a/package.json b/package.json index 531d40da35..84ba820d4f 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "url": "https://github.com/twilio/twilio-node.git" }, "dependencies": { + "@types/express": "^4.11.1", + "deprecate": "1.0.0", "jsonwebtoken": "^8.1.0", "lodash": "4.0.0", "moment": "2.19.3", @@ -27,8 +29,7 @@ "request": "2.83.x", "rootpath": "0.1.2", "scmp": "0.0.3", - "xmlbuilder": "9.0.1", - "deprecate": "1.0.0" + "xmlbuilder": "9.0.1" }, "devDependencies": { "express": "3.x", From f8243387d82a799b5786918f70020da583eeeda2 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:38:48 +0100 Subject: [PATCH 07/10] Add JWT generation typings --- lib/jwt/AccessToken.d.ts | 161 +++++++++++++++++++ lib/jwt/ClientCapability.d.ts | 53 ++++++ lib/jwt/taskrouter/TaskRouterCapability.d.ts | 64 ++++++++ lib/jwt/taskrouter/util.d.ts | 91 +++++++++++ 4 files changed, 369 insertions(+) create mode 100644 lib/jwt/AccessToken.d.ts create mode 100644 lib/jwt/ClientCapability.d.ts create mode 100644 lib/jwt/taskrouter/TaskRouterCapability.d.ts create mode 100644 lib/jwt/taskrouter/util.d.ts diff --git a/lib/jwt/AccessToken.d.ts b/lib/jwt/AccessToken.d.ts new file mode 100644 index 0000000000..156c8585c5 --- /dev/null +++ b/lib/jwt/AccessToken.d.ts @@ -0,0 +1,161 @@ +declare class AccessToken { + static DEFAULT_ALGORITHM: 'HS256'; + static ALGORITHMS: ['HS256', 'HS384', 'HS512']; + + /** + * Creates new AccessToken instance + * + * @param accountSid - The account's unique ID to which access is scoped + * @param keySid - The signing key's unique ID + * @param secret - The secret to sign the token with + * @param options - Options + */ + constructor( + accountSid: string, + keySid: string, + secret: string, + options?: AccessToken.AccessTokenOptions + ); + + /** + * Adds a grant for a respective Twilio service to the access token + * @param grant The grant to add + */ + addGrant>(grant: T): void; + + /** + * Turns the access token instance into a JWT that can be used in the front-end + * @param algorithm The algorithm to sign the JWT + */ + toJwt(algorithm: 'HS256' | 'HS384' | 'HS512'): string; +} + +declare namespace AccessToken { + export abstract class Grant { + constructor(opts?: TOptions); + key: TKey; + toPayload(): TPayload; + } + + export interface TaskRouterGrantOptions { + workspaceSid?: string; + workerSid?: string; + role?: string; + } + + export interface TaskRouterGrantPayload { + workspace_sid?: string; + worker_id?: string; + role?: string; + } + + export class TaskRouterGrant extends Grant< + TaskRouterGrantOptions, + TaskRouterGrantPayload, + 'task_router' + > {} + + export interface ChatGrantOptions { + serviceSid?: string; + endpointId?: string; + deploymentRoleSid?: string; + pushCredentialSid?: string; + } + + export interface ChatGrantPayload { + service_sid?: string; + endpoint_id?: string; + deployment_role_sid?: string; + push_credential_sid?: string; + } + + export class ChatGrant extends Grant< + ChatGrantOptions, + ChatGrantPayload, + 'chat' + > {} + + export class IpMessagingGrant extends Grant< + ChatGrantOptions, + ChatGrantPayload, + 'ip_messaging' + > {} + + export interface ConversationsGrantOptions { + configurationProfileSid?: string; + } + + export interface ConversationsGrantPayload { + configuration_profile_sid?: string; + } + + export class ConversationsGrant extends Grant< + ConversationsGrantOptions, + ConversationsGrantPayload, + 'rtc' + > {} + + export interface VideoGrantOptions { + room?: string; + } + + export interface VideoGrantPayload { + room?: string; + } + + export class VideoGrant extends Grant< + VideoGrantOptions, + VideoGrantPayload, + 'video' + > {} + + export interface SyncGrantOptions { + serviceSid?: string; + endpointId?: string; + } + + export interface SyncGrantPayload { + service_sid?: string; + endpoint_id?: string; + } + + export class SyncGrant extends Grant< + SyncGrantOptions, + SyncGrantPayload, + 'data_sync' + > {} + + export interface VoiceGrantOptions { + outgoingApplicationSid?: string; + outgoingApplicationParams?: object; + pushCredentialSid?: string; + endpointId?: string; + } + + export interface VoiceGrantPayload { + outgoing?: { application_sid: string; params?: object }; + push_credential_sid?: string; + endpoint_id?: string; + } + + export class VoiceGrant extends Grant< + VoiceGrantOptions, + VoiceGrantPayload, + 'voice' + > {} + + export interface AccessTokenOptions { + /** + * Time to live in seconds + */ + ttl: number /** + * The identity of the first person + */; + identity: string /** + * Time from epoch in seconds for not before value + */; + nbf: number; + } +} + +export = AccessToken; diff --git a/lib/jwt/ClientCapability.d.ts b/lib/jwt/ClientCapability.d.ts new file mode 100644 index 0000000000..16aa542e7b --- /dev/null +++ b/lib/jwt/ClientCapability.d.ts @@ -0,0 +1,53 @@ +declare class ClientCapability { + constructor(options: ClientCapability.ClientCapabilityOptions); + + accountSid: string; + authToken: string; + ttl: number; + scopes: ClientCapability.Scope[]; + addScope(scope: ClientCapability.Scope): void; + toJwt(): string; +} + +declare namespace ClientCapability { + export interface Scope { + scope: string; + payload(): string; + } + + export interface OutgoingClientScopeOptions { + applicationSid: string; + clientName?: string; + params?: object; + } + + export class EventStreamScope implements Scope { + constructor(filters: object); + filters: object; + scope: 'scope:stream:subscribe'; + payload(): string; + } + + export class IncomingClientScope implements Scope { + constructor(clientName: string); + clientName: string + scope: 'scope:client:incoming'; + payload(): string; + } + + export class OutgoingClientScope implements Scope { + constructor(options: OutgoingClientScopeOptions); + applicationSid: string; + clientName?: string; + params?: object; + scope: 'scope:client:outgoing'; + payload(): string; + } + + export interface ClientCapabilityOptions { + accountSid: string; + authToken: string; + } +} + +export = ClientCapability; diff --git a/lib/jwt/taskrouter/TaskRouterCapability.d.ts b/lib/jwt/taskrouter/TaskRouterCapability.d.ts new file mode 100644 index 0000000000..ba93403420 --- /dev/null +++ b/lib/jwt/taskrouter/TaskRouterCapability.d.ts @@ -0,0 +1,64 @@ +declare class TaskRouterCapability { + /** + * TaskRouterCapability class + * @param options Options to initiate + */ + constructor(options: TaskRouterCapability.TaskRouterCapabilityOptions); + + accountSid: string; + authToken: string; + workspaceSid: string; + channelId: string; + ttl: number; + version: string; + policies: TaskRouterCapability.Policy[]; + friendlyName?: string; + + addPolicy(policy: TaskRouterCapability.Policy): void; + toJwt(): string; +} + +declare namespace TaskRouterCapability { + export interface TaskRouterCapabilityOptions { + accountSid: string; + authToken: string; + workspaceSid: string; + channelId: string; + friendlyName?: string; + ttl?: number; + version?: string; + } + + export interface PolicyOptions { + /** Policy URL */ + url?: string; + /** HTTP Method */ + method?: string; + /** Request query filter allowances */ + queryFilter?: object; + /** Request post filter allowances */ + postFilter?: object; + /** Allow the policy */ + allowed?: boolean; + } + + export interface PolicyPayload { + url: string; + method: string; + query_filter: object; + post_filter: object; + allow: boolean; + } + + export class Policy { + /** + * Create a new Policy + * @param options Options to initiate policy + */ + constructor(options: PolicyOptions); + + payload(): PolicyPayload; + } +} + +export = TaskRouterCapability; diff --git a/lib/jwt/taskrouter/util.d.ts b/lib/jwt/taskrouter/util.d.ts new file mode 100644 index 0000000000..1794a1005a --- /dev/null +++ b/lib/jwt/taskrouter/util.d.ts @@ -0,0 +1,91 @@ +import TaskRouterCapability = require('./TaskRouterCapability'); + +/** + * Build the default Policies for a worker + * + * @param version TaskRouter version + * @param workspaceSid workspace sid + * @param workerSid worker sid + * @returns list of Policies + */ +export function defaultWorkerPolicies( + version: string, + workspaceSid: string, + workerSid: string +): TaskRouterCapability.Policy[]; + +/** + * Build the default Event Bridge Policies + * + * @param accountSid account sid + * @param channelId channel id + * @returns list of Policies + */ +export function defaultEventBridgePolicies( + accountSid: string, + channelId: string +): TaskRouterCapability.Policy[]; + +/** + * Generate TaskRouter workspace url + * + * @param workspaceSid workspace sid or '**' for all workspaces + * @return generated url + */ +export function workspacesUrl(workspaceSid?: string): string; + +/** + * Generate TaskRouter task queue url + * + * @param workspaceSid workspace sid + * @param taskQueueSid task queue sid or '**' for all task queues + * @return generated url + */ +export function taskQueuesUrl( + workspaceSid: string, + taskQueueSid?: string +): string; + +/** + * Generate TaskRouter task url + * + * @param workspaceSid workspace sid + * @param taskSid task sid or '**' for all tasks + * @returns generated url + */ +export function tasksUrl(workspaceSid: string, taskSid?: string): string; + +/** + * Generate TaskRouter activity url + * + * @param workspaceSid workspace sid + * @param activitySid activity sid or '**' for all activities + * @returns generated url + */ +export function activitiesUrl( + workspaceSid: string, + activitySid?: string +): string; + +/** + * Generate TaskRouter worker url + * + * @param workspaceSid workspace sid + * @param workerSid worker sid or '**' for all workers + * @returns generated url + */ +export function workersUrl(workspaceSid: string, workerSid?: string): string; + +/** + * Generate TaskRouter worker reservation url + * + * @param workspaceSid workspace sid + * @param workerSid worker sid + * @param reservationSid reservation sid or '**' for all reservations + * @returns generated url + */ +export function reservationsUrl( + workspaceSid: string, + workerSid: string, + reservationSid?: string +): string; From 514421a59ef9a1c04e6cad50903ebd084615a9e0 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:42:42 +0100 Subject: [PATCH 08/10] Add typings entry file --- index.d.ts | 43 +++++++++++++++++++++++++++++++++++++++++++ package.json | 4 +++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 index.d.ts diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000000..845eb79136 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,43 @@ +import * as VoiceResponse from './lib/twiml/VoiceResponse'; +import * as MessagingResponse from './lib/twiml/MessagingResponse'; +import * as FaxResponse from './lib/twiml/FaxResponse'; +import * as webhookTools from './lib/webhooks/webhooks'; +import * as util from './lib/jwt/taskrouter/util'; + +import TwilioClient = require('./lib/rest/Twilio'); +import AccessToken = require('./lib/jwt/AccessToken'); +import ClientCapability = require('./lib/jwt/ClientCapability'); +import TaskRouterCapability = require('./lib/jwt/taskrouter/TaskRouterCapability'); + +interface TwimlConstructor { + new (): T; +} + +declare function twilio( + accountSid?: string, + authToken?: string, + opts?: TwilioClient.TwilioClientOptions +): TwilioClient; + +declare namespace twilio { + export interface TwimlInterface { + VoiceResponse: typeof VoiceResponse; + FaxResponse: typeof FaxResponse; + MessagingResponse: typeof MessagingResponse; + } + export interface JwtInterface { + AccessToken: typeof AccessToken; + ClientCapability: typeof ClientCapability; + taskrouter: { + TaskRouterCapability: typeof TaskRouterCapability; + util: typeof util; + }; + } + export const jwt: JwtInterface; + export const twiml: TwimlInterface; + export const validateRequest: typeof webhookTools.validateRequest; + export const validateExpressRequest: typeof webhookTools.validateExpressRequest; + export const webhook: typeof webhookTools.webhook; +} + +export = twilio; diff --git a/package.json b/package.json index 84ba820d4f..32286e638d 100644 --- a/package.json +++ b/package.json @@ -51,9 +51,11 @@ }, "files": [ "lib", - "index.js" + "index.js", + "index.d.ts" ], "main": "./lib", + "types": "./index.d.ts", "engines": { "node": ">=0.12.0" }, From 4e7fda8754bbcbf493f5ab49bcaca247a9170c19 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:46:20 +0100 Subject: [PATCH 09/10] Add example file and test command. Not in use yet --- examples/typescript/example.ts | 140 +++++++++++++++++++++++++++++++++ package.json | 6 +- 2 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 examples/typescript/example.ts diff --git a/examples/typescript/example.ts b/examples/typescript/example.ts new file mode 100644 index 0000000000..a16fb3bd6f --- /dev/null +++ b/examples/typescript/example.ts @@ -0,0 +1,140 @@ +import * as _ from 'lodash'; +import twilio = require('../../'); +import { MessageListCreateOptions } from '../../lib/rest/api/v2010/account/message'; + +const accountSid: string = process.env.TWILIO_ACCOUNT_SID || ''; +const token: string = process.env.TWILIO_AUTH_TOKEN || ''; + +const client = twilio(accountSid, token); + +let i: number = 0; +client.calls.each({ + pageSize: 7, + callback: (call, done) => { + console.log(call.sid); + i++; + if (i === 10) { + done(); + } + }, + done: err => { + console.log('je suis fini'); + console.log(err); + } +}); + +client.calls.each(call => { + console.log(call.sid); +}); + +const from = process.env.FROM_NUMBER || ''; +const to = process.env.TO_NUMBER || ''; + +const msgData: MessageListCreateOptions = { + from, + to, + body: 'create using callback' +} + +// Send message using callback +client.messages.create(msgData, + (err, result) => { + console.log('Created message using callback'); + console.log(result.sid); + } +); + +// Send message using promise +const promise = client.messages.create({ + from: from, + to: to, + body: 'create using promises' +}); +promise.then(function(message) { + console.log('Created message using promises'); + console.log(message.sid); +}); + +// Create sip trunk using callback as first parameter +client.trunking.v1.trunks.create(function(err, result) { + console.log('Created default trunk'); + console.log(result.sid); +}); + +// Create sip trunk using callback as second parameter +client.trunking.v1.trunks.create( + { + friendlyName: 'sip trunking' + }, + function(err, result) { + console.log('Created trunk with friendly name'); + console.log(result.sid); + console.log(result.friendlyName); + } +); + +const promiseTrunk = client.trunking.v1.trunks.create({ + friendlyName: 'promise trunking' +}); +promiseTrunk.then(function(trunk) { + console.log('Created trunk with friendly name and promises'); + console.log(trunk.sid); + console.log(trunk.friendlyName); +}); + +const trunkSid = 'TK7e37e59861c14bb80dde245cfaad5522'; + +// Fetch trunk sid using callback +client.trunking.v1.trunks(trunkSid).fetch(function(err, result) { + console.log('Fetch trunk using callback'); + console.log(result.sid); +}); + +// Fetch trunk using promise +const promiseTrunk2 = client.trunking.v1.trunks(trunkSid).fetch(); +promiseTrunk2.then(function(trunk) { + console.log('Fetch trunk using promise'); + console.log(trunk.sid); +}); + +// Update trunk using callback +client.trunking.v1.trunks(trunkSid).update( + { + friendlyName: 'callback trunk' + }, + function(err, result) { + console.log('Updated using callbacks'); + console.log(result.sid); + console.log(result.friendlyName); + } +); + +// Update trunk using promise +const promiseTrunk3 = client.trunking.v1.trunks(trunkSid).update({ + friendlyName: 'promise trunk' +}); +promiseTrunk3.then(function(trunk) { + console.log('Updated trunk with friendly name and promises'); + console.log(trunk.sid); + console.log(trunk.friendlyName); +}); + +// List messages using callbacks +client.messages.list(function(err, messages) { + console.log('Listing messages using callbacks'); + _.each(messages, function(message) { + console.log(message.sid); + }); +}); + +// List messages using promises +const promiseMessage = client.messages.list(); +promiseMessage.then(function(messages) { + console.log('Listing messages using promises'); + _.each(messages, function(message) { + console.log(message.sid); + }); +}); + +const twiml = new twilio.twiml.VoiceResponse(); +twiml.dial({}) \ No newline at end of file diff --git a/package.json b/package.json index 32286e638d..976fa977ad 100644 --- a/package.json +++ b/package.json @@ -32,16 +32,20 @@ "xmlbuilder": "9.0.1" }, "devDependencies": { + "@types/lodash": "^4.14.104", + "@types/node": "^9.4.6", "express": "3.x", "jasmine-node": "1.14.5", "jscs": "3.0.7", "jsdoc": "3.5.5", "jshint": "2.8.x", "nsp": "2.8.0", - "proxyquire": "1.8.0" + "proxyquire": "1.8.0", + "typescript": "^2.7.2" }, "scripts": { "test": "jasmine-node --captureExceptions spec", + "test:typescript": "tsc examples/typescript/example.ts --noEmit --strict", "jshint": "jshint lib/rest/** lib/base/** lib/http/**", "jscs": "jscs -c .jscsrc lib/base/** lib/http/** --fix", "check": "npm run jshint && npm run jscs", From 2b59af70152b3b7015e6c65fc481730ffb14fd40 Mon Sep 17 00:00:00 2001 From: Dominik Kundel Date: Thu, 8 Mar 2018 11:52:31 +0100 Subject: [PATCH 10/10] Remove typings from JS style checking --- .jscsrc | 1 + .jshintignore | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.jscsrc b/.jscsrc index 6aa6fce280..f47bae1337 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,4 +1,5 @@ { + "excludeFiles": [".git", "node_modules", "lib/**/*.d.ts", "index.d.ts"], "disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true }, diff --git a/.jshintignore b/.jshintignore index 86b9017029..f7161f4943 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1 +1,3 @@ spec/integration/** +lib/**/*.d.ts +index.d.ts