nylas 6.5.1 → 7.0.0-beta.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.
- package/README.md +9 -5
- package/lib/config.d.ts +53 -0
- package/lib/config.js +56 -0
- package/lib/models/scheduler.d.ts +2 -2
- package/lib/models/scheduler.js +2 -2
- package/lib/models/webhook.d.ts +1 -0
- package/lib/models/webhook.js +1 -0
- package/lib/nylas.d.ts +41 -16
- package/lib/nylas.js +58 -34
- package/lib/server-bindings/express-binding.d.ts +18 -0
- package/lib/server-bindings/express-binding.js +163 -0
- package/lib/server-bindings/server-binding.d.ts +65 -0
- package/lib/server-bindings/server-binding.js +87 -0
- package/lib/services/routes.d.ts +26 -0
- package/lib/services/routes.js +95 -0
- package/lib/services/tunnel.d.ts +29 -0
- package/lib/services/tunnel.js +112 -0
- package/package.json +9 -2
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Here are some resources to help you get started:
|
|
|
20
20
|
|
|
21
21
|
## ⚙️ Install
|
|
22
22
|
|
|
23
|
-
To
|
|
23
|
+
To install the Nylas Node SDK, you will first need to have [Node](https://nodejs.org/en/download/) and [npm](https://www.npmjs.com/get-npm) installed on your machine.
|
|
24
24
|
|
|
25
25
|
Then, head to the nearest command line and run the following:
|
|
26
26
|
`npm install nylas`
|
|
@@ -37,22 +37,26 @@ npm install
|
|
|
37
37
|
|
|
38
38
|
## ⚡️ Usage
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
The SDK entrypoint and application resources (i.e., application accounts, authentication, webhooks) is accessed via an instance of `Nylas`. You can initialize a `Nylas` instance with your `clientId` and `clientSecret`.
|
|
41
41
|
|
|
42
42
|
```javascript
|
|
43
43
|
const Nylas = require('nylas');
|
|
44
44
|
|
|
45
|
-
Nylas
|
|
45
|
+
const nylasClient = new Nylas({
|
|
46
46
|
clientId: CLIENT_ID,
|
|
47
47
|
clientSecret: CLIENT_SECRET,
|
|
48
48
|
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Every account resource (i.e., messages, events, contacts) is accessed via an instance of `NylasConnection`. To initialize an instance of `NylasConnection`, call `with` on your `Nylas` instance and pass it your `accessToken`.
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
```javascript
|
|
54
|
+
const nylasConnection = nylasClient.with(ACCESS_TOKEN);
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
Then, you can use Nylas to access information about a user's account:
|
|
54
58
|
```javascript
|
|
55
|
-
|
|
59
|
+
nylasConnection.threads.list().then(threads => {
|
|
56
60
|
console.log(threads.length);
|
|
57
61
|
});
|
|
58
62
|
```
|
package/lib/config.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { WebhookTriggers } from './models/webhook';
|
|
2
|
+
import ExpressBinding from './server-bindings/express-binding';
|
|
3
|
+
import AccessToken from './models/access-token';
|
|
1
4
|
export declare let apiServer: string | null;
|
|
2
5
|
export declare function setApiServer(newApiServer: string | null): void;
|
|
3
6
|
export declare let clientSecret: string;
|
|
@@ -15,3 +18,53 @@ export declare type AuthenticateUrlConfig = {
|
|
|
15
18
|
provider?: string;
|
|
16
19
|
scopes?: string[];
|
|
17
20
|
};
|
|
21
|
+
export declare enum Region {
|
|
22
|
+
Us = "us",
|
|
23
|
+
Canada = "canada",
|
|
24
|
+
Ireland = "ireland",
|
|
25
|
+
Australia = "australia",
|
|
26
|
+
Staging = "staging"
|
|
27
|
+
}
|
|
28
|
+
export declare const DEFAULT_REGION = Region.Us;
|
|
29
|
+
export declare const regionConfig: {
|
|
30
|
+
us: {
|
|
31
|
+
nylasAPIUrl: string;
|
|
32
|
+
dashboardApiUrl: string;
|
|
33
|
+
callbackDomain: string;
|
|
34
|
+
websocketDomain: string;
|
|
35
|
+
telemetryApiUrl: string;
|
|
36
|
+
};
|
|
37
|
+
canada: {
|
|
38
|
+
nylasAPIUrl: string;
|
|
39
|
+
dashboardApiUrl: string;
|
|
40
|
+
callbackDomain: string;
|
|
41
|
+
websocketDomain: string;
|
|
42
|
+
telemetryApiUrl: string;
|
|
43
|
+
};
|
|
44
|
+
ireland: {
|
|
45
|
+
nylasAPIUrl: string;
|
|
46
|
+
dashboardApiUrl: string;
|
|
47
|
+
callbackDomain: string;
|
|
48
|
+
websocketDomain: string;
|
|
49
|
+
telemetryApiUrl: string;
|
|
50
|
+
};
|
|
51
|
+
australia: {
|
|
52
|
+
nylasAPIUrl: string;
|
|
53
|
+
dashboardApiUrl: string;
|
|
54
|
+
callbackDomain: string;
|
|
55
|
+
websocketDomain: string;
|
|
56
|
+
telemetryApiUrl: string;
|
|
57
|
+
};
|
|
58
|
+
staging: {
|
|
59
|
+
nylasAPIUrl: string;
|
|
60
|
+
dashboardApiUrl: string;
|
|
61
|
+
callbackDomain: string;
|
|
62
|
+
websocketDomain: string;
|
|
63
|
+
telemetryApiUrl: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
export declare const DEFAULT_WEBHOOK_TRIGGERS: WebhookTriggers[];
|
|
67
|
+
export declare const ServerBindings: {
|
|
68
|
+
express: typeof ExpressBinding;
|
|
69
|
+
};
|
|
70
|
+
export declare type ExchangeCodeForTokenCallback = (error: Error | null, accessToken?: AccessToken) => void;
|
package/lib/config.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
var _a;
|
|
2
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
var webhook_1 = require("./models/webhook");
|
|
8
|
+
var express_binding_1 = __importDefault(require("./server-bindings/express-binding"));
|
|
3
9
|
exports.apiServer = null;
|
|
4
10
|
function setApiServer(newApiServer) {
|
|
5
11
|
exports.apiServer = newApiServer;
|
|
@@ -10,3 +16,53 @@ function setClientSecret(newClientSecret) {
|
|
|
10
16
|
exports.clientSecret = newClientSecret;
|
|
11
17
|
}
|
|
12
18
|
exports.setClientSecret = setClientSecret;
|
|
19
|
+
var Region;
|
|
20
|
+
(function (Region) {
|
|
21
|
+
Region["Us"] = "us";
|
|
22
|
+
Region["Canada"] = "canada";
|
|
23
|
+
Region["Ireland"] = "ireland";
|
|
24
|
+
Region["Australia"] = "australia";
|
|
25
|
+
Region["Staging"] = "staging";
|
|
26
|
+
})(Region = exports.Region || (exports.Region = {}));
|
|
27
|
+
exports.DEFAULT_REGION = Region.Us;
|
|
28
|
+
exports.regionConfig = (_a = {},
|
|
29
|
+
_a[Region.Us] = {
|
|
30
|
+
nylasAPIUrl: 'https://api.nylas.com',
|
|
31
|
+
dashboardApiUrl: 'https://dashboard-api.nylas.com',
|
|
32
|
+
callbackDomain: 'cb.nylas.com',
|
|
33
|
+
websocketDomain: 'tunnel.nylas.com',
|
|
34
|
+
telemetryApiUrl: 'https://cli.nylas.com',
|
|
35
|
+
},
|
|
36
|
+
_a[Region.Canada] = {
|
|
37
|
+
nylasAPIUrl: 'https://canada.api.nylas.com',
|
|
38
|
+
dashboardApiUrl: 'https://canada.dashboard.nylas.com',
|
|
39
|
+
callbackDomain: 'cb.nylas.com',
|
|
40
|
+
websocketDomain: 'tunnel.nylas.com',
|
|
41
|
+
telemetryApiUrl: 'https://cli.nylas.com',
|
|
42
|
+
},
|
|
43
|
+
_a[Region.Ireland] = {
|
|
44
|
+
nylasAPIUrl: 'https://ireland.api.nylas.com',
|
|
45
|
+
dashboardApiUrl: 'https://ireland.dashboard.nylas.com',
|
|
46
|
+
callbackDomain: 'cb.nylas.com',
|
|
47
|
+
websocketDomain: 'tunnel.nylas.com',
|
|
48
|
+
telemetryApiUrl: 'https://cli.nylas.com',
|
|
49
|
+
},
|
|
50
|
+
_a[Region.Australia] = {
|
|
51
|
+
nylasAPIUrl: 'https://australia.api.nylas.com',
|
|
52
|
+
dashboardApiUrl: 'https://australia.dashboard.nylas.com',
|
|
53
|
+
callbackDomain: 'cb.nylas.com',
|
|
54
|
+
websocketDomain: 'tunnel.nylas.com',
|
|
55
|
+
telemetryApiUrl: 'https://cli.nylas.com',
|
|
56
|
+
},
|
|
57
|
+
_a[Region.Staging] = {
|
|
58
|
+
nylasAPIUrl: 'https://api-staging.nylas.com',
|
|
59
|
+
dashboardApiUrl: 'https://staging-dashboard.nylas.com',
|
|
60
|
+
callbackDomain: 'cb.nylas.com',
|
|
61
|
+
websocketDomain: 'tunnel.nylas.com',
|
|
62
|
+
telemetryApiUrl: 'https://cli.nylas.com',
|
|
63
|
+
},
|
|
64
|
+
_a);
|
|
65
|
+
exports.DEFAULT_WEBHOOK_TRIGGERS = Object.values(webhook_1.WebhookTriggers);
|
|
66
|
+
exports.ServerBindings = {
|
|
67
|
+
express: express_binding_1.default,
|
|
68
|
+
};
|
|
@@ -99,7 +99,7 @@ export declare type SchedulerBookingProperties = {
|
|
|
99
99
|
calendarInviteToGuests?: boolean;
|
|
100
100
|
cancellationPolicy?: string;
|
|
101
101
|
confirmationEmailsToGuests?: boolean;
|
|
102
|
-
|
|
102
|
+
confirmationEmailsToHost?: boolean;
|
|
103
103
|
confirmationMethod?: string;
|
|
104
104
|
minBookingNotice?: number;
|
|
105
105
|
minBuffer?: number;
|
|
@@ -116,7 +116,7 @@ export declare class SchedulerBooking extends Model implements SchedulerBookingP
|
|
|
116
116
|
calendarInviteToGuests?: boolean;
|
|
117
117
|
cancellationPolicy?: string;
|
|
118
118
|
confirmationEmailsToGuests?: boolean;
|
|
119
|
-
|
|
119
|
+
confirmationEmailsToHost?: boolean;
|
|
120
120
|
confirmationMethod?: string;
|
|
121
121
|
minBookingNotice?: number;
|
|
122
122
|
minBuffer?: number;
|
package/lib/models/scheduler.js
CHANGED
|
@@ -228,8 +228,8 @@ var SchedulerBooking = /** @class */ (function (_super) {
|
|
|
228
228
|
modelKey: 'confirmationEmailsToGuests',
|
|
229
229
|
jsonKey: 'confirmation_emails_to_guests',
|
|
230
230
|
}),
|
|
231
|
-
|
|
232
|
-
modelKey: '
|
|
231
|
+
confirmationEmailsToHost: attributes_1.default.Boolean({
|
|
232
|
+
modelKey: 'confirmationEmailsToHost',
|
|
233
233
|
jsonKey: 'confirmation_emails_to_host',
|
|
234
234
|
}),
|
|
235
235
|
confirmationMethod: attributes_1.default.String({
|
package/lib/models/webhook.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare enum WebhookTriggers {
|
|
|
8
8
|
AccountStopped = "account.stopped",
|
|
9
9
|
AccountInvalid = "account.invalid",
|
|
10
10
|
AccountSyncError = "account.sync_error",
|
|
11
|
+
MessageBounced = "message.bounced",
|
|
11
12
|
MessageCreated = "message.created",
|
|
12
13
|
MessageOpened = "message.opened",
|
|
13
14
|
MessageUpdated = "message.updated",
|
package/lib/models/webhook.js
CHANGED
|
@@ -25,6 +25,7 @@ var WebhookTriggers;
|
|
|
25
25
|
WebhookTriggers["AccountStopped"] = "account.stopped";
|
|
26
26
|
WebhookTriggers["AccountInvalid"] = "account.invalid";
|
|
27
27
|
WebhookTriggers["AccountSyncError"] = "account.sync_error";
|
|
28
|
+
WebhookTriggers["MessageBounced"] = "message.bounced";
|
|
28
29
|
WebhookTriggers["MessageCreated"] = "message.created";
|
|
29
30
|
WebhookTriggers["MessageOpened"] = "message.opened";
|
|
30
31
|
WebhookTriggers["MessageUpdated"] = "message.updated";
|
package/lib/nylas.d.ts
CHANGED
|
@@ -5,28 +5,53 @@ import Connect from './models/connect';
|
|
|
5
5
|
import RestfulModelCollection from './models/restful-model-collection';
|
|
6
6
|
import ManagementModelCollection from './models/management-model-collection';
|
|
7
7
|
import Webhook from './models/webhook';
|
|
8
|
-
import { AuthenticateUrlConfig, NylasConfig } from './config';
|
|
8
|
+
import { AuthenticateUrlConfig, ExchangeCodeForTokenCallback, NylasConfig } from './config';
|
|
9
9
|
import AccessToken from './models/access-token';
|
|
10
10
|
import ApplicationDetails, { ApplicationDetailsProperties } from './models/application-details';
|
|
11
11
|
declare class Nylas {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
12
|
+
clientId: string;
|
|
13
|
+
get clientSecret(): string;
|
|
14
|
+
set clientSecret(newClientSecret: string);
|
|
15
|
+
get apiServer(): string | null;
|
|
16
|
+
set apiServer(newApiServer: string | null);
|
|
17
|
+
accounts: ManagementModelCollection<ManagementAccount> | RestfulModelCollection<Account>;
|
|
18
|
+
connect: Connect;
|
|
19
|
+
webhooks: ManagementModelCollection<Webhook>;
|
|
20
|
+
constructor(config: NylasConfig);
|
|
21
|
+
/**
|
|
22
|
+
* Checks if the Nylas instance has been configured with credentials
|
|
23
|
+
* @return True if the Nylas instance has been configured with credentials
|
|
24
|
+
*/
|
|
25
|
+
clientCredentials(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Configure a NylasConnection instance to access a user's resources
|
|
28
|
+
* @param accessToken The access token to access the user's resources
|
|
29
|
+
* @return The configured NylasConnection instance
|
|
30
|
+
*/
|
|
31
|
+
with(accessToken: string): NylasConnection;
|
|
32
|
+
/**
|
|
33
|
+
* Return information about a Nylas application
|
|
34
|
+
* @param options Application details to overwrite
|
|
35
|
+
* @return Information about the Nylas application
|
|
36
|
+
*/
|
|
37
|
+
application(options?: ApplicationDetailsProperties): Promise<ApplicationDetails>;
|
|
38
|
+
/**
|
|
39
|
+
* Exchange an authorization code for an access token
|
|
40
|
+
* @param code One-time authorization code from Nylas
|
|
41
|
+
* @param callback Callback before returning the access token
|
|
42
|
+
* @return The {@link AccessToken} object containing the access token and other information
|
|
43
|
+
*/
|
|
44
|
+
exchangeCodeForToken(code: string, callback?: ExchangeCodeForTokenCallback): Promise<AccessToken>;
|
|
45
|
+
/**
|
|
46
|
+
* Build the URL for authenticating users to your application via Hosted Authentication
|
|
47
|
+
* @param options Configuration for the authentication process
|
|
48
|
+
* @return The URL for hosted authentication
|
|
49
|
+
*/
|
|
50
|
+
urlForAuthentication(options: AuthenticateUrlConfig): string;
|
|
26
51
|
/**
|
|
27
52
|
* Revoke a single access token
|
|
28
53
|
* @param accessToken The access token to revoke
|
|
29
54
|
*/
|
|
30
|
-
|
|
55
|
+
revoke(accessToken: string): Promise<void>;
|
|
31
56
|
}
|
|
32
57
|
export = Nylas;
|
package/lib/nylas.js
CHANGED
|
@@ -23,29 +23,8 @@ var webhook_1 = __importDefault(require("./models/webhook"));
|
|
|
23
23
|
var access_token_1 = __importDefault(require("./models/access-token"));
|
|
24
24
|
var application_details_1 = __importDefault(require("./models/application-details"));
|
|
25
25
|
var Nylas = /** @class */ (function () {
|
|
26
|
-
function Nylas() {
|
|
27
|
-
|
|
28
|
-
Object.defineProperty(Nylas, "clientSecret", {
|
|
29
|
-
get: function () {
|
|
30
|
-
return config.clientSecret;
|
|
31
|
-
},
|
|
32
|
-
set: function (newClientSecret) {
|
|
33
|
-
config.setClientSecret(newClientSecret);
|
|
34
|
-
},
|
|
35
|
-
enumerable: true,
|
|
36
|
-
configurable: true
|
|
37
|
-
});
|
|
38
|
-
Object.defineProperty(Nylas, "apiServer", {
|
|
39
|
-
get: function () {
|
|
40
|
-
return config.apiServer;
|
|
41
|
-
},
|
|
42
|
-
set: function (newApiServer) {
|
|
43
|
-
config.setApiServer(newApiServer);
|
|
44
|
-
},
|
|
45
|
-
enumerable: true,
|
|
46
|
-
configurable: true
|
|
47
|
-
});
|
|
48
|
-
Nylas.config = function (config) {
|
|
26
|
+
function Nylas(config) {
|
|
27
|
+
this.clientId = '';
|
|
49
28
|
if (config.apiServer && config.apiServer.indexOf('://') === -1) {
|
|
50
29
|
throw new Error('Please specify a fully qualified URL for the API Server.');
|
|
51
30
|
}
|
|
@@ -73,17 +52,51 @@ var Nylas = /** @class */ (function () {
|
|
|
73
52
|
this.accounts = new restful_model_collection_1.default(account_1.default, conn);
|
|
74
53
|
}
|
|
75
54
|
return this;
|
|
76
|
-
}
|
|
77
|
-
Nylas.
|
|
55
|
+
}
|
|
56
|
+
Object.defineProperty(Nylas.prototype, "clientSecret", {
|
|
57
|
+
get: function () {
|
|
58
|
+
return config.clientSecret;
|
|
59
|
+
},
|
|
60
|
+
set: function (newClientSecret) {
|
|
61
|
+
config.setClientSecret(newClientSecret);
|
|
62
|
+
},
|
|
63
|
+
enumerable: true,
|
|
64
|
+
configurable: true
|
|
65
|
+
});
|
|
66
|
+
Object.defineProperty(Nylas.prototype, "apiServer", {
|
|
67
|
+
get: function () {
|
|
68
|
+
return config.apiServer;
|
|
69
|
+
},
|
|
70
|
+
set: function (newApiServer) {
|
|
71
|
+
config.setApiServer(newApiServer);
|
|
72
|
+
},
|
|
73
|
+
enumerable: true,
|
|
74
|
+
configurable: true
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Checks if the Nylas instance has been configured with credentials
|
|
78
|
+
* @return True if the Nylas instance has been configured with credentials
|
|
79
|
+
*/
|
|
80
|
+
Nylas.prototype.clientCredentials = function () {
|
|
78
81
|
return this.clientId != null && this.clientSecret != null;
|
|
79
82
|
};
|
|
80
|
-
|
|
83
|
+
/**
|
|
84
|
+
* Configure a NylasConnection instance to access a user's resources
|
|
85
|
+
* @param accessToken The access token to access the user's resources
|
|
86
|
+
* @return The configured NylasConnection instance
|
|
87
|
+
*/
|
|
88
|
+
Nylas.prototype.with = function (accessToken) {
|
|
81
89
|
if (!accessToken) {
|
|
82
90
|
throw new Error('This function requires an access token');
|
|
83
91
|
}
|
|
84
92
|
return new nylas_connection_1.default(accessToken, { clientId: this.clientId });
|
|
85
93
|
};
|
|
86
|
-
|
|
94
|
+
/**
|
|
95
|
+
* Return information about a Nylas application
|
|
96
|
+
* @param options Application details to overwrite
|
|
97
|
+
* @return Information about the Nylas application
|
|
98
|
+
*/
|
|
99
|
+
Nylas.prototype.application = function (options) {
|
|
87
100
|
if (!this.clientId) {
|
|
88
101
|
throw new Error('This function requires a clientId');
|
|
89
102
|
}
|
|
@@ -106,7 +119,13 @@ var Nylas = /** @class */ (function () {
|
|
|
106
119
|
return new application_details_1.default().fromJSON(res);
|
|
107
120
|
});
|
|
108
121
|
};
|
|
109
|
-
|
|
122
|
+
/**
|
|
123
|
+
* Exchange an authorization code for an access token
|
|
124
|
+
* @param code One-time authorization code from Nylas
|
|
125
|
+
* @param callback Callback before returning the access token
|
|
126
|
+
* @return The {@link AccessToken} object containing the access token and other information
|
|
127
|
+
*/
|
|
128
|
+
Nylas.prototype.exchangeCodeForToken = function (code, callback) {
|
|
110
129
|
if (!this.clientId || !this.clientSecret) {
|
|
111
130
|
throw new Error('exchangeCodeForToken() cannot be called until you provide a clientId and secret via config()');
|
|
112
131
|
}
|
|
@@ -131,10 +150,11 @@ var Nylas = /** @class */ (function () {
|
|
|
131
150
|
errorMessage = body.message;
|
|
132
151
|
throw new Error(errorMessage);
|
|
133
152
|
}
|
|
153
|
+
var accessToken = new access_token_1.default().fromJSON(body);
|
|
134
154
|
if (callback) {
|
|
135
|
-
callback(null,
|
|
155
|
+
callback(null, accessToken);
|
|
136
156
|
}
|
|
137
|
-
return
|
|
157
|
+
return accessToken;
|
|
138
158
|
}, function (error) {
|
|
139
159
|
var newError = new Error(error.message);
|
|
140
160
|
if (callback) {
|
|
@@ -143,7 +163,12 @@ var Nylas = /** @class */ (function () {
|
|
|
143
163
|
throw newError;
|
|
144
164
|
});
|
|
145
165
|
};
|
|
146
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Build the URL for authenticating users to your application via Hosted Authentication
|
|
168
|
+
* @param options Configuration for the authentication process
|
|
169
|
+
* @return The URL for hosted authentication
|
|
170
|
+
*/
|
|
171
|
+
Nylas.prototype.urlForAuthentication = function (options) {
|
|
147
172
|
if (!this.clientId) {
|
|
148
173
|
throw new Error('urlForAuthentication() cannot be called until you provide a clientId via config()');
|
|
149
174
|
}
|
|
@@ -172,15 +197,14 @@ var Nylas = /** @class */ (function () {
|
|
|
172
197
|
* Revoke a single access token
|
|
173
198
|
* @param accessToken The access token to revoke
|
|
174
199
|
*/
|
|
175
|
-
Nylas.revoke = function (accessToken) {
|
|
176
|
-
return
|
|
200
|
+
Nylas.prototype.revoke = function (accessToken) {
|
|
201
|
+
return this.with(accessToken)
|
|
177
202
|
.request({
|
|
178
203
|
method: 'POST',
|
|
179
204
|
path: '/oauth/revoke',
|
|
180
205
|
})
|
|
181
206
|
.catch(function (err) { return Promise.reject(err); });
|
|
182
207
|
};
|
|
183
|
-
Nylas.clientId = '';
|
|
184
208
|
return Nylas;
|
|
185
209
|
}());
|
|
186
210
|
module.exports = Nylas;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import Nylas from '../nylas';
|
|
2
|
+
import { RequestHandler, Router } from 'express';
|
|
3
|
+
import { ServerBindingOptions, ServerBinding } from './server-binding';
|
|
4
|
+
export default class ExpressBinding extends ServerBinding {
|
|
5
|
+
constructor(nylasClient: Nylas, options: ServerBindingOptions);
|
|
6
|
+
/**
|
|
7
|
+
* Middleware for the webhook endpoint so we can verify that Nylas is sending the events
|
|
8
|
+
*/
|
|
9
|
+
webhookVerificationMiddleware(): RequestHandler;
|
|
10
|
+
/**
|
|
11
|
+
* Build middleware for an Express app with routes for:
|
|
12
|
+
* 1. '/nylas/webhook': Receiving webhook events, verifying its authenticity, and emitting webhook objects
|
|
13
|
+
* 2. '/nylas/generate-auth-url': Building the URL for authenticating users to your application via Hosted Authentication
|
|
14
|
+
* 3. '/nylas/exchange-mailbox-token': Exchange an authorization code for an access token
|
|
15
|
+
* @return The routes packaged as Express middleware
|
|
16
|
+
*/
|
|
17
|
+
buildMiddleware(): Router;
|
|
18
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
extendStatics(d, b);
|
|
11
|
+
function __() { this.constructor = d; }
|
|
12
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
16
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
17
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
18
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
19
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
20
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
21
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
25
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
26
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
27
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
28
|
+
function step(op) {
|
|
29
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
30
|
+
while (_) try {
|
|
31
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
32
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
33
|
+
switch (op[0]) {
|
|
34
|
+
case 0: case 1: t = op; break;
|
|
35
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
36
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
37
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
38
|
+
default:
|
|
39
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
40
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
41
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
42
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
43
|
+
if (t[2]) _.ops.pop();
|
|
44
|
+
_.trys.pop(); continue;
|
|
45
|
+
}
|
|
46
|
+
op = body.call(thisArg, _);
|
|
47
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
48
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
52
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
53
|
+
};
|
|
54
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
55
|
+
var express_1 = __importDefault(require("express"));
|
|
56
|
+
var server_binding_1 = require("./server-binding");
|
|
57
|
+
var body_parser_1 = __importDefault(require("body-parser"));
|
|
58
|
+
var routes_1 = require("../services/routes");
|
|
59
|
+
var ExpressBinding = /** @class */ (function (_super) {
|
|
60
|
+
__extends(ExpressBinding, _super);
|
|
61
|
+
function ExpressBinding(nylasClient, options) {
|
|
62
|
+
return _super.call(this, nylasClient, options) || this;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Middleware for the webhook endpoint so we can verify that Nylas is sending the events
|
|
66
|
+
*/
|
|
67
|
+
ExpressBinding.prototype.webhookVerificationMiddleware = function () {
|
|
68
|
+
var _this = this;
|
|
69
|
+
return function (req, res, next) {
|
|
70
|
+
var isVerified = _this.verifyWebhookSignature(req.header(server_binding_1.ServerBinding.NYLAS_SIGNATURE_HEADER), req.body);
|
|
71
|
+
if (!isVerified) {
|
|
72
|
+
return res
|
|
73
|
+
.status(401)
|
|
74
|
+
.send('X-Nylas-Signature failed verification 🚷 ');
|
|
75
|
+
}
|
|
76
|
+
next();
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Build middleware for an Express app with routes for:
|
|
81
|
+
* 1. '/nylas/webhook': Receiving webhook events, verifying its authenticity, and emitting webhook objects
|
|
82
|
+
* 2. '/nylas/generate-auth-url': Building the URL for authenticating users to your application via Hosted Authentication
|
|
83
|
+
* 3. '/nylas/exchange-mailbox-token': Exchange an authorization code for an access token
|
|
84
|
+
* @return The routes packaged as Express middleware
|
|
85
|
+
*/
|
|
86
|
+
ExpressBinding.prototype.buildMiddleware = function () {
|
|
87
|
+
var _this = this;
|
|
88
|
+
var _a, _b, _c;
|
|
89
|
+
var router = express_1.default.Router();
|
|
90
|
+
// For the Nylas webhook endpoint, we should get the raw body to use for verification
|
|
91
|
+
router.use(routes_1.DefaultPaths.webhooks, body_parser_1.default.raw({ inflate: true, type: 'application/json' }));
|
|
92
|
+
router.use(express_1.default.json(), body_parser_1.default.urlencoded({ limit: '5mb', extended: true }) // support encoded bodies
|
|
93
|
+
);
|
|
94
|
+
router.post(((_a = this.overridePaths) === null || _a === void 0 ? void 0 : _a.webhooks) || routes_1.DefaultPaths.webhooks, this.webhookVerificationMiddleware(), function (req, res) {
|
|
95
|
+
var deltas = req.body.deltas || [];
|
|
96
|
+
_this.emitDeltaEvents(deltas);
|
|
97
|
+
res.status(200).send('ok');
|
|
98
|
+
});
|
|
99
|
+
router.post(((_b = this.overridePaths) === null || _b === void 0 ? void 0 : _b.buildAuthUrl) || routes_1.DefaultPaths.buildAuthUrl, function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
100
|
+
var state, authUrl;
|
|
101
|
+
return __generator(this, function (_a) {
|
|
102
|
+
switch (_a.label) {
|
|
103
|
+
case 0:
|
|
104
|
+
state = '';
|
|
105
|
+
if (!this.csrfTokenExchangeOpts) return [3 /*break*/, 2];
|
|
106
|
+
return [4 /*yield*/, this.csrfTokenExchangeOpts.generateCsrfToken(req)];
|
|
107
|
+
case 1:
|
|
108
|
+
state = _a.sent();
|
|
109
|
+
_a.label = 2;
|
|
110
|
+
case 2: return [4 /*yield*/, this.buildAuthUrl({
|
|
111
|
+
scopes: this.defaultScopes,
|
|
112
|
+
clientUri: this.clientUri,
|
|
113
|
+
emailAddress: req.body.email_address,
|
|
114
|
+
successUrl: req.body.success_url,
|
|
115
|
+
state: state,
|
|
116
|
+
})];
|
|
117
|
+
case 3:
|
|
118
|
+
authUrl = _a.sent();
|
|
119
|
+
res.status(200).send(authUrl);
|
|
120
|
+
return [2 /*return*/];
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}); });
|
|
124
|
+
router.post(((_c = this.overridePaths) === null || _c === void 0 ? void 0 : _c.exchangeCodeForToken) ||
|
|
125
|
+
routes_1.DefaultPaths.exchangeCodeForToken, function (req, res) { return __awaiter(_this, void 0, void 0, function () {
|
|
126
|
+
var csrfToken, isValidToken, accessTokenObj, e_1;
|
|
127
|
+
return __generator(this, function (_a) {
|
|
128
|
+
switch (_a.label) {
|
|
129
|
+
case 0:
|
|
130
|
+
_a.trys.push([0, 5, , 6]);
|
|
131
|
+
if (!this.csrfTokenExchangeOpts) return [3 /*break*/, 2];
|
|
132
|
+
csrfToken = req.body.csrfToken;
|
|
133
|
+
return [4 /*yield*/, this.csrfTokenExchangeOpts.validateCsrfToken(csrfToken, req)];
|
|
134
|
+
case 1:
|
|
135
|
+
isValidToken = _a.sent();
|
|
136
|
+
if (!isValidToken) {
|
|
137
|
+
return [2 /*return*/, res.status(401).send('Invalid CSRF State Token')];
|
|
138
|
+
}
|
|
139
|
+
_a.label = 2;
|
|
140
|
+
case 2: return [4 /*yield*/, this.exchangeCodeForToken(req.body.token)];
|
|
141
|
+
case 3:
|
|
142
|
+
accessTokenObj = _a.sent();
|
|
143
|
+
return [4 /*yield*/, this.exchangeMailboxTokenCallback(accessTokenObj, res)];
|
|
144
|
+
case 4:
|
|
145
|
+
_a.sent();
|
|
146
|
+
// If the callback event already sent a response then we don't need to do anything
|
|
147
|
+
if (!res.writableEnded) {
|
|
148
|
+
res.status(200).send('success');
|
|
149
|
+
}
|
|
150
|
+
return [3 /*break*/, 6];
|
|
151
|
+
case 5:
|
|
152
|
+
e_1 = _a.sent();
|
|
153
|
+
res.status(500).send(e_1.message);
|
|
154
|
+
return [3 /*break*/, 6];
|
|
155
|
+
case 6: return [2 /*return*/];
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}); });
|
|
159
|
+
return router;
|
|
160
|
+
};
|
|
161
|
+
return ExpressBinding;
|
|
162
|
+
}(server_binding_1.ServerBinding));
|
|
163
|
+
exports.default = ExpressBinding;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Request, Response, Router } from 'express';
|
|
3
|
+
import { Scope } from '../models/connect';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import Webhook, { WebhookTriggers } from '../models/webhook';
|
|
6
|
+
import { WebhookDelta } from '../models/webhook-notification';
|
|
7
|
+
import AccessToken from '../models/access-token';
|
|
8
|
+
import Nylas from '../nylas';
|
|
9
|
+
import { OpenWebhookTunnelOptions } from '../services/tunnel';
|
|
10
|
+
import { BuildAuthUrl, ExchangeCodeForToken, VerifyWebhookSignature } from '../services/routes';
|
|
11
|
+
declare type Middleware = Router;
|
|
12
|
+
declare type ServerRequest = Request;
|
|
13
|
+
declare type ServerResponse = Response;
|
|
14
|
+
declare type ExchangeMailboxTokenCallback = (accessToken: AccessToken, res: ServerResponse) => void;
|
|
15
|
+
declare type CsrfTokenExchangeOptions = {
|
|
16
|
+
generateCsrfToken: (req: ServerRequest) => Promise<string>;
|
|
17
|
+
validateCsrfToken: (csrfToken: string, req: ServerRequest) => Promise<boolean>;
|
|
18
|
+
};
|
|
19
|
+
declare type OverridePaths = {
|
|
20
|
+
buildAuthUrl?: string;
|
|
21
|
+
exchangeCodeForToken?: string;
|
|
22
|
+
webhooks?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare type ServerBindingOptions = {
|
|
25
|
+
defaultScopes: Scope[];
|
|
26
|
+
exchangeMailboxTokenCallback: ExchangeMailboxTokenCallback;
|
|
27
|
+
csrfTokenExchangeOpts?: CsrfTokenExchangeOptions;
|
|
28
|
+
clientUri?: string;
|
|
29
|
+
overridePaths?: OverridePaths;
|
|
30
|
+
};
|
|
31
|
+
export declare abstract class ServerBinding extends EventEmitter implements ServerBindingOptions {
|
|
32
|
+
nylasClient: Nylas;
|
|
33
|
+
defaultScopes: Scope[];
|
|
34
|
+
exchangeMailboxTokenCallback: ExchangeMailboxTokenCallback;
|
|
35
|
+
csrfTokenExchangeOpts?: CsrfTokenExchangeOptions;
|
|
36
|
+
clientUri?: string;
|
|
37
|
+
overridePaths?: OverridePaths;
|
|
38
|
+
static NYLAS_SIGNATURE_HEADER: string;
|
|
39
|
+
protected buildAuthUrl: BuildAuthUrl;
|
|
40
|
+
protected exchangeCodeForToken: ExchangeCodeForToken;
|
|
41
|
+
protected verifyWebhookSignature: VerifyWebhookSignature;
|
|
42
|
+
private _untypedOn;
|
|
43
|
+
private _untypedEmit;
|
|
44
|
+
protected constructor(nylasClient: Nylas, options: ServerBindingOptions);
|
|
45
|
+
abstract buildMiddleware(): Middleware;
|
|
46
|
+
on: <K extends WebhookTriggers>(event: K, listener: (payload: WebhookDelta) => void) => this;
|
|
47
|
+
emit: <K extends WebhookTriggers>(event: K, payload: WebhookDelta) => boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Emit all incoming delta events
|
|
50
|
+
* @param deltas The list of delta JSON objects
|
|
51
|
+
*/
|
|
52
|
+
emitDeltaEvents(deltas: Record<string, unknown>[]): void;
|
|
53
|
+
/**
|
|
54
|
+
* Start a local development websocket to get webhook events
|
|
55
|
+
* @param webhookTunnelConfig Optional configuration for setting region, triggers, and overriding callbacks
|
|
56
|
+
* @return The webhook details response from the API
|
|
57
|
+
*/
|
|
58
|
+
startDevelopmentWebsocket(webhookTunnelConfig?: Partial<OpenWebhookTunnelOptions>): Promise<Webhook>;
|
|
59
|
+
/**
|
|
60
|
+
* Delta event processor to be used either by websocket or webhook
|
|
61
|
+
* @param d The delta event
|
|
62
|
+
*/
|
|
63
|
+
protected handleDeltaEvent: (d: WebhookDelta) => void;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __extends = (this && this.__extends) || (function () {
|
|
3
|
+
var extendStatics = function (d, b) {
|
|
4
|
+
extendStatics = Object.setPrototypeOf ||
|
|
5
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
6
|
+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
|
7
|
+
return extendStatics(d, b);
|
|
8
|
+
};
|
|
9
|
+
return function (d, b) {
|
|
10
|
+
extendStatics(d, b);
|
|
11
|
+
function __() { this.constructor = d; }
|
|
12
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
13
|
+
};
|
|
14
|
+
})();
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
var events_1 = require("events");
|
|
17
|
+
var webhook_notification_1 = require("../models/webhook-notification");
|
|
18
|
+
var tunnel_1 = require("../services/tunnel");
|
|
19
|
+
var routes_1 = require("../services/routes");
|
|
20
|
+
var ServerBinding = /** @class */ (function (_super) {
|
|
21
|
+
__extends(ServerBinding, _super);
|
|
22
|
+
function ServerBinding(nylasClient, options) {
|
|
23
|
+
var _a;
|
|
24
|
+
var _this = _super.call(this) || this;
|
|
25
|
+
_this._untypedOn = _this.on;
|
|
26
|
+
_this._untypedEmit = _this.emit;
|
|
27
|
+
// Taken from the best StackOverflow answer of all time https://stackoverflow.com/a/56228127
|
|
28
|
+
_this.on = function (event, listener) { return _this._untypedOn(event, listener); };
|
|
29
|
+
_this.emit = function (event, payload) { return _this._untypedEmit(event, payload); };
|
|
30
|
+
/**
|
|
31
|
+
* Delta event processor to be used either by websocket or webhook
|
|
32
|
+
* @param d The delta event
|
|
33
|
+
*/
|
|
34
|
+
_this.handleDeltaEvent = function (d) {
|
|
35
|
+
d.type && _this.emit(d.type, d);
|
|
36
|
+
};
|
|
37
|
+
_this.nylasClient = nylasClient;
|
|
38
|
+
_this.defaultScopes = options.defaultScopes;
|
|
39
|
+
_this.exchangeMailboxTokenCallback = options.exchangeMailboxTokenCallback;
|
|
40
|
+
_this.csrfTokenExchangeOpts = options.csrfTokenExchangeOpts;
|
|
41
|
+
_this.clientUri = options.clientUri;
|
|
42
|
+
(_a = routes_1.Routes(nylasClient), _this.buildAuthUrl = _a.buildAuthUrl, _this.exchangeCodeForToken = _a.exchangeCodeForToken, _this.verifyWebhookSignature = _a.verifyWebhookSignature);
|
|
43
|
+
_this.overridePaths = options.overridePaths;
|
|
44
|
+
return _this;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Emit all incoming delta events
|
|
48
|
+
* @param deltas The list of delta JSON objects
|
|
49
|
+
*/
|
|
50
|
+
ServerBinding.prototype.emitDeltaEvents = function (deltas) {
|
|
51
|
+
var _this = this;
|
|
52
|
+
deltas.forEach(function (d) { return _this.handleDeltaEvent(new webhook_notification_1.WebhookDelta().fromJSON(d)); });
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Start a local development websocket to get webhook events
|
|
56
|
+
* @param webhookTunnelConfig Optional configuration for setting region, triggers, and overriding callbacks
|
|
57
|
+
* @return The webhook details response from the API
|
|
58
|
+
*/
|
|
59
|
+
ServerBinding.prototype.startDevelopmentWebsocket = function (webhookTunnelConfig) {
|
|
60
|
+
/* eslint-disable no-console */
|
|
61
|
+
var defaultOnClose = function () {
|
|
62
|
+
return console.log('Nylas websocket client connection closed');
|
|
63
|
+
};
|
|
64
|
+
var defaultOnConnectFail = function (e) {
|
|
65
|
+
return console.log('Failed to connect Nylas websocket client', e.message);
|
|
66
|
+
};
|
|
67
|
+
var defaultOnError = function (e) {
|
|
68
|
+
return console.log('Error in Nylas websocket client', e.message);
|
|
69
|
+
};
|
|
70
|
+
var defaultOnConnect = function () {
|
|
71
|
+
return console.log('Nylas websocket client connected');
|
|
72
|
+
};
|
|
73
|
+
/* eslint-enable no-console */
|
|
74
|
+
return tunnel_1.openWebhookTunnel(this.nylasClient, {
|
|
75
|
+
onMessage: (webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.onMessage) || this.handleDeltaEvent,
|
|
76
|
+
onClose: (webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.onClose) || defaultOnClose,
|
|
77
|
+
onConnectFail: (webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.onConnectFail) || defaultOnConnectFail,
|
|
78
|
+
onError: (webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.onError) || defaultOnError,
|
|
79
|
+
onConnect: (webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.onConnect) || defaultOnConnect,
|
|
80
|
+
region: webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.region,
|
|
81
|
+
triggers: webhookTunnelConfig === null || webhookTunnelConfig === void 0 ? void 0 : webhookTunnelConfig.triggers,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
ServerBinding.NYLAS_SIGNATURE_HEADER = 'x-nylas-signature';
|
|
85
|
+
return ServerBinding;
|
|
86
|
+
}(events_1.EventEmitter));
|
|
87
|
+
exports.ServerBinding = ServerBinding;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Scope } from '../models/connect';
|
|
3
|
+
import Nylas from '../nylas';
|
|
4
|
+
import AccessToken from '../models/access-token';
|
|
5
|
+
export declare enum DefaultPaths {
|
|
6
|
+
buildAuthUrl = "/nylas/generate-auth-url",
|
|
7
|
+
exchangeCodeForToken = "/nylas/exchange-mailbox-token",
|
|
8
|
+
webhooks = "/nylas/webhook"
|
|
9
|
+
}
|
|
10
|
+
export declare type BuildAuthUrl = (options: BuildAuthUrlOptions) => Promise<string>;
|
|
11
|
+
export declare type ExchangeCodeForToken = (code: string) => Promise<AccessToken>;
|
|
12
|
+
export declare type VerifyWebhookSignature = (nylasSignature: string, rawBody: Buffer) => boolean;
|
|
13
|
+
export declare type BuildAuthUrlOptions = {
|
|
14
|
+
scopes: Scope[];
|
|
15
|
+
emailAddress: string;
|
|
16
|
+
successUrl: string;
|
|
17
|
+
clientUri?: string;
|
|
18
|
+
state?: string;
|
|
19
|
+
};
|
|
20
|
+
declare type Routes = {
|
|
21
|
+
buildAuthUrl: BuildAuthUrl;
|
|
22
|
+
exchangeCodeForToken: ExchangeCodeForToken;
|
|
23
|
+
verifyWebhookSignature: VerifyWebhookSignature;
|
|
24
|
+
};
|
|
25
|
+
export declare const Routes: (nylasClient: Nylas) => Routes;
|
|
26
|
+
export default Routes;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (_) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
var crypto_1 = __importDefault(require("crypto"));
|
|
43
|
+
var DefaultPaths;
|
|
44
|
+
(function (DefaultPaths) {
|
|
45
|
+
DefaultPaths["buildAuthUrl"] = "/nylas/generate-auth-url";
|
|
46
|
+
DefaultPaths["exchangeCodeForToken"] = "/nylas/exchange-mailbox-token";
|
|
47
|
+
DefaultPaths["webhooks"] = "/nylas/webhook";
|
|
48
|
+
})(DefaultPaths = exports.DefaultPaths || (exports.DefaultPaths = {}));
|
|
49
|
+
exports.Routes = function (nylasClient) {
|
|
50
|
+
/**
|
|
51
|
+
* Build the URL for authenticating users to your application via Hosted Authentication
|
|
52
|
+
* @param options Configuration for the authentication process
|
|
53
|
+
* @return The URL for hosted authentication
|
|
54
|
+
*/
|
|
55
|
+
var buildAuthUrl = function (options) { return __awaiter(void 0, void 0, void 0, function () {
|
|
56
|
+
var scopes, emailAddress, successUrl, clientUri, state;
|
|
57
|
+
return __generator(this, function (_a) {
|
|
58
|
+
scopes = options.scopes, emailAddress = options.emailAddress, successUrl = options.successUrl, clientUri = options.clientUri, state = options.state;
|
|
59
|
+
return [2 /*return*/, nylasClient.urlForAuthentication({
|
|
60
|
+
loginHint: emailAddress,
|
|
61
|
+
redirectURI: (clientUri || '') + successUrl,
|
|
62
|
+
scopes: scopes,
|
|
63
|
+
state: state,
|
|
64
|
+
})];
|
|
65
|
+
});
|
|
66
|
+
}); };
|
|
67
|
+
/**
|
|
68
|
+
* Exchange an authorization code for an access token
|
|
69
|
+
* @param code One-time authorization code from Nylas
|
|
70
|
+
* @param callback Callback before returning the access token
|
|
71
|
+
* @return The {@link AccessToken} object containing the access token and other information
|
|
72
|
+
*/
|
|
73
|
+
var exchangeCodeForToken = function (code, callback) { return __awaiter(void 0, void 0, void 0, function () {
|
|
74
|
+
return __generator(this, function (_a) {
|
|
75
|
+
switch (_a.label) {
|
|
76
|
+
case 0: return [4 /*yield*/, nylasClient.exchangeCodeForToken(code, callback)];
|
|
77
|
+
case 1: return [2 /*return*/, _a.sent()];
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}); };
|
|
81
|
+
/**
|
|
82
|
+
* Verify incoming webhook signature came from Nylas
|
|
83
|
+
* @param nylasSignature The signature to verify
|
|
84
|
+
* @param rawBody The raw body from the payload
|
|
85
|
+
* @return true if the webhook signature was verified from Nylas
|
|
86
|
+
*/
|
|
87
|
+
var verifyWebhookSignature = function (nylasSignature, rawBody) {
|
|
88
|
+
var digest = crypto_1.default
|
|
89
|
+
.createHmac('sha256', nylasClient.clientSecret)
|
|
90
|
+
.update(rawBody)
|
|
91
|
+
.digest('hex');
|
|
92
|
+
return digest === nylasSignature;
|
|
93
|
+
};
|
|
94
|
+
return { buildAuthUrl: buildAuthUrl, exchangeCodeForToken: exchangeCodeForToken, verifyWebhookSignature: verifyWebhookSignature };
|
|
95
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { client as WebSocketClient } from 'websocket';
|
|
2
|
+
import { Region } from '../config';
|
|
3
|
+
import Nylas from '../nylas';
|
|
4
|
+
import Webhook, { WebhookTriggers } from '../models/webhook';
|
|
5
|
+
import { WebhookDelta } from '../models/webhook-notification';
|
|
6
|
+
export interface OpenWebhookTunnelOptions {
|
|
7
|
+
onMessage: (msg: WebhookDelta) => void;
|
|
8
|
+
onConnectFail?: (error: Error) => void;
|
|
9
|
+
onError?: (error: Error) => void;
|
|
10
|
+
onClose?: (wsClient: WebSocketClient) => void;
|
|
11
|
+
onConnect?: (wsClient: WebSocketClient) => void;
|
|
12
|
+
region?: Region;
|
|
13
|
+
triggers?: WebhookTriggers[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Open a webhook tunnel and register it with the Nylas API
|
|
17
|
+
* 1. Creates a UUID
|
|
18
|
+
* 2. Opens a websocket connection to Nylas' webhook forwarding service,
|
|
19
|
+
* with the UUID as a header
|
|
20
|
+
* 3. Creates a new webhook pointed at the forwarding service with the UUID as the path
|
|
21
|
+
*
|
|
22
|
+
* When an event is received by the forwarding service, it will push directly to this websocket
|
|
23
|
+
* connection
|
|
24
|
+
*
|
|
25
|
+
* @param nylasClient The configured Nylas application
|
|
26
|
+
* @param config Configuration for the webhook tunnel, including callback functions, region, and events to subscribe to
|
|
27
|
+
* @return The webhook details response from the API
|
|
28
|
+
*/
|
|
29
|
+
export declare const openWebhookTunnel: (nylasClient: Nylas, config: OpenWebhookTunnelOptions) => Promise<Webhook>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var websocket_1 = require("websocket");
|
|
4
|
+
var uuid_1 = require("uuid");
|
|
5
|
+
var config_1 = require("../config");
|
|
6
|
+
var webhook_notification_1 = require("../models/webhook-notification");
|
|
7
|
+
/**
|
|
8
|
+
* Deletes the Nylas webhook
|
|
9
|
+
* @param nylasClient The Nylas application configured with the webhook
|
|
10
|
+
* @param nylasWebhook The Nylas webhook details
|
|
11
|
+
*/
|
|
12
|
+
var deleteTunnelWebhook = function (nylasClient, nylasWebhook) {
|
|
13
|
+
if (nylasWebhook && nylasWebhook.id) {
|
|
14
|
+
/* eslint-disable no-console */
|
|
15
|
+
console.log("Shutting down the webhook tunnel and deleting id: " + nylasWebhook.id);
|
|
16
|
+
/* eslint-enable no-console */
|
|
17
|
+
nylasClient.webhooks
|
|
18
|
+
.delete(nylasWebhook)
|
|
19
|
+
.then(function () { return process.exit(); })
|
|
20
|
+
.catch(function (err) {
|
|
21
|
+
console.warn("Error while trying to deregister the webhook " + nylasWebhook.id + ": " + err.message);
|
|
22
|
+
process.exit();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Create a webhook to the Nylas forwarding service which will pass messages to our websocket
|
|
28
|
+
* @param nylasClient The configured Nylas application
|
|
29
|
+
* @param callbackDomain The domain name of the callback
|
|
30
|
+
* @param tunnelPath The path to the tunnel
|
|
31
|
+
* @param triggers The list of triggers to subscribe to
|
|
32
|
+
* @return The webhook details response from the API
|
|
33
|
+
*/
|
|
34
|
+
var buildTunnelWebhook = function (nylasClient, callbackDomain, tunnelPath, triggers) {
|
|
35
|
+
var callbackUrl = "https://" + callbackDomain + "/" + tunnelPath;
|
|
36
|
+
return nylasClient.webhooks
|
|
37
|
+
.build({
|
|
38
|
+
callbackUrl: callbackUrl,
|
|
39
|
+
state: 'active',
|
|
40
|
+
test: true,
|
|
41
|
+
triggers: triggers,
|
|
42
|
+
})
|
|
43
|
+
.save()
|
|
44
|
+
.then(function (webhook) {
|
|
45
|
+
// Ensure that, upon all exits, delete the webhook on the Nylas application
|
|
46
|
+
process.on('SIGINT', function () { return deleteTunnelWebhook(nylasClient, webhook); });
|
|
47
|
+
process.on('SIGTERM', function () { return deleteTunnelWebhook(nylasClient, webhook); });
|
|
48
|
+
process.on('SIGBREAK', function () { return deleteTunnelWebhook(nylasClient, webhook); });
|
|
49
|
+
return webhook;
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Open a webhook tunnel and register it with the Nylas API
|
|
54
|
+
* 1. Creates a UUID
|
|
55
|
+
* 2. Opens a websocket connection to Nylas' webhook forwarding service,
|
|
56
|
+
* with the UUID as a header
|
|
57
|
+
* 3. Creates a new webhook pointed at the forwarding service with the UUID as the path
|
|
58
|
+
*
|
|
59
|
+
* When an event is received by the forwarding service, it will push directly to this websocket
|
|
60
|
+
* connection
|
|
61
|
+
*
|
|
62
|
+
* @param nylasClient The configured Nylas application
|
|
63
|
+
* @param config Configuration for the webhook tunnel, including callback functions, region, and events to subscribe to
|
|
64
|
+
* @return The webhook details response from the API
|
|
65
|
+
*/
|
|
66
|
+
exports.openWebhookTunnel = function (nylasClient, config) {
|
|
67
|
+
var triggers = config.triggers || config_1.DEFAULT_WEBHOOK_TRIGGERS;
|
|
68
|
+
var region = config.region || config_1.DEFAULT_REGION;
|
|
69
|
+
var _a = config_1.regionConfig[region], websocketDomain = _a.websocketDomain, callbackDomain = _a.callbackDomain;
|
|
70
|
+
// This UUID will map our websocket to a webhook in the forwarding server
|
|
71
|
+
var tunnelId = uuid_1.v4();
|
|
72
|
+
var client = new websocket_1.client({ closeTimeout: 60000 });
|
|
73
|
+
client.on('connectFailed', function (error) {
|
|
74
|
+
config.onConnectFail && config.onConnectFail(error);
|
|
75
|
+
});
|
|
76
|
+
client.on('connect', function (connection) {
|
|
77
|
+
config.onConnect && config.onConnect(client);
|
|
78
|
+
connection.on('error', function (error) {
|
|
79
|
+
config.onError && config.onError(error);
|
|
80
|
+
});
|
|
81
|
+
connection.on('close', function () {
|
|
82
|
+
config.onClose && config.onClose(client);
|
|
83
|
+
});
|
|
84
|
+
connection.on('message', function (message) {
|
|
85
|
+
// This shouldn't happen. If any of these are seen, open an issue
|
|
86
|
+
if (message.type === 'binary') {
|
|
87
|
+
config.onError &&
|
|
88
|
+
config.onError(new Error('Unknown binary message received'));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
var req = JSON.parse(message.utf8Data);
|
|
93
|
+
var deltas = JSON.parse(req.body).deltas;
|
|
94
|
+
deltas.forEach(function (delta) {
|
|
95
|
+
return config.onMessage(new webhook_notification_1.WebhookDelta().fromJSON(delta));
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
config.onError &&
|
|
100
|
+
config.onError(new Error("Error converting Nylas websocket event to JSON: " + (e &&
|
|
101
|
+
e.message)));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
client.connect("wss://" + websocketDomain, undefined, undefined, {
|
|
106
|
+
'Client-Id': nylasClient.clientId,
|
|
107
|
+
'Client-Secret': nylasClient.clientSecret,
|
|
108
|
+
'Tunnel-Id': tunnelId,
|
|
109
|
+
Region: region,
|
|
110
|
+
});
|
|
111
|
+
return buildTunnelWebhook(nylasClient, callbackDomain, tunnelId, triggers);
|
|
112
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nylas",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0-beta.0",
|
|
4
4
|
"description": "A NodeJS wrapper for the Nylas REST API for email, contacts, and calendar.",
|
|
5
5
|
"main": "lib/nylas.js",
|
|
6
6
|
"types": "lib/nylas.d.ts",
|
|
@@ -47,7 +47,11 @@
|
|
|
47
47
|
"backoff": "^2.5.0",
|
|
48
48
|
"form-data": "^4.0.0",
|
|
49
49
|
"JSONStream": "^1.3.5",
|
|
50
|
-
"node-fetch": "^2.6.1"
|
|
50
|
+
"node-fetch": "^2.6.1",
|
|
51
|
+
"express": "^4.17.13",
|
|
52
|
+
"body-parser": "^1.20.0",
|
|
53
|
+
"uuid": "^8.3.2",
|
|
54
|
+
"websocket": "^1.0.34"
|
|
51
55
|
},
|
|
52
56
|
"devDependencies": {
|
|
53
57
|
"@babel/cli": "^7.13.16",
|
|
@@ -57,6 +61,9 @@
|
|
|
57
61
|
"@types/backoff": "^2.5.1",
|
|
58
62
|
"@types/jest": "^25.1.4",
|
|
59
63
|
"@types/node-fetch": "^2.5.8",
|
|
64
|
+
"@types/uuid": "^8.3.4",
|
|
65
|
+
"@types/websocket": "^1.0.5",
|
|
66
|
+
"@types/express": "^4.17.13",
|
|
60
67
|
"@typescript-eslint/eslint-plugin": "^2.25.0",
|
|
61
68
|
"@typescript-eslint/parser": "^2.25.0",
|
|
62
69
|
"babel-eslint": "^10.0.1",
|