Skip to content

Releases: nylas/nylas-nodejs

v6.4.1

06 Jun 21:49
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings a couple of fixes.

Release Notes

Fixed

  • Fixed issue where API response data was being lost (#356)
  • Fixed incorrect tunnel index number in webhook example

v6.4.0

10 May 22:00
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings support for collective and group events, as well as a fix.

Release Notes

Added

  • Support collective and group events

Fixed

  • Fix fileIdsToAttach field not being set when initializing a Draft

v6.3.2

04 May 22:07
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings a couple of fixes and changes.

Release Notes

Added

  • Added missing fileIdsToAttach field in DraftProperties (#347)

Fixed

  • Fixed JSON parse error when using CalendarRestfulModelCollection.freeBusy (#349)
  • Fixed base URL not being set for SchedulerRestfulModelCollection functions

New Contributors 🎉

  • @crhayes made their first contribution with [Bugfix] Fix bug in CalendarRestfulModelCollection (#349)

v6.3.1

22 Apr 20:25
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings a couple of fixes.

Release Notes

Added

  • Add missing order and emails field in calendar availability (#344)

Fixed

  • Fix issue where passing in an array of one for MessageRestfulModelCollection.findMultiple throws an error (#343)

v6.3.0

14 Apr 17:10
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings a few of features as well as a couple of fixes.

Release Notes

Added

  • Add support for revoking a single access token
  • Improve Outbox job status support
  • Support Setting Redirect On Error in Authenticate URL Config (#338)

Fixed

  • Fix issue where an empty response body could trigger a JSON deserialization error
  • Remove usage of unreliable node-fetch response.size (#339)

New Contributors

  • @myleslinder made their first contributions with Support Setting Redirect On Error in Authenticate URL Config (#338) and Fix Outbox JSON Parsing Error (#339)

Using New Features

Revoking a single access token

const Nylas = require('nylas');
Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});

Nylas.revoke("ACCESS_TOKEN_TO_REVOKE");

Improved Outbox Job Status

To get an outbox job status by ID, it's the same as you would get any Job Status, but in the background the SDK will identify if the job status is an outbox job status, and if so it will return the correct type:

const Nylas = require('nylas');
Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

const jobStatus = nylas.jobstatuses.find("outbox-job-status-id");

v6.2.2

01 Apr 21:03
90fac5a
Compare
Choose a tag to compare

This release of the Nylas Node SDK comes with a few new changes and fixes.

Release Notes

Changed

  • Allow getting raw message by message ID directly instead of needing to fetch the message first
  • Add new authenticationType field in ManagementAccount

Fixed

  • Fix JSON error thrown when Nylas API returns non-JSON error payload

v6.2.1

25 Mar 18:40
Compare
Choose a tag to compare

This release of the Nylas Node SDK comes with a few new changes and fixes.

Release Notes

Changed

  • Bump supported Nylas API version to v2.5

Fixed

  • Fix circular dependency issue in Attribute
  • Fix SchedulerBookingOpeningHoursProperties.days and add missing fields to Scheduler models (#328)

Dependencies

  • Bump node-fetch dependency from 2.6.1 to 2.6.7
  • Bump ajv sub-dependency from 6.10.2 to 6.12.6

v6.2.0

04 Feb 16:14
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings a few features as well as an enhancement.

New Features

  • Add support for returning multiple messages by a list of message IDs (#313)
  • Add new field in Draft for adding files by file IDs (#314)
  • Add Webhook Notification models (#311)
  • Improved Delta support: added Delta model and two new methods; since and longpoll

Enhancements

  • Fix Virtual Calendar logic and serialization

Using New Features

Return multiple messages by multiple message IDs

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

const messages = await nylas.messages.findMultiple(['message_id_1', 'message_id_2']);

Add files to a Draft by draft IDs

const Nylas = require('nylas');
Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

const draft = new Draft(nylas, {
  to: [{ name: 'Nylas Swag', email: '[email protected]' }],
  fileIdsToAttach = ["file_id_1", "file_id_2"],
});
draft.save();

Please note that this new field, fileIdsToAttach: string[] in Draft, only adds files to a draft. To remove an existing file from an already saved Draft object, it must be done on the files field. Upon saving we will make sure to merge unique values in the outgoing payload.

Delta improvements: new Delta and Deltas models, new since() and longPoll() functions

There have been a number of changes to improve Delta support in this SDK:

  • Delta is now of RestfulModel type representing a single Delta API object.
  • Deltas is a new model representing the API object that contains a set of Delta objects.
  • DeltaCollection is a new class that contains all delta-related operations (including latestCursor and startStream)
  • NylasConnection.deltas now returns a DeltaCollection object. To maintain backwards compatibility, latestCursor and startStream have been moved out of Delta and into DeltaCollection.
  • DeltaCollection.since(cursor: string): Promise<Deltas> returns the set of deltas since the cursor provided. (see GET /delta)
  • DeltaCollection.longPoll(cursor: string, timeout: string, params?: DeltaParams): Promise<DeltaLongPoll> polls the API for Deltas since the cursor provided until either the provided timeout is reached, or the server sends a response. (see GET /delta/longpoll)

To return a set of delta cursors since a specific cursor:

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

const deltas = nylas.deltas.since("CURSOR");

/*
* There are a few options you can pass in to this endpoint:
* view: string - This type of view to return within the delta objects
* includeTypes: string[] - The list of types to include in the query ('file', 'event', etc.)
* excludeTypes: string[] - The list of types to exclude in the query ('file', 'event', etc.)
*/

const deltas = nylas.deltas.since("CURSOR", {
  view: 'expanded',
  excludeTypes: ['file', 'event'],
  includeTypes: ['message'],
});

To long-poll for delta cursors since a specific cursor:

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

// long-poll for 30 seconds
nylas.deltas.longPoll("CURSOR", 30).then(deltaEmitter => {
  deltaEmitter.on('delta', delta => {
    console.log("Recieved a delta!");
    console.log(delta);
  });
});

/*
* There are a few options you can pass in to this endpoint:
* view: string - This type of view to return within the delta objects
* includeTypes: string[] - The list of types to include in the query ('file', 'event', etc.)
* excludeTypes: string[] - The list of types to exclude in the query ('file', 'event', etc.)
*/

nylas.deltas.longPoll("CURSOR", 30, {
  view: 'expanded',
  excludeTypes: ['file', 'event'],
  includeTypes: ['message'],
}).then(deltaEmitter => {
  deltaEmitter.on('delta', delta => {
    console.log("Recieved a delta!");
    console.log(delta);
  });
});

Getting the latest cursor and streaming has not changed:

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

// Get the latest cursor
const latestCursor = await nylas.deltas.latestCursor();

// Start streaming
nylas.deltas.startStream(latestCursor).then(deltaEmitter => {
  deltaEmitter.on('delta', delta => {
    console.log("Recieved a delta!");
    console.log(delta);
  });
});

New Webhook Notification models

The sample below clarifies the models, the types, and the strictness of all new Webhook Notification-related models. To better understand it, please refer to the documentation on Webhook Notifications.

webhookNotification: WebhookDelta[] = new WebhookNotification().fromJSON(webhookNotificationJSON);
/*
* Available Fields for WebhookNotification:
* WebhookNotification.deltas: WebhookDelta[]
 */

const webhookDelta: WebhookDelta = webhookNotification.deltas[0];
/*
* Available Fields for WebhookDelta:
* WebhookDelta.date: Date
* WebhookDelta.object: string
* WebhookDelta.type: string
* WebhookDelta.objectData: WebhookObjectData
 */

const webhookDeltaObjectData: WebhookObjectData = webhookDelta.objectData;
/*
* Available Fields for WebhookObjectData:
* WebhookObjectData.id: string
* WebhookObjectData.accountId: string
* WebhookObjectData.namespaceId: string
* WebhookObjectData.object: string
* WebhookObjectData.objectAttributes?: WebhookObjectAttributes
* WebhookObjectData.metadata?: MessageTrackingData
 */

const webhookDeltaObjectAttributes: WebhookObjectAttributes = webhookDeltaObjectData.objectAttributes;
/*
* Available Fields for WebhookObjectAttributes:
* WebhookObjectAttributes.action?: string
* WebhookObjectAttributes.jobStatusId?: string
* WebhookObjectAttributes.threadId?: string
* WebhookObjectAttributes.receivedDate?: Date
*/

const webhookMessageTrackingData: MessageTrackingData = webhookDeltaObjectData.metadata;
/*
* Available Fields for MessageTrackingData:
* MessageTrackingData.senderAppId: number
* MessageTrackingData.messageId: string
* MessageTrackingData.payload: string
* MessageTrackingData.threadId?: string
* MessageTrackingData.replyToMessageId?: string
* MessageTrackingData.count?: number
* MessageTrackingData.fromSelf?: boolean
* MessageTrackingData.timestamp?: Date
* MessageTrackingData.linkData?: LinkClickCount[]
* MessageTrackingData.recents?: LinkClick[]
 */

const linkData: LinkClickCount = webhookMessageTrackingData.linkData[0];
/*
* Available Fields for LinkClickCount:
* LinkClickCount.url: string
* LinkClickCount.count: number
 */

const recents = webhookMessageTrackingData.recents[0];
/*
* Available Fields for LinkClick:
* LinkClick.id: number
* LinkClick.ip: string
* LinkClick.userAgent: string
* LinkClick.timestamp: Date
* LinkClick.linkIndex?: number
 */

Virtual Calendar fixed

In order to improve the user experience with Virtual Calendar, scope and settings are no longer required to be provided in the Connect.authorize() function if the user wants to authorize a Virtual Calendar. This is done to prevent confusion as the API only accepts one specific value for the two fields in order for the call to be accepted. Below is the sample of authorizing a Virtual Calendar:

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});

const virtualCalendarAuth = await Nylas.connect.authorize({
  name: "Virtual Calendar Name",
  emailAddress: "virtual_account_unique_id",
  clientId: "CLIENT_ID", // Note that clientId is optional, defaults to the clientId configured above in Nylas.config()
});

v6.1.0

28 Jan 20:42
Compare
Choose a tag to compare

This new release of the Nylas Node SDK brings a couple of features as well as a couple of enhancements.

New Features

  • Add support for Event to ICS
  • Add support for calendars field in free-busy, availability, and consecutive availability queries

Enhancements

  • Add comment and phoneNumber fields to EventParticipant
  • Fix issue where properties of Model type were sending read-only attributes to the API

Using New Features

Generate an ICS from an Event

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

const exampleEvent = await nylas.events.find('{id}');

// Generate an ICS from an event
let ics = await exampleEvent.generateICS();

// You can also pass ICS Options for more configuration
ics = await exampleEvent.generateICS({
  iCalUID="test_uuid",
  method="add",
  prodId="test_prodid"
})

New calendars field in free-busy/availability queries

Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

// To check free-busy with calendars:
const freeBusy = nylas.calendars.freeBusy({
  startTime: 1590454800,
  endTime: 1590780800,
  calendars: [{
    accountId: "test_account_id",
    calendarIds: [
      "example_calendar_id_A",
       "example_calendar_id_B",
    ],
  }],
});

// To check availability with calendars:
const availability = nylas.calendars.availability({
  startTime: 1590454800,
  endTime: 1590780800,
  interval: 5,
  duration: 30,
  calendars: [{
    accountId: "test_account_id",
    calendarIds: [
      "example_calendar_id_A",
       "example_calendar_id_B",
    ],
  }],
});

// To check consecutive availability with calendars:
const availability = nylas.calendars.consecutiveAvailability({
  startTime: 1590454800,
  endTime: 1590780800,
  interval: 5,
  duration: 30,
  calendars: [{
    accountId: "test_account_id",
    calendarIds: [
      "example_calendar_id_A",
       "example_calendar_id_B",
    ],
  }],
});

v6.0.0

12 Jan 22:14
Compare
Choose a tag to compare

This release of the Node SDK is a major overhaul of the SDK with a focus refactoring and improving the SDK to make it more Typescript-like as well as improving the usability of the SDK by providing better and stricter type hinting as well as expected parameters. It is highly encouraged to read through the release notes, changelog, and the migration guide before upgrading as this release brings a slew of breaking changes and may not be compatible with prior versions. A full changelog and the link to the migration guide can be found at the very bottom of the post.

This major release can be broken down into three main sections: refactoring RestfulModel, improving deserialization and object creation, and improving the typing of the SDK in general.

Refactoring RestfulModel and Introducing Model superclass

As the SDK coverage grows, we need to define what a "basic" model is instead of solely using RestfulModel for every model represented in the SDK. To do this we needed to decouple the standard functionality of a model from the specific functionality/structure of a "classic" Nylas API model. A "classic" Nylas API model is a model used for endpoints like Event, Calendar, Message, etc. where we expect the object to have an id, account_id, and object field and we are expected to perform RESTful operations directly with this model. Now with the Nylas API, there are a lot of models that are representations of API objects, but don't have endpoint(s) nor are we expected to make RESTful calls directly using them. A perfect example of this are all the Contact subclasses. This allows the user to instantiate these objects without the need to pass in a NylasConnection type, which cleans up the code and produces less overhead.

The same logic was also applied to refactoring RestfulModelCollection and creating a ModelCollection superclass.

Improving Deserialization and Object Creation

Following up on the creation of the Model superclass, each model has an accompanying interface that represents an object of parameters that the model will use, as well as the proper strictness dictated by what values will always be present in any scenario (GET, POST, PUT). In the constructor of each model, we now specify that we can take in an optional props property of the Model interface's type. This helps to hint the user as to what properties they must pass in during the initialization of the object. This also helps us with the strictness of the typing in each model as now we properly outline what properties are needed at a bare minimum.

This props method property is left as optional because it allows some flexibility to the SDK user to just instantiate a type of object then either:

  • performing [model].fromJSON()
  • or, setting the property values individually via [model].[property] = value
    If taking this route, we initialize all the required types to a default value in order not to upset Typescript's strictness requirements.

With this, we also deprecate the RestfulModelCollection.build() method as it provides a way for the user to bypass the constructor typing requirements and pass in whatever object they want. It also does not provide any type hinting to the user when trying to initialize the object. Here's an example of the before and after:

const Nylas = require('nylas');
Nylas.config({clientId: 'clientId', clientSecret: 'clientSecret'});
const nylas = Nylas.with('access_token');

// before, user can put whatever they want
const event = nylas.events.build({foo: "bar"});

// now, this way the user has to abide by EventProperties or else face a warning from Typescript

// throws warning:
const event = new Event(nylas, {foo: "bar"});

// does not throw warning
const event = new Event(nylas, {calendarId: "id", when: {startTime: 1234, endTime: 4321}});

// also does not throw warning, inits and object that has default values set
const event = new Event(nylas);

Improving SDK Typing

The biggest change we've made here is that all of the SDK methods that are meant to be used by the end users all have a non-any return type. In addition to this, the PR improves on the previous work of the refactor to ensure that we are utilizing the use of models, interfaces, and proper deserialization. With this, our support for Calendar availability has improved with the introduction of classes and types for API objects like free-busy and availability. Our support for Native Authentication and Virtual Calendars have also seen improvements as we have models to represent these objects and introduced enums to provide the user an easier time with providing things like providers and scopes without needing to refer to the API docs to see what scopes/providers are supported and to reduce user typing errors.

Changlog -- Breaking Changes

  • Refactored RestfulModel and RestfulModelCollection, introduced Model and ModelCollection superclass for models that do not directly interact with the Nylas API
  • Introduction of interfaces that accompany models to improve experience when instantiating API models and provides better insight on "required" fields
  • Applied missing variable and return types, and applied stricter typing to improve deserialization and to adhere Typescript best practice
  • Event.when is now of When type
  • All Event fields for participants are now of EventParticipant type
  • Several Contact fields that took an object as a value now take a corresponding Contact subclass type
  • NeuralMessageOptions is now a Model class instead of an interface type
  • CalendarRestfulModelCollection.freeBusy() now returns a (new) FreeBusy type instead of a JSON
  • CalendarRestfulModelCollection.availability() now returns a (new) CalendarAvailability type instead of a JSON
  • CalendarRestfulModelCollection.consecutiveAvailability() now returns a (new) CalendarConsecutiveAvailability type instead of a JSON
  • Connect.authorize() now takes in a parameter of VirtualCalendarProperties | NativeAuthenticationProperties type (new) instead of an object and returns AuthorizationCode type (new) instead of a JSON
  • Connect.token() now returns an Account type instead of a JSON
  • Contact, EventConferencing, and Folder are now default exports
  • Nylas has stricter parameters and introduction of defined return types
  • Nylas.exchangeCodeForToken() now returns an AccessToken type that's a representation of the full API response as opposed to just the access token string
  • Nylas.application() takes ApplicationDetailProperties type and returns an ApplicationDetail type
  • Removed RestfulModelCollection.build() as it does not allow for proper property and type hinting in favor of instantiating via new Model()
  • Removed Connect.newAccount() as it had no functionality
  • Removed File.metadata() as it doesn't appear any different than making a NylasConnection.files().find() call
  • Lots of new models are introduced, almost all API objects are represented as a model in the SDK now
  • Introduction of Enum types

Migration Guide

The migration guide for this major release can be found on our Nylas Docs page!