From 48ede7f9aebdbb13463d50981dd1001f3ea3c9ff Mon Sep 17 00:00:00 2001
From: Lawrence Forooghian
Date: Mon, 13 Nov 2023 15:52:22 -0300
Subject: [PATCH] Add documentation for the modular version of the library
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
I imagine there’s plenty of room for improvement here, but it’s a start.
Hopefully a tech writer will be able to have a look at it before we
release, too.
For handling TypeDoc documentation for the two different variants of the
library, I’ve resurrected the approach that we used when we had
callback-based and Promise-based variants of the library (removed in
2a2ed49).
Resolves #1443.
---
README.md | 31 ++++
ably.d.ts | 2 +
modules.d.ts | 214 ++++++++++++++++++++++
package.json | 2 +-
typedoc/landing-page.md | 7 -
typedoc/landing-pages/choose-library.html | 31 ++++
typedoc/landing-pages/default.md | 5 +
typedoc/landing-pages/modules.md | 21 +++
8 files changed, 305 insertions(+), 8 deletions(-)
delete mode 100644 typedoc/landing-page.md
create mode 100644 typedoc/landing-pages/choose-library.html
create mode 100644 typedoc/landing-pages/default.md
create mode 100644 typedoc/landing-pages/modules.md
diff --git a/README.md b/README.md
index f8d4607101..55f1ab07e5 100644
--- a/README.md
+++ b/README.md
@@ -81,6 +81,37 @@ WebPack will search your `node_modules` folder by default, so if you include `ab
If that doesn't work for some reason (e.g. you are using a custom webpack target), you can reference the `ably.js` static file directly: `require('ably/build/ably.js');` (or `import * as Ably from 'ably/build/ably.js'` for typescript / ES6 modules).
+#### Modular (tree-shakable) variant
+
+Aimed at those who are concerned about their app’s bundle size, the modular variant of the library allows you to create a client which has only the functionality that you choose. Unused functionality can then be tree-shaken by your module bundler.
+
+The modular variant of the library provides:
+
+- a `BaseRealtime` class;
+- various modules that add functionality to a `BaseRealtime` instance, such as `Rest`, `RealtimePresence`, etc.
+
+To use this variant of the library, import the `BaseRealtime` class from `ably/modules`, along with the modules that you wish to use. Then, pass these modules to the `BaseRealtime` constructor as shown in the example below:
+
+```javascript
+import { BaseRealtime, WebSocketTransport, FetchRequest, RealtimePresence } from 'ably/modules';
+
+const options = { key: 'YOUR_ABLY_API_KEY' /* Replace with a real key from the Ably dashboard */ };
+const client = new BaseRealtime(options, {
+ WebSocketTransport,
+ FetchRequest,
+ RealtimePresence
+});
+```
+
+You must provide:
+
+- at least one HTTP request implementation; that is, one of `FetchRequest` or `XHRRequest`;
+- at least one realtime transport implementation; that is, one of `WebSocketTransport`, `XHRStreaming`, or `XHRPolling`.
+
+`BaseRealtime` offers the same API as the `Realtime` class described in the rest of this `README`. This means that you can develop an application using the default variant of the SDK and switch to the modular version when you wish to optimize your bundle size.
+
+For more information, see the [generated documentation](https://sdk.ably.com/builds/ably/ably-js/main/typedoc/modules/index.html) (this link points to the documentation for the `main` branch).
+
### TypeScript
The TypeScript typings are included in the package and so all you have to do is:
diff --git a/ably.d.ts b/ably.d.ts
index fa58110328..ffaf96a8ee 100644
--- a/ably.d.ts
+++ b/ably.d.ts
@@ -2219,6 +2219,8 @@ declare namespace Types {
*/
subscribe(events: Array, listener?: messageCallback): Promise;
/**
+ * {@label WITH_MESSAGE_FILTER}
+ *
* Registers a listener for messages on this channel that match the supplied filter.
*
* @param filter - A {@link MessageFilter}.
diff --git a/modules.d.ts b/modules.d.ts
index 45e48bd18f..0ea246a164 100644
--- a/modules.d.ts
+++ b/modules.d.ts
@@ -10,35 +10,249 @@ export declare const decodePresenceMessage: Types.PresenceMessageStatic['fromEnc
export declare const decodePresenceMessages: Types.PresenceMessageStatic['fromEncodedArray'];
export declare const constructPresenceMessage: Types.PresenceMessageStatic['fromValues'];
+/**
+ * Provides REST-related functionality to a {@link BaseRealtime} client.
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest, Rest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest, Rest });
+ * ```
+ *
+ * When provided, the following functionality becomes available:
+ *
+ * - { @link Types.Push | push admin }
+ * - { @link BaseRealtime.time | retrieving Ably service time }
+ * - { @link BaseRealtime.request | making arbitrary REST requests }
+ * - { @link BaseRealtime.batchPublish | batch publishing of messages }
+ * - { @link BaseRealtime.batchPresence | batch retrieval of channel presence state }
+ * - { @link Types.Auth.revokeTokens | requesting the revocation of tokens }
+ * - { @link Types.RealtimeChannel.history | retrieving the message history of a channel }
+ * - { @link Types.RealtimePresence.history | retrieving the presence history of a channel }
+ *
+ * If this module is not provided, then trying to use the above functionality will cause a runtime error.
+ */
export declare const Rest: unknown;
+
+/**
+ * Provides a {@link BaseRest} or {@link BaseRealtime} instance with the ability to encrypt and decrypt {@link Types.Message} payloads.
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest, Crypto } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest, Crypto });
+ * ```
+ *
+ * When provided, you can configure message encryption on a channel via the {@link Types.ChannelOptions.cipher} property of the `ChannelOptions` that you pass when {@link Types.Channels.get | fetching a channel}. If this module is not provided, then passing a `ChannelOptions` with a `cipher` property will cause a runtime error.
+ */
export declare const Crypto: unknown;
+
+/**
+ * Provides a {@link BaseRest} or {@link BaseRealtime} instance with the ability to communicate with the Ably service using the more space-efficient [MessagePack](https://msgpack.org/index.html) format.
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest, MsgPack } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest, MsgPack });
+ * ```
+ *
+ * When provided, you can control whether the client uses MessagePack via the {@link Types.ClientOptions.useBinaryProtocol} client option. If you do not provide this module, then the library will always JSON format for encoding messages.
+ */
export declare const MsgPack: unknown;
+
+/**
+ * Provides a {@link BaseRealtime} instance with the ability to interact with a channel’s presence set.
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest, RealtimePresence } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest, RealtimePresence });
+ * ```
+ *
+ * If you do not provide this module, then attempting to access a channel’s {@link Types.RealtimeChannel.presence} property will cause a runtime error.
+ */
export declare const RealtimePresence: unknown;
+
+/**
+ * Provides a {@link BaseRealtime} instance with the ability to establish a connection with the Ably realtime service using a [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) connection.
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest });
+ * ```
+ *
+ * Note that network conditions, such as firewalls or proxies, might prevent the client from establishing a WebSocket connection. For this reason, you may wish to provide the `BaseRealtime` instance with the ability to alternatively establish a connection using a transport that is less susceptible to these external conditions. You do this by passing one or more alternative transport modules, namely {@link XHRStreaming} and/or {@link XHRPolling}, alongside `WebSocketTransport`:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, XHRStreaming, FetchRequest });
+ * ```
+ */
export declare const WebSocketTransport: unknown;
+
+/**
+ * Provides a {@link BaseRealtime} instance with the ability to establish a connection with the Ably realtime service using the browser’s [XMLHttpRequest API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest).
+ *
+ * `XHRPolling` uses HTTP long polling; that is, it will make a new HTTP request each time a message is received from Ably. This is less efficient than {@link XHRStreaming}, but is also more likely to succeed in the presence of certain network conditions such as firewalls or proxies.
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { XHRPolling, FetchRequest });
+ * ```
+ *
+ * Provide this module if, for example, you wish the client to have an alternative mechanism for connecting to Ably if it’s unable to establish a WebSocket connection.
+ */
export declare const XHRPolling: unknown;
+
+/**
+ * Provides a {@link BaseRealtime} instance with the ability to establish a connection with the Ably realtime service using the browser’s [XMLHttpRequest API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest).
+ *
+ * `XHRStreaming` uses HTTP streaming; that is, in contrast to {@link XHRPolling}, it does not need to make a new HTTP request each time a message is received from Ably. This is more efficient than `XHRPolling`, but is more likely to be blocked by certain network conditions such as firewalls or proxies.
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { XHRStreaming, FetchRequest });
+ * ```
+ *
+ * Provide this module if, for example, you wish the client to have an alternative mechanism for connecting to Ably if it’s unable to establish a WebSocket connection.
+ */
export declare const XHRStreaming: unknown;
+
+/**
+ * Provides a {@link BaseRest} or {@link BaseRealtime} instance with the ability to make HTTP requests using the browser’s [XMLHttpRequest API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest).
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, XHRRequest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, XHRRequest });
+ * ```
+ */
export declare const XHRRequest: unknown;
+
+/**
+ * Provides a {@link BaseRest} or {@link BaseRealtime} instance with the ability to make HTTP requests using the browser’s [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest });
+ * ```
+ */
export declare const FetchRequest: unknown;
+
+/**
+ * Provides a {@link BaseRealtime} instance with the ability to filter channel subscriptions at runtime using { @link Types.RealtimeChannel.subscribe:WITH_MESSAGE_FILTER | the overload of `subscribe()` that accepts a `MessageFilter` }.
+ *
+ * To create a client that includes this module, include it in the `ModulesMap` that you pass to the {@link BaseRealtime.constructor}:
+ *
+ * ```javascript
+ * import { BaseRealtime, WebSocketTransport, FetchRequest, MessageInteractions } from 'ably/modules';
+ * const realtime = new BaseRealtime(options, { WebSocketTransport, FetchRequest, MessageInteractions });
+ * ```
+ *
+ * If you do not provide this module, then attempting to use this overload of `subscribe()` will cause a runtime error.
+ */
export declare const MessageInteractions: unknown;
+/**
+ * Pass a `ModulesMap` to { @link BaseRest.constructor | the constructor of BaseRest } or {@link BaseRealtime.constructor | that of BaseRealtime} to specify which functionality should be made available to that client.
+ */
export interface ModulesMap {
+ /**
+ * See {@link Rest | documentation for the `Rest` module}.
+ */
Rest?: typeof Rest;
+
+ /**
+ * See {@link Crypto | documentation for the `Crypto` module}.
+ */
Crypto?: typeof Crypto;
+
+ /**
+ * See {@link MsgPack | documentation for the `MsgPack` module}.
+ */
MsgPack?: typeof MsgPack;
+
+ /**
+ * See {@link RealtimePresence | documentation for the `RealtimePresence` module}.
+ */
RealtimePresence?: typeof RealtimePresence;
+
+ /**
+ * See {@link WebSocketTransport | documentation for the `WebSocketTransport` module}.
+ */
WebSocketTransport?: typeof WebSocketTransport;
+
+ /**
+ * See {@link XHRPolling | documentation for the `XHRPolling` module}.
+ */
XHRPolling?: typeof XHRPolling;
+
+ /**
+ * See {@link XHRStreaming | documentation for the `XHRStreaming` module}.
+ */
XHRStreaming?: typeof XHRStreaming;
+
+ /**
+ * See {@link XHRRequest | documentation for the `XHRRequest` module}.
+ */
XHRRequest?: typeof XHRRequest;
+
+ /**
+ * See {@link FetchRequest | documentation for the `FetchRequest` module}.
+ */
FetchRequest?: typeof FetchRequest;
+
+ /**
+ * See {@link MessageInteractions | documentation for the `MessageInteractions` module}.
+ */
MessageInteractions?: typeof MessageInteractions;
}
+/**
+ * A client that offers a simple stateless API to interact directly with Ably's REST API.
+ *
+ * `BaseRest` is the equivalent, in the modular variant of the Ably Client Library SDK, of the [`Rest`](../../default/classes/Rest.html) class in the default variant of the SDK. The difference is that its constructor allows you to decide exactly which functionality the client should include. This allows unused functionality to be tree-shaken, reducing bundle size.
+ */
export declare class BaseRest extends Types.Rest {
+ /**
+ * Construct a client object using an Ably {@link Types.ClientOptions} object.
+ *
+ * @param options - A {@link Types.ClientOptions} object to configure the client connection to Ably.
+ * @param modules - An object which describes which functionality the client should offer. See the documentation for {@link ModulesMap}.
+ *
+ * You must provide at least one HTTP request implementation; that is, one of {@link FetchRequest} or {@link XHRRequest}. For minimum bundle size, favour `FetchRequest`.
+ *
+ * The {@link Rest} module is always implicitly included.
+ */
constructor(options: Types.ClientOptions, modules: ModulesMap);
}
+/**
+ * A client that extends the functionality of {@link BaseRest} and provides additional realtime-specific features.
+ *
+ * `BaseRealtime` is the equivalent, in the modular variant of the Ably Client Library SDK, of the [`Realtime`](../../default/classes/Realtime.html) class in the default variant of the SDK. The difference is that its constructor allows you to decide exactly which functionality the client should include. This allows unused functionality to be tree-shaken, reducing bundle size.
+ */
export declare class BaseRealtime extends Types.Realtime {
+ /**
+ * Construct a client object using an Ably {@link Types.ClientOptions} object.
+ *
+ * @param options - A {@link Types.ClientOptions} object to configure the client connection to Ably.
+ * @param modules - An object which describes which functionality the client should offer. See the documentation for {@link ModulesMap}.
+ *
+ * You must provide:
+ *
+ * - at least one HTTP request implementation; that is, one of {@link FetchRequest} or {@link XHRRequest} — for minimum bundle size, favour `FetchRequest`;
+ * - at least one realtime transport implementation; that is, one of {@link WebSocketTransport}, {@link XHRStreaming}, or {@link XHRPolling} — for minimum bundle size, favour `WebSocketTransport`.
+ */
constructor(options: Types.ClientOptions, modules: ModulesMap);
}
diff --git a/package.json b/package.json
index 858cf24c51..7667646f9b 100644
--- a/package.json
+++ b/package.json
@@ -132,6 +132,6 @@
"format:check": "prettier --check --ignore-path .gitignore --ignore-path .prettierignore src test ably.d.ts modules.d.ts webpack.config.js Gruntfile.js scripts/*.js",
"sourcemap": "source-map-explorer build/ably.min.js",
"modulereport": "node scripts/moduleReport.js",
- "docs": "typedoc --entryPoints ably.d.ts --out typedoc/generated --readme typedoc/landing-page.md"
+ "docs": "typedoc --entryPoints ably.d.ts --out typedoc/generated/default --readme typedoc/landing-pages/default.md && typedoc --entryPoints modules.d.ts --out typedoc/generated/modules --name \"ably (modular version)\" --readme typedoc/landing-pages/modules.md && cp typedoc/landing-pages/choose-library.html typedoc/generated/index.html"
}
}
diff --git a/typedoc/landing-page.md b/typedoc/landing-page.md
deleted file mode 100644
index f9a0bb6212..0000000000
--- a/typedoc/landing-page.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Ably JavaScript Client Library SDK API Reference
-
-The JavaScript Client Library SDK supports a realtime and a REST interface. The JavaScript API references are generated from the [Ably JavaScript Client Library SDK source code](https://github.com/ably/ably-js/) using [TypeDoc](https://typedoc.org) and structured by classes.
-
-The realtime interface enables a client to maintain a persistent connection to Ably and publish, subscribe and be present on channels. The REST interface is stateless and typically implemented server-side. It is used to make requests such as retrieving statistics, token authentication and publishing to a channel.
-
-View the [Ably docs](https://ably.com/docs/) for conceptual information on using Ably, and for API references featuring all languages. The combined [API references](https://ably.com/docs/api/) are organized by features and split between the [realtime](https://ably.com/docs/api/realtime-sdk) and [REST](https://ably.com/docs/api/rest-sdk) interfaces.
diff --git a/typedoc/landing-pages/choose-library.html b/typedoc/landing-pages/choose-library.html
new file mode 100644
index 0000000000..d6a91bb42e
--- /dev/null
+++ b/typedoc/landing-pages/choose-library.html
@@ -0,0 +1,31 @@
+
+
+
+
+ Ably JavaScript Client Library SDK API Reference
+
+
+ Ably JavaScript Client Library SDK API Reference
+
+
+ The JavaScript Client Library SDK supports a realtime and a REST interface. The JavaScript API references are generated from the Ably JavaScript Client Library SDK source code using TypeDoc and structured by classes.
+
+
+
+ The realtime interface enables a client to maintain a persistent connection to Ably and publish, subscribe and be present on channels. The REST interface is stateless and typically implemented server-side. It is used to make requests such as retrieving statistics, token authentication and publishing to a channel.
+
+
+
+ There are two variants of the Ably JavaScript Client Library SDK:
+
+
+ - Default variant: This variant of the SDK always creates a fully-featured Ably client.
+ - Modular (tree-shakable) variant: Aimed at those who are concerned about their app’s bundle size, this allows you to create a client which has only the functionality that you choose.
+
+
+
+
+ View the Ably docs for conceptual information on using Ably, and for API references featuring all languages. The combined API references are organized by features and split between the realtime and REST interfaces.
+
+
+
diff --git a/typedoc/landing-pages/default.md b/typedoc/landing-pages/default.md
new file mode 100644
index 0000000000..9f2e9698e8
--- /dev/null
+++ b/typedoc/landing-pages/default.md
@@ -0,0 +1,5 @@
+# Ably JavaScript Client Library SDK API Reference
+
+You are currently viewing the default variant of the Ably JavaScript Client Library SDK. View the modular variant [here](../modules/index.html).
+
+To get started with the Ably JavaScript Client Library SDK, follow the [Quickstart Guide](https://ably.com/docs/quick-start-guide) or view the introductions to the [realtime](https://ably.com/docs/realtime/usage) and [REST](https://ably.com/docs/rest/usage) interfaces.
diff --git a/typedoc/landing-pages/modules.md b/typedoc/landing-pages/modules.md
new file mode 100644
index 0000000000..2a9ff63dea
--- /dev/null
+++ b/typedoc/landing-pages/modules.md
@@ -0,0 +1,21 @@
+# Ably JavaScript Client Library SDK API Reference (modular variant)
+
+You are currently viewing the modular (tree-shakable) variant of the Ably JavaScript Client Library SDK. View the callback-based variant [here](../default/index.html).
+
+To get started with the Ably JavaScript Client Library SDK, follow the [Quickstart Guide](https://ably.com/docs/quick-start-guide) or view the introductions to the [realtime](https://ably.com/docs/realtime/usage) and [REST](https://ably.com/docs/rest/usage) interfaces.
+
+## No `static` class functionality
+
+In contrast to the default variant of the SDK, the modular variant does not expose any functionality via `static` class properties or methods, since they cannot be tree-shaken by module bundlers. Instead, it exports free-standing functions which provide the same functionality. These are:
+
+| `static` version | Replacement in modular variant |
+| ------------------------------------------ | ----------------------------------------------------------------------- |
+| `Crypto.generateRandomKey()` | [`generateRandomKey()`](functions/generateRandomKey.html) |
+| `Crypto.getDefaultParams()` | [`getDefaultCryptoParams()`](functions/getDefaultCryptoParams.html) |
+| `MessageStatic.fromEncoded()` | [`decodeMessage()`](functions/decodeMessage.html) |
+| `MessageStatic.fromEncoded()` | [`decodeEncryptedMessage()`](functions/decodeEncryptedMessage.html) |
+| `MessageStatic.fromEncodedArray()` | [`decodeMessages()`](functions/decodeMessages.html) |
+| `MessageStatic.fromEncodedArray()` | [`decodeEncryptedMessages()`](functions/decodeEncryptedMessages.html) |
+| `PresenceMessageStatic.fromEncoded()` | [`decodePresenceMessage()`](functions/decodePresenceMessage.html) |
+| `PresenceMessageStatic.fromEncodedArray()` | [`decodePresenceMessages()`](functions/decodePresenceMessages.html) |
+| `PresenceMessageStatic.fromValues()` | [`constructPresenceMessage()`](functions/constructPresenceMessage.html) |