Skip to content

Commit

Permalink
Merge pull request #1498 from ably/1442-add-typings-for-tree-shakable…
Browse files Browse the repository at this point in the history
…-version

[SDK-3857] Add typings for the tree-shakable version of the library
  • Loading branch information
lawrence-forooghian authored Nov 21, 2023
2 parents cdcf043 + b839715 commit a47c23d
Show file tree
Hide file tree
Showing 15 changed files with 219 additions and 146 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ module.exports = {
},
},
{
files: 'ably.d.ts',
files: ['ably.d.ts', 'modules.d.ts'],
extends: [
'plugin:jsdoc/recommended',
],
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ jobs:
- run: npm ci
- run: npm run lint
- run: npm run format:check
- run: npx tsc --noEmit ably.d.ts build/ably-webworker.min.d.ts
- run: npx tsc --noEmit ably.d.ts modules.d.ts build/ably-webworker.min.d.ts
- run: npm audit --production
149 changes: 54 additions & 95 deletions ably.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1700,32 +1700,7 @@ declare namespace Types {
/**
* A client that offers a simple stateless API to interact directly with Ably's REST API.
*/
class 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.
*/
constructor(options: Types.ClientOptions);
/**
* Constructs a client object using an Ably API key or token string.
*
* @param keyOrToken - The Ably API key or token string used to validate the client.
*/
constructor(keyOrToken: string);
/**
* The cryptographic functions available in the library.
*/
static Crypto: Types.Crypto;
/**
* Static utilities related to messages.
*/
static Message: Types.MessageStatic;
/**
* Static utilities related to presence messages.
*/
static PresenceMessage: Types.PresenceMessageStatic;

abstract class Rest {
/**
* An {@link Types.Auth} object.
*/
Expand Down Expand Up @@ -1799,31 +1774,7 @@ declare namespace Types {
/**
* A client that extends the functionality of {@link Rest} and provides additional realtime-specific features.
*/
class 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.
*/
constructor(options: Types.ClientOptions);
/**
* Constructs a client object using an Ably API key or token string.
*
* @param keyOrToken - The Ably API key or token string used to validate the client.
*/
constructor(keyOrToken: string);
/**
* The cryptographic functions available in the library.
*/
static Crypto: Types.Crypto;
/**
* Static utilities related to messages.
*/
static Message: Types.MessageStatic;
/**
* Static utilities related to presence messages.
*/
static PresenceMessage: Types.PresenceMessageStatic;
abstract class Realtime {
/**
* A client ID, used for identifying this client when publishing messages or for presence purposes. The `clientId` can be any non-empty string, except it cannot contain a `*`. This option is primarily intended to be used in situations where the library is instantiated with a key. A `clientId` may also be implicit in a token used to instantiate the library; an error will be raised if a `clientId` specified here conflicts with the `clientId` implicit in the token.
*/
Expand Down Expand Up @@ -2387,28 +2338,6 @@ declare namespace Types {
* Contains an individual message that is sent to, or received from, Ably.
*/
class Message {
/**
* Constructor for internal use.
*
* @internal
*/
constructor();
/**
* A static factory method to create a `Message` object from a deserialized Message-like object encoded using Ably's wire protocol.
*
* @param JsonObject - A `Message`-like deserialized object.
* @param channelOptions - A {@link ChannelOptions} object. If you have an encrypted channel, use this to allow the library to decrypt the data.
* @returns A promise which will be fulfilled with a `Message` object.
*/
static fromEncoded: (JsonObject: any, channelOptions?: ChannelOptions) => Promise<Message>;
/**
* A static factory method to create an array of `Message` objects from an array of deserialized Message-like object encoded using Ably's wire protocol.
*
* @param JsonArray - An array of `Message`-like deserialized objects.
* @param channelOptions - A {@link ChannelOptions} object. If you have an encrypted channel, use this to allow the library to decrypt the data.
* @returns A promise which will be fulfilled with an array of {@link Message} objects.
*/
static fromEncodedArray: (JsonArray: any[], channelOptions?: ChannelOptions) => Promise<Message[]>;
/**
* The client ID of the publisher of this message.
*/
Expand Down Expand Up @@ -2469,26 +2398,6 @@ declare namespace Types {
* Contains an individual presence update sent to, or received from, Ably.
*/
class PresenceMessage {
/**
* Constructor for internal use.
*
* @internal
*/
constructor();
/**
* Decodes and decrypts a deserialized `PresenceMessage`-like object using the cipher in {@link ChannelOptions}. Any residual transforms that cannot be decoded or decrypted will be in the `encoding` property. Intended for users receiving messages from a source other than a REST or Realtime channel (for example a queue) to avoid having to parse the encoding string.
*
* @param JsonObject - The deserialized `PresenceMessage`-like object to decode and decrypt.
* @param channelOptions - A {@link ChannelOptions} object containing the cipher.
*/
static fromEncoded: (JsonObject: any, channelOptions?: ChannelOptions) => Promise<PresenceMessage>;
/**
* Decodes and decrypts an array of deserialized `PresenceMessage`-like object using the cipher in {@link ChannelOptions}. Any residual transforms that cannot be decoded or decrypted will be in the `encoding` property. Intended for users receiving messages from a source other than a REST or Realtime channel (for example a queue) to avoid having to parse the encoding string.
*
* @param JsonArray - An array of deserialized `PresenceMessage`-like objects to decode and decrypt.
* @param channelOptions - A {@link ChannelOptions} object containing the cipher.
*/
static fromEncodedArray: (JsonArray: any[], channelOptions?: ChannelOptions) => Promise<PresenceMessage[]>;
/**
* The type of {@link PresenceAction} the `PresenceMessage` is for.
*/
Expand Down Expand Up @@ -2891,12 +2800,62 @@ declare namespace Types {
/**
* A client that offers a simple stateless API to interact directly with Ably's REST API.
*/
export declare class Rest extends Types.Rest {}
export declare class Rest 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.
*/
constructor(options: Types.ClientOptions);
/**
* Constructs a client object using an Ably API key or token string.
*
* @param keyOrToken - The Ably API key or token string used to validate the client.
*/
constructor(keyOrToken: string);
/**
* The cryptographic functions available in the library.
*/
static Crypto: Types.Crypto;
/**
* Static utilities related to messages.
*/
static Message: Types.MessageStatic;
/**
* Static utilities related to presence messages.
*/
static PresenceMessage: Types.PresenceMessageStatic;
}

/**
* A client that extends the functionality of {@link Rest} and provides additional realtime-specific features.
*/
export declare class Realtime extends Types.Realtime {}
export declare class Realtime 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.
*/
constructor(options: Types.ClientOptions);
/**
* Constructs a client object using an Ably API key or token string.
*
* @param keyOrToken - The Ably API key or token string used to validate the client.
*/
constructor(keyOrToken: string);
/**
* The cryptographic functions available in the library.
*/
static Crypto: Types.Crypto;
/**
* Static utilities related to messages.
*/
static Message: Types.MessageStatic;
/**
* Static utilities related to presence messages.
*/
static PresenceMessage: Types.PresenceMessageStatic;
}

/**
* A generic Ably error object that contains an Ably-specific status code, and a generic status code. Errors returned from the Ably server are compatible with the `ErrorInfo` structure and should result in errors that inherit from `ErrorInfo`.
Expand Down
45 changes: 45 additions & 0 deletions modules.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Types } from './ably';

export declare const generateRandomKey: Types.Crypto['generateRandomKey'];
export declare const getDefaultCryptoParams: Types.Crypto['getDefaultParams'];
export declare const decodeMessage: Types.MessageStatic['fromEncoded'];
export declare const decodeEncryptedMessage: Types.MessageStatic['fromEncoded'];
export declare const decodeMessages: Types.MessageStatic['fromEncodedArray'];
export declare const decodeEncryptedMessages: Types.MessageStatic['fromEncodedArray'];
export declare const decodePresenceMessage: Types.PresenceMessageStatic['fromEncoded'];
export declare const decodePresenceMessages: Types.PresenceMessageStatic['fromEncodedArray'];
export declare const constructPresenceMessage: Types.PresenceMessageStatic['fromValues'];

export declare const Rest: unknown;
export declare const Crypto: unknown;
export declare const MsgPack: unknown;
export declare const RealtimePresence: unknown;
export declare const WebSocketTransport: unknown;
export declare const XHRPolling: unknown;
export declare const XHRStreaming: unknown;
export declare const XHRRequest: unknown;
export declare const FetchRequest: unknown;
export declare const MessageInteractions: unknown;

export interface ModulesMap {
Rest?: typeof Rest;
Crypto?: typeof Crypto;
MsgPack?: typeof MsgPack;
RealtimePresence?: typeof RealtimePresence;
WebSocketTransport?: typeof WebSocketTransport;
XHRPolling?: typeof XHRPolling;
XHRStreaming?: typeof XHRStreaming;
XHRRequest?: typeof XHRRequest;
FetchRequest?: typeof FetchRequest;
MessageInteractions?: typeof MessageInteractions;
}

export declare class BaseRest extends Types.Rest {
constructor(options: Types.ClientOptions, modules: ModulesMap);
}

export declare class BaseRealtime extends Types.Realtime {
constructor(options: Types.ClientOptions, modules: ModulesMap);
}

export { Types };
23 changes: 14 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@
"url": "https://github.com/ably/ably-js/issues",
"email": "[email protected]"
},
"main": "./build/ably-node.js",
"typings": "./ably.d.ts",
"react-native": {
"./build/ably-node.js": "./build/ably-reactnative.js"
},
"browser": {
"./build/ably-node.js": "./build/ably.js"
"exports": {
".": {
"node": "./build/ably-node.js",
"react-native": "./build/ably-reactnative.js",
"default": "./build/ably.js"
},
"./modules": {
"types": "./modules.d.ts",
"default": "./build/modules/index.js"
}
},
"typings": "./ably.d.ts",
"files": [
"build/**",
"ably.d.ts",
"modules.d.ts",
"resources/**",
"src/**",
"react/**"
Expand Down Expand Up @@ -123,8 +128,8 @@
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"prepare": "npm run build",
"format": "prettier --write --ignore-path .gitignore --ignore-path .prettierignore src test ably.d.ts webpack.config.js Gruntfile.js scripts/*.js docs/chrome-mv3.md",
"format:check": "prettier --check --ignore-path .gitignore --ignore-path .prettierignore src test ably.d.ts webpack.config.js Gruntfile.js scripts/*.js",
"format": "prettier --write --ignore-path .gitignore --ignore-path .prettierignore src test ably.d.ts modules.d.ts webpack.config.js Gruntfile.js scripts/*.js docs/chrome-mv3.md",
"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",
"sourcemap:noencryption": "source-map-explorer build/ably.noencryption.min.js",
"modulereport": "node scripts/moduleReport.js",
Expand Down
11 changes: 8 additions & 3 deletions test/package/browser/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ This directory is intended to be used for testing the following aspects of the a
- that its exports are correctly configured and provide access to ably-js’s functionality
- that its TypeScript typings are correctly configured and can be successfully used from a TypeScript-based app that imports the package

The file `src/index.ts` imports the ably-js package and exports a function which briefly exercises its functionality.
It contains two files, each of which import ably-js in different manners, and which export a function which briefly exercises its functionality:

- `src/index-default.ts` imports the default ably-js package (`import { Realtime } from 'ably'`).
- `src/index-modules.ts` imports the tree-shakable ably-js package (`import { BaseRealtime, WebSocketTransport, FetchRequest } from 'ably/modules'`).

## Why is `ably` not in `package.json`?

Expand All @@ -15,6 +18,8 @@ The `ably` dependency gets added when we run the repository’s `test:package` p

This directory exposes three package scripts that are to be used for testing:

- `build`: Uses esbuild to create a bundle containing `src/index.ts` and ably-js.
- `test`: Using the bundle created by `build`, tests that the code that exercises ably-js’s functionality is working correctly in a browser.
- `build`: Uses esbuild to create:
1. a bundle containing `src/index-default.ts` and ably-js;
2. a bundle containing `src/index-modules.ts` and ably-js.
- `test`: Using the bundles created by `build`, tests that the code that exercises ably-js’s functionality is working correctly in a browser.
- `typecheck`: Type-checks the code that imports ably-js.
2 changes: 1 addition & 1 deletion test/package/browser/template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"build": "esbuild --bundle src/index.ts --outdir=dist",
"build": "esbuild --bundle src/index-default.ts --outdir=dist && esbuild --bundle src/index-modules.ts --outdir=dist",
"typecheck": "tsc -noEmit",
"test-support:server": "ts-node server/server.ts",
"test": "playwright test",
Expand Down
11 changes: 11 additions & 0 deletions test/package/browser/template/server/resources/index-default.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Ably NPM package test (default export)</title>
</head>
<body>
<script type="text/javascript" src="index-default.js"></script>
<script type="text/javascript" src="runTest.js"></script>
</body>
</html>
11 changes: 11 additions & 0 deletions test/package/browser/template/server/resources/index-modules.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Ably NPM package test (tree-shakable export)</title>
</head>
<body>
<script type="text/javascript" src="index-modules.js"></script>
<script type="text/javascript" src="runTest.js"></script>
</body>
</html>
21 changes: 0 additions & 21 deletions test/package/browser/template/server/resources/index.html

This file was deleted.

9 changes: 9 additions & 0 deletions test/package/browser/template/server/resources/runTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(async () => {
try {
await testAblyPackage();
onResult(null);
} catch (error) {
console.log('Caught error', error);
onResult(error);
}
})();
5 changes: 4 additions & 1 deletion test/package/browser/template/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import path from 'node:path';

async function startWebServer(listenPort: number) {
const server = express();
server.get('/', (req, res) => res.send('OK'));
server.use(express.static(path.join(__dirname, '/resources')));
server.use('/index.js', express.static(path.join(__dirname, '..', 'dist', 'index.js')));
for (const filename of ['index-default.js', 'index-modules.js']) {
server.use(`/${filename}`, express.static(path.join(__dirname, '..', 'dist', filename)));
}

server.listen(listenPort);
}
Expand Down
Loading

0 comments on commit a47c23d

Please sign in to comment.