Skip to content

Commit

Permalink
WIP migration guide for v2
Browse files Browse the repository at this point in the history
based on e71ed5f...c64732c

note that 1.2.50, to which this guide refers, doesn't exist yet

directory structure anticipates there also being
docs/migration-guides/v2/react-hooks.md

html tags used for headings because i'm gonna keep editing them and am
almost certianly going to get a broken link, so do stable ids (GitHub
doesn't seem to support
https://www.markdownguide.org/extended-syntax/#heading-ids)
and we don't have a linter

[skip ci]
  • Loading branch information
lawrence-forooghian committed Mar 15, 2024
1 parent 7fb2842 commit a224cdd
Showing 1 changed file with 207 additions and 0 deletions.
207 changes: 207 additions & 0 deletions docs/migration-guides/v2/lib.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# Migration guide for ably-js v2

Here’s how to migrate from ably-js v1 to v2:

1. [Stop using functionality that v1 deprecated](#stop-using-v1-deprecated).
1. [Stop using other functionality that v2 removes](#stop-using-v2-removed).
1. [Update to v2 and handle its breaking changes](#update-to-v2-and-handle-breaking-changes).
1. (Optional) [Stop using functionality that v2 deprecates](#stop-using-v2-deprecated).
1. (Optional) [Take advantage of new features that v2 introduces](#use-v2-new-features).

<h2 id="stop-using-v1-deprecated">Stop using functionality that v1 deprecated</h2>

Begin by updating to ably-js 1.2.50 or later, to make sure you see the deprecation log messages [described below](#stop-using-v1-deprecated-all-users).

Now, you need to stop using the functionality that is deprecated by v1 and which is removed in v2. Here we explain how.

The changes below are split into those that affect all users, and those that only affect TypeScript users.

<h3 id="stop-using-v1-deprecated-all-users">Changes that affect all users</h3>

In ably-js 1.2.50 or later, use of the following APIs will trigger a deprecation warning at runtime.

**Note about deprecation warnings:** These deprecation warnings take the form of log messages emitted through the library’s logging mechanism (i.e. `ClientOptions.log.handler` or `ClientOptions.logHandler` if you’ve set these properties, or else `console.log()`). To find them in your logs, search for `Ably: Deprecation warning`.

- Changes to `Crypto.getDefaultParams()`:
- The ability to pass a callback to this method has been removed. This method now directly returns its result, instead of returning it asynchronously. Update your code so that it uses the return value of this method instead of passing a callback. (TODO but callbacks aren't supported anyway, tie this up)
- The ability to call this method without specifying an encryption key has been removed. Update your code so that it instead passes an object whose `key` property contains an encryption key. That is, replace `Crypto.getDefaultParams()` with `Crypto.getDefaultParams({ key })`, where `key` is an encryption key that you have generated (for example from the `Crypto.generateRandomKey()` method).
- The ability to pass the encryption key as the first argument of this method has been removed. Update your code so that it instead passes an object whose `key` property contains the key. That is, replace `Crypto.getDefaultParams(key)` with `Crypto.getDefaultParams({ key })`.
- The `headers` client option has been removed. Remove your use of this client option.
- The `fallbackHostsUseDefault` client option has been removed.
- If you’re using this client option to force the library to make use of fallback hosts even though you’ve set the `environment` client option, then this is no longer necessary: remove your usage of the `fallbackHostsUseDefault` client option and the library will then automatically choose the correct fallback hosts to use for the specified environment.
- If you’re using this client option to force the library to make use of fallback hosts even though you’re not using the primary Ably environment, then stop using `fallbackHostsUseDefault`, and update your code to either pass the `environment` client option (in which case the library will automatically choose the correct fallback hosts to use for the specified environment), or to pass the `fallbackHosts` client option to specify a custom list of fallback hosts to use (for example, if you’re using a custom CNAME, in which case Ably will have provided you with an explicit list of fallback hosts).
- The ability to use a boolean value for the `recover` client option has been removed. If you wish for the connection to always be recovered, replace `{ recover: true }` with a function that always passes `true` to its callback: `{ recover: function(lastConnectionDetails, cb) { cb(true); } }`.
- The `log` client option has been removed. Equivalent functionality is provided by the `logLevel` and `logHandler` client options. Update your client options code of the form `{ log: { level: logLevel, handler: logHandler } }` to instead be `{ logLevel, logHandler }`.
- The ability to pass an array of channel mode flags as the first argument of `RealtimeChannel.attach()` has been removed. To set channel mode flags, populate the `modes` property of the channel options object that you pass to `Channels.get()` or `RealtimeChannel.setOptions()`.
- The `force` auth option has been removed. If you’re using this option to force `authorize()` to fetch a new token even if the current token has not expired, this is no longer necessary, as `authorize()` now always fetches a new token. Update your code to no longer pass the `force` auth option. Note that, in general, passing an auth options argument to `authorize()` will overwrite the library’s stored auth options, which may not be what you want. The library currently contains a special case behavior where passing an auth options object which only contains `{ force: true }` will _not_ overwrite the stored options. This special case behavior will be removed alongside support for the `force` option, so if you’re currently passing `authorize()` an auth options object which only contains `{ force: true }`, you should stop passing it an auth options object entirely.
- The `host` client option has been renamed to `restHost`. Update your code to use `restHost`.
- The `wsHost` client option has been renamed to `realtimeHost`. Update your code to use `realtimeHost`.
- The `queueEvents` client option has been renamed to `queueMessages`. Update your code to use `queueMessages`.
- `RealtimePresence`’s `on` method has been renamed to `subscribe`. Update your code to use `subscribe`.
- `RealtimePresence`’s `off` method has been renamed to `unsubscribe`. Update your code to use `unsubscribe`.
- `Auth`’s `authorise` method has been renamed to `authorize`. Update your code to use `authorize`.
- The `"xhr"` transport has been renamed to `"xhr_streaming"`. Update your client options code to use `transports: ["xhr_streaming"]`.

### Only TypeScript users

- The `stats()` method on `Rest` and `Realtime` no longer accepts an argument of type `any`. Make sure that any argument you pass to this method implements the `StatsParams` interface.
- The `fromEncoded<T>` and `fromEncodedArray<T>` types, which were already not being used by the library, are no longer exported by the library. Remove your references to these types.

<h2 id="stop-using-v2-removed">Stop using other functionality that v2 removes</h2>

<h3 id="switch-from-callbacks-to-promises">Switch from the callbacks-based variant of the library to the promise-based variant</h3>

ably-js v1 offered a choice between styles of asynchronous programming. There was a variant of the library that implemented asynchronous function calls via callbacks, and another that implemented them via promises. Now that promises are widely supported across modern JavaScript engines, ably-js v2 removes the callbacks variant of the library, and only offers promise-based asynchronicity.

So, if you’re currently using the callbacks variant of the library, then before upgrading to v2 you should switch to using the promises variant. Here, we explain how to do this.

First, you should stop choosing the callbacks variant of the library, and instead choose the promises variant. How exactly you should change your code to achieve this depends on how you’re currently choosing the callbacks variant:

- If you’re implicitly choosing the callbacks variant of the library by writing `require('ably')`, then update your code to `require(ably/promises)`.
- If you’re explicitly choosing the callbacks variant through the subpath of the imported module — that is, if you’re writing `require('ably/callbacks')` — then update your code to `require('ably/promises')`.
- If you’re explicitly choosing the callbacks variant at the moment of instantiating the client — that is, if you’re writing `new Ably.Rest.Callbacks(…)` or `new Ably.Realtime.Callbacks(…)` — then update your code to use the `Promise` property instead, i.e. write `new Ably.Realtime.Promise(…)` or `new Ably.Rest.Promise(…)`.

Now, update your code to use ably-js’s promise-based API instead of the callback-based API. **(TODO what would be good guidance on how to do this? Is it just "look at the v1 documentation for the promises variant and figure it out, here's a link", or an example of a single method call plus some hand-wavey instructions, or something else?)**

**Important:** For historical reasons, the `Crypto.generateRandomKey()` method does not have a promise-based version in v1. That is, even in the promise-based variant of the SDK, it implements asynchronicity via callbacks. So, if you’re using this method, then you’ll need to keep using the callback-based version of this method until upgrading to v2, which replaces the callback-based variant of this method with a promise-based one. For more information see [here](#switch-to-promise-based-generateRandomKey).

<h2 id="update-to-v2-and-handle-breaking-changes">Update to v2 and handle its breaking changes</h2>

Next, update to ably-js version 2.0.0 or later.

Now, you need to address the other breaking changes introduced by v2. Here we explain how.

The changes below are split into those that affect all users, and those that only affect TypeScript users.

### All users

#### Stop explicitly selecting the promise-based variant of the library

As [mentioned above](#switch-from-callbacks-to-promises), v2 of the library no longer offers a choice between a callbacks-based API and a promises-based API. This means that v1’s mechanism for choosing which variant to use has been removed, so you should stop using this mechanism.

- If you’re explicitly choosing the promises variant of the library through the subpath of the imported module — that is, if you’re writing `require('ably/promises')` — then update your code to `require('ably')`.
- If you’re explicitly choosing the promises variant at the moment of instantiating the client — that is, if you’re writing `new Ably.Rest.Promise(…)` or `new Ably.Realtime.Promise(…)` — then update your code remove the use of the `Promise` property, i.e. write `new Ably.Realtime(…)` or `new Ably.Rest(…)`.

#### Be aware of platforms that are no longer supported

v2 of the library drops support for some platforms that v1 supported. Most notably, it no longer supports Internet Explorer or non-LTS versions of Node.js. For more information, see [this section of the Readme](../../../README.md#supported-platforms).

<h4 id="switch-to-promise-based-generateRandomKey">Switch to using the new promise-based API of <code>Crypto.generateRandomKey()</code></h4>

**Note:** This section is only relevant if you’re using the `Crypto.generateRandomKey()` method.

If you’re using the `Crypto.generateRandomKey()` method, you’ll need to change how you call this method. In v1, this method required that you pass a callback. In v2, it communicates its result by returning a promise.

So you need to change code that looks like this:

```javascript
Ably.Realtime.Crypto.generateRandomKey((key) => { … })
```

into code that looks like this:

```javascript
const key = await Ably.Realtime.Crypto.generateRandomKey();
```

#### Update your usage of `Rest.request()` to pass a `version` argument

**Note:** This section is only relevant if you’re using the `Rest.request()` method.

The signature of this method has been changed; it now requires that you pass a `version` argument to specify the major version of the REST API to use. For more information about REST API versioning, see [this section of the REST API reference](https://ably.com/docs/api/rest-api#versioning).

TODO this wording "major version" comes from https://github.com/ably/sdk-api-reference/pull/32#pullrequestreview-1408872163. I guess that it means you should take the current sentence 'By default, all requests receive the latest version of the API, which is currently 1.1' from the linked versioning page and infer that the "major version" is 1, and so that's what I should pass to `Rest.request()`. But I thought that we've moved away from using a `major.minor` protocol version to just a single integer? See https://sdk.ably.com/builds/ably/specification/main/features/#CSV2a. Should we update those versioning docs to say that the latest version of the API is 3, and then drop the "major" in the documentation for `Rest.request()`?

As an example, given the current code to [get the service time](https://ably.com/docs/api/rest-api#time):

```javascript
const time = await rest.request('get', '/time');
```

add an argument to specify the API version:

```javascript
const time = await rest.request('get', '/time', 3);
```

- [Add mandatory version param to Rest.request](https://github.com/ably/ably-js/commit/ba77bfb0d2b59210aec1f920604b2f81096f870c)

#### Be aware of changed `whenState()` behaviour

**Note:** This section is only relevant if you’re using the `RealtimeChannel.whenState()` or `Connection.whenState()` methods.

The `RealtimeChannel.whenState()` and `Connection.whenState()` methods now return `null` when the connection is already in the given state, instead of attempting to synthesize an artificial state change.

#### Be aware that the `fromEncoded()` and `fromEncodedArray()` methods are now async

**Note:** This section is only relevant if you’re using `Message` or `PresenceMessage`’s `fromEncoded` or `fromEncodedArray` methods.

`Message` and `PresenceMessage`’s `fromEncoded` and `fromEncodedArray` methods now operate asynchronously. That is, instead of returning the decoding result, they return a promise. Update your code to `await` the result of these methods.

<h4 id="secure-context">Be aware that symmetric encryption in a browser now requires a secure context</h4>

**Note:** This section is only relevant if you’re using the `cipher` client option and running in a browser.

If you’re making use of the `cipher` client option to enable symmetric encryption on a channel, be aware that when running in a browser this functionality is now implemented using the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API). Hence, this functionality is only available when this API is available; namely, when the current environment is a [secure context](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). Roughly speaking, this means that you can now only use Ably channel encryption inside a web page when serving your page over HTTPS or from `localhost`.

<h4 id="no-more-CryptoJS">Be aware that the library no longer uses CryptoJS and hence no longer works with <code>WordArray</code></h4>

**Note:** This section is only relevant if you’re using the `cipher` client option and running in a browser.

When running in a browser, the library previously used the CryptoJS library for implementing symmetric encryption on a channel. As mentioned [here](#secure-context), the library now instead uses the built-in Web Crypto API.

This means that the library is no longer capable of interacting with CryptoJS’s `WordArray` type. Specifically:

- `Crypto.generateRandomKey()` now returns an `ArrayBuffer` instead of a `WordArray`.
- `Crypto.getDefaultParams({ key })` no longer accepts a `WordArray` key; pass an `ArrayBuffer` or `Uint8Array` instead.

#### Stop using the `noencryption` variant of the library

**Note:** This section is only relevant if you’re importing `ably/build/ably.noencryption.min.js` or using the `ably.noencryption.min-1.js` CDN build.

In v1, we provided a separate version of the library that did not support the `cipher` channel option. This was offered for those who did not wish to bloat their app’s bundle size with encryption code.

Since v2 [no longer uses the CryptoJS library](#no-more-CryptoJS), the `cipher` channel option functionality now has a much smaller impact on your app’s bundle size. So, we no longer offer the `noencryption` variant of the library.

Furthermore, v2 introduces the [modular variant of the library](#modular-variant), which is specifically aimed at those who are concerned about their app’s bundle size. It provides a general mechanism for choosing which Ably functionality you wish to include in your app’s bundle. So, if you do not wish to incur even the small bundle size overhead that the `cipher` channel option imposes, consider using the modular variant of the library without the `Crypto` module.

#### Stop using the special Web Worker build of the library

**Note:** This section is only relevant if you’re using ably-js inside a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API).

In v1, if you wished to use ably-js inside a Web Worker, you had to use a special build of the library, by writing `import Ably from 'ably/build/ably-webworker.min';`.

In v2, the library can be used inside a Web Worker without needing to use a special build, and this special `ably-webworker` build no longer exists. So, update your code to `import Ably from 'ably';`.

#### Removal of `ably-commonjs*.js` files

TODO

- [removed `ably-commonjs*.js` files](https://github.com/ably/ably-js/commit/359f9a79ac1b31bc544b2b04bed206c439dea541)

(this affects the guidance in the `README` about directly referencing this file — and I’m not even sure if that guidance is valid post `exports`, need to check)

### Only TypeScript users

TODO

- [Remove `Realtime < Rest` inheritance in public API](https://github.com/ably/ably-js/commit/69c35f14fd82e8b33f9d88ad78180db3d3acc888)
- [Fix optionality of `Message` properties](https://github.com/ably/ably-js/commit/4e3733f427fe70754dc36a6a9928182c79e81d72)
- [Tighten type of publishing methods](https://github.com/ably/ably-js/commit/19a8d475fb892c9b308685ebf015a50d6ba8e9b2)
- [Add "Abstract" prefix to Types.{Rest, Realtime} names](https://github.com/ably/ably-js/commit/312298a7a95370f149b63ac8751caf8b73e76b2a) — I think this was since changed though; there’s nothing with those names. I’m seeing `RealtimeClient` and `RestClient` interfaces. Ah, yep, changed it in [Rename Abstract* classes to *Client](https://github.com/ably/ably-js/commit/44eae5d4b6010b86c2043edaa4bd83523903d69e)
- [Remove the Types namespace](https://github.com/ably/ably-js/commit/30f267d8f9f377bde2917cd3f61dd598bbeadb21)
- [Remove public ChannelModes type](https://github.com/ably/ably-js/commit/04f0f16427c0caab9799b02ee73877f6b71e5ded)
- [Remove duplicate type names](https://github.com/ably/ably-js/commit/f7e28aa029a64f178c2996c668f4bab878033c03)
- [Merge `*Base` and `*Promise` classes](https://github.com/ably/ably-js/commit/6cb717990d5a993ebd6e0430b2b2629660c27cf8) (perhaps link to the previous section though)

<h2 id="stop-using-v2-deprecated">Stop using functionality that v2 deprecates</h2>

TODO

- [Typings: update v2 typings to use createRecoveryKey() instead of reco…](https://github.com/ably/ably-js/commit/717b060122ace7c7495e6dbade4be25ff260b598)

<h2 id="use-v2-new-features">Take advantage of new features that v2 introduces</h2>

<h3 id="modular-variant">Using the modular variant of the library</h3>

TODO brief overview, link to readme section

0 comments on commit a224cdd

Please sign in to comment.