From 4f65355f55c7b60e3a5ede63dc5783e1fd16d9ab Mon Sep 17 00:00:00 2001 From: Andy Ford Date: Mon, 9 Dec 2024 15:20:51 +0000 Subject: [PATCH 1/5] chore: 0.3.0 release prep This change: - Updates the package version around the codebase - Updates the CHANGELOG - Updates the upcoming feature list in the README - Adds UPGRADING.md to provide more guidance for upgrading --- CHANGELOG.md | 31 +++++++++++++ README.md | 2 +- UPGRADING.md | 103 +++++++++++++++++++++++++++++++++++++++++ cspell.json | 3 +- demo/package-lock.json | 12 ++--- demo/package.json | 2 +- package-lock.json | 12 ++--- package.json | 4 +- src/core/version.ts | 2 +- 9 files changed, 153 insertions(+), 18 deletions(-) create mode 100644 UPGRADING.md diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb526e8..7af4c75f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ This contains only the most important and/or user-facing changes; for a full changelog, see the commit history. +## [0.3.0](https://github.com/ably/ably-chat-js/tree/0.3.0) (2025-01-06) + +### Breaking Changes + +Please see `UPGRADING.md` for full guidance on upgrading from version 0.2.1 and before. + +- The default typing timeout has now been reduced to 5 seconds. [#361](https://github.com/ably/ably-chat-js/pull/361) +- Room and Connection status types have been renamed. [#382](https://github.com/ably/ably-chat-js/pull/382) +- Renamed the `timeserial` field on the `Message` type to `serial`. Messages may now be compared for global order by string comparison of this field. +- `Rooms.get` is now asynchronous and returns a `Promise` that will resolve once any `release` operations on the room are complete. [#387](https://github.com/ably/ably-chat-js/pull/387). +- The `Room.channel` property is now an instance of `Ably.RealtimeChannel`, rather than a `Promise`. [#387](https://github.com/ably/ably-chat-js/pull/387) +- In React, accessing the room via `useRoom`, or properties of the room via other hooks, now returns `ValueType | undefined`. Once the room's promise is resolved (see above), this will update to the actual value. [#387](https://github.com/ably/ably-chat-js/pull/387) +- The default Room status is now `Initialized`. The `Initializing` status is retained for use in React when the room has not yet been resolved. [#387](https://github.com/ably/ably-chat-js/pull/387) +- The `direction` argument to message history has been replaced by `orderBy`, which uses a new enum `OrderBy` with values `OldestFirst` and `NewestFirst`. Its behavior is identical to `direction: forwards | backwards`. + +### New Features + +- Added new fields to Messages to support editing and deleting. [#362](https://github.com/ably/ably-chat-js/pull/362) +- Added the ability to delete messages in the chat. [#365](https://github.com/ably/ably-chat-js/pull/365) +- Added the ability to edit messages in the chat. [#378](https://github.com/ably/ably-chat-js/pull/378) + +### Fixed Bugs + +- The Room will now transition immediately to `released` if `release` is called whilst its status is `Initialized`. [#400](https://github.com/ably/ably-chat-js/pull/400) +- When paginating messages (e.g. via `getPreviousMessages`) the objects returned by successive pages will now fully implement the `Message` interface. Previously they were simple JSON objects after the first page. [#403](https://github.com/ably/ably-chat-js/pull/403). +- Fixed a bug whereby a room may get stuck in the `Suspended` status after network issues. [#409](https://github.com/ably/ably-chat-js/pull/409) + +### Other Changes + +- `ably-chat` is no longer a reserved key on Message and Reaction metadata/headers. [#374](https://github.com/ably/ably-chat-js/pull/374) + ## [0.2.1](https://github.com/ably/ably-chat-js/tree/0.2.1) (2024-09-18) - Fixed a bug that can lead to unhandled promise rejections and error logs when a room is released prior to initialization, particularly in React [#352](https://github.com/ably/ably-chat-js/pull/352) diff --git a/README.md b/README.md index 4cbace1e..344d0040 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Ably Chat is a set of purpose-built APIs for a host of chat features enabling you to create 1:1, 1:Many, Many:1 and Many:Many chat rooms for any scale. It is designed to meet a wide range of chat use cases, such as livestreams, in-game communication, customer support, or social interactions in SaaS products. Built on [Ably's](https://ably.com/) core service, it abstracts complex details to enable efficient chat architectures. > [!IMPORTANT] -> This SDK is currently under development. If you are interested in being an early adopter and providing feedback then you can [sign up to the private beta](https://forms.gle/vB2kXhCXrTQpzHLu5) and are welcome to [provide us with feedback](https://forms.gle/mBw9M53NYuCBLFpMA). Coming soon: chat moderation, editing and deleting messages. +> This SDK is currently under development. If you are interested in being an early adopter and providing feedback then you can [sign up to the private beta](https://forms.gle/vB2kXhCXrTQpzHLu5) and are welcome to [provide us with feedback](https://forms.gle/mBw9M53NYuCBLFpMA). Coming soon: chat moderation, simplified granular permissions and message reactions. Get started using the [📚 documentation](https://ably.com/docs/products/chat) and [🚀check out the live demo](https://ably-livestream-chat-demo.vercel.app/), or [📘 browse the API reference](https://sdk.ably.com/builds/ably/ably-chat-js/main/typedoc/). diff --git a/UPGRADING.md b/UPGRADING.md new file mode 100644 index 00000000..3adef2c6 --- /dev/null +++ b/UPGRADING.md @@ -0,0 +1,103 @@ +# Upgrade Guide + +This guide provides detailed instructions on how to upgrade between major versions of the Chat SDK. + +## <= 0.2.1 to 0.3.0 + +### Room and Connection Status Types + +**Expected Impact: High** + +These have been renamed for greater clarity. The key changes are that the `RoomStatus` and `ConnectionStatus` identifiers are now enumerations of the possible statuses, whereas before they were an interface name. Furthermore, the current status is now presented as the property `status`, rather than the property `current`. + +| Action | Before | After | +| -------------------------------------------------------- | ---------------------------------------------------- | ------------------------------------------------- | +| Get the “current” status of a room | `room.status.current` | `room.status` | +| Get the “current” error related to the room status | `room.status.error` | `room.error` | +| Subscribe to room status updates | `room.status.onChange` | `room.onStatusChange` | +| Remove all room status subscribers | `room.status.offAll` | `room.offAllStatusChange` | +| Compare the room status to some value | `roomStatus === RoomLifecycle.Attached` | `roomStatus === RoomStatus.Attached` | +| Get the “current” connection status | `chat.connection.status.current` | `chat.connection.status` | +| Get the “current” error related to the connection status | `chat.connection.status.error` | `chat.connection.error` | +| Subscribe to connection status updates | `chat.connection.status.onChange` | `chat.connection.onStatusChange` | +| Remove all connection status subscribers | `chat.connection.status.offAll` | `chat.connection.offAllStatusChange` | +| Compare the connection status to some value | `connectionStatus === ConnectionLifecycle.Connected` | `connectionStatus === ConnectionStatus.Connected` | + +### Creating a Room Is Now Asynchronous + +**Expected Impact: High** + +The `Rooms.get` method is now asynchronous, returning a `Promise` which will resolve when the `Room` object is ready. If a `release` operation is in progress for the room, it shall wait for this +process to complete before resolving. + +Before: + +```ts +const room = chat.rooms.get('basketball-stream', { typing: { timeoutMs: 500 } }); +``` + +After: + +```ts +const room = await chat.rooms.get('basketball-stream', { typing: { timeoutMs: 500 } }); +``` + +As a result, the `channel` property of various features (e.g. `messages.channel`) now returns an `Ably.RealtimeChannel` rather than a `Promise`. + +### Default Room Status + +**Expected Impact: Medium** + +The default status of a newly created room is now `Initialized`. It was previously `Initializing`. `Initializing` is still used in React when the room is not yet resolved. + +### Message Timeserial Field Rename + +**Expected Impact: Medium** + +This field has been renamed, so all occurrences of `message.timeserial` should now be changed to `message.serial`. + +If you wish to, messages may now be compared for global ordering by comparing their `serial` strings. + +```ts +const message1First = message1.serial < message2.serial; +``` + +The `before` and `after` methods are still available and will be kept for simplicity and autocomplete convenience. + +### History Direction Parameter Removed + +**Expected Impact: Medium** + +The `direction` argument to message history has been replaced by `orderBy`, which uses a new enum `OrderBy` with values `OldestFirst` and `NewestFirst`. Its behavior is identical to `direction: forwards | backwards`. + +Before: + +```ts +const historicalMessages = await room.messages.get({ direction: 'backwards', limit: 50 }); +``` + +After: + +```ts +const historicalMessages = await room.messages.get({ orderBy: OrderBy.NewestFirst, limit: 50 }); +``` + +### React Hooks Room Property Values + +**Expected Impact: Low** + +In previous versions of React Hooks, properties of the Room (e.g. `room.messages`) and the room itself were returned as `ValueType`. These are now returned as `ValueType | undefined`. + +The value will be updated once the internal call to `Rooms.get()` has resolved. + +### Typing Timeout + +**Expected Impact: Low** + +The default is now 5 seconds. + +If you wish to retain the old behavior, change your `RoomOptions` when creating a `Room` as follows: + +```ts +const room = await chat.rooms.get('basketball-stream', { typing: { timeoutMs: 500 } }); +``` diff --git a/cspell.json b/cspell.json index afd79dfe..0b7383d5 100644 --- a/cspell.json +++ b/cspell.json @@ -14,7 +14,8 @@ "Failable", "livestreams", "livestream", - "clonedeep" + "clonedeep", + "timeserial" ], // This will ignore anything that's formatted like a lexicographically ordered timeserial "ignoreRegExpList": ["/\\d{14}-\\d{3}@.*/"], diff --git a/demo/package-lock.json b/demo/package-lock.json index 1aac292e..1741222a 100644 --- a/demo/package-lock.json +++ b/demo/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.0", "dependencies": { "@ably/chat": "file:..", - "ably": "ably/ably-js#mutable-messages-with-submodule-test", + "ably": "^2.6.0", "clsx": "^2.1.1", "nanoid": "^5.0.9", "react": "^18.3.1", @@ -35,7 +35,7 @@ }, "..": { "name": "@ably/chat", - "version": "0.2.1", + "version": "0.3.0", "license": "Apache-2.0", "dependencies": { "async-mutex": "^0.5.0", @@ -85,7 +85,7 @@ "@rollup/rollup-linux-x64-gnu": "^4.18" }, "peerDependencies": { - "ably": "ably/ably-js#mutable-messages-with-submodule-test" + "ably": "^2.6.0" } }, "node_modules/@ably/chat": { @@ -1698,9 +1698,9 @@ } }, "node_modules/ably": { - "version": "2.5.0", - "resolved": "git+ssh://git@github.com/ably/ably-js.git#c5c99987920327cadf144fa3f7652c8f4672c6cd", - "license": "Apache-2.0", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/ably/-/ably-2.6.0.tgz", + "integrity": "sha512-WmvV8tFgnnGU/nuuQ0I7lWTGSgwimM5H4EqLTX23PUBOVBgfmnMJ2MBT46BmcmrrFF9pmeSV11PNULwum80uAQ==", "dependencies": { "@ably/msgpack-js": "^0.4.0", "fastestsmallesttextencoderdecoder": "^1.0.22", diff --git a/demo/package.json b/demo/package.json index 2aa73a91..fd9118b5 100644 --- a/demo/package.json +++ b/demo/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@ably/chat": "file:..", - "ably": "ably/ably-js#mutable-messages-with-submodule-test", + "ably": "^2.6.0", "clsx": "^2.1.1", "nanoid": "^5.0.9", "react": "^18.3.1", diff --git a/package-lock.json b/package-lock.json index 36337c0d..11367ca0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ably/chat", - "version": "0.2.1", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ably/chat", - "version": "0.2.1", + "version": "0.3.0", "license": "Apache-2.0", "dependencies": { "async-mutex": "^0.5.0", @@ -56,7 +56,7 @@ "@rollup/rollup-linux-x64-gnu": "^4.18" }, "peerDependencies": { - "ably": "ably/ably-js#mutable-messages-with-submodule-test" + "ably": "^2.6.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3136,9 +3136,9 @@ "dev": true }, "node_modules/ably": { - "version": "2.5.0", - "resolved": "git+ssh://git@github.com/ably/ably-js.git#c5c99987920327cadf144fa3f7652c8f4672c6cd", - "license": "Apache-2.0", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/ably/-/ably-2.6.0.tgz", + "integrity": "sha512-WmvV8tFgnnGU/nuuQ0I7lWTGSgwimM5H4EqLTX23PUBOVBgfmnMJ2MBT46BmcmrrFF9pmeSV11PNULwum80uAQ==", "peer": true, "dependencies": { "@ably/msgpack-js": "^0.4.0", diff --git a/package.json b/package.json index ec16a214..96e60186 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ably/chat", - "version": "0.2.1", + "version": "0.3.0", "description": "Ably Chat is a set of purpose-built APIs for a host of chat features enabling you to create 1:1, 1:Many, Many:1 and Many:Many chat rooms for any scale. It is designed to meet a wide range of chat use cases, such as livestreams, in-game communication, customer support, or social interactions in SaaS products.", "type": "module", "main": "dist/chat/ably-chat.umd.cjs", @@ -63,7 +63,7 @@ }, "homepage": "https://github.com/ably/ably-chat-js#readme", "peerDependencies": { - "ably": "ably/ably-js#mutable-messages-with-submodule-test" + "ably": "^2.6.0" }, "devDependencies": { "@eslint/compat": "^1.2.0", diff --git a/src/core/version.ts b/src/core/version.ts index 9dba6320..265f1886 100644 --- a/src/core/version.ts +++ b/src/core/version.ts @@ -1,4 +1,4 @@ // Update this when you release a new version -export const VERSION = '0.2.1'; +export const VERSION = '0.3.0'; export const CHANNEL_OPTIONS_AGENT_STRING = `chat-js/${VERSION}`; export const DEFAULT_CHANNEL_OPTIONS = { params: { agent: CHANNEL_OPTIONS_AGENT_STRING } }; From 285ea867a9105c004c1921f939abd09e55793bf6 Mon Sep 17 00:00:00 2001 From: Andy Ford Date: Tue, 10 Dec 2024 10:38:30 +0000 Subject: [PATCH 2/5] docs: update README for edit/delete - Add some missing changes from action*() to version*() - Generally update wording for clarity --- README.md | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 344d0040..602ed6b0 100644 --- a/README.md +++ b/README.md @@ -283,8 +283,7 @@ const message = await room.messages.send({ ### Updating messages -To update an existing message, call `update` on the `room.messages` property, with the original message you want to update, -the updated fields, and optional operation details to provide extra context for the update. +To update an existing message, call `update` on the `room.messages` property, with the original message you want to update, the updated fields, and optional operation details to provide extra context for the update. The optional operation details are: @@ -309,15 +308,15 @@ const updatedMessage = await room.messages.update( A `Message` that was updated will have values for `updatedAt` and `updatedBy`, and `isUpdated()` will return `true`. -Note that if you delete an updated message, it is no longer considered _updated_. Only the last operation takes effect. +Note that if you delete an updated message, it is no longer considered _updated_. Only the latest operation takes effect. #### Handling updates in realtime -Updated messages received from realtime have the `action` parameter set to `ChatMessageActions.MessageUpdate`, and the event received has the `type` set to `MessageEvents.Updated`. Updated messages are full copies of the message, meaning that all that is needed to keep a state or UI up to date is to replace the old message with the received one. +Updated messages received from the server have the `action` parameter set to `ChatMessageActions.MessageUpdate`, and the event received has the `type` set to `MessageEvents.Updated`. Updated messages are full copies of the message, meaning that all that is needed to keep a state or UI up to date is to replace the old message with the received one. -In rare occasions updates might arrive over realtime out of order. To keep a correct state, compare the `version` lexicographically (string compare). Alternatively, the `Message` interface provides convenience methods to compare two instances of the same base message to determine which version is newer: `versionBefore()`, `versionAfter()`, and `versionEqual()`. +On rare occasions updates might arrive from the server out of order (in terms of the global order in which these events occur). An example of this is when messages are transiting between regions, and latencies between nearby regions is lower than those further away. To deterministically determine whether an update should supersede the current version, simply compare the `version` strings using the standard `<` and `>` operators. Alternatively, the `Message` interface provides convenience methods to compare two instances of the same base message to determine which version is newer: `versionBefore()`, `versionAfter()`, and `versionEqual()`. -The same out-of-order situation can happen between updates received over realtime and HTTP responses. In the situation where two concurrent updates happen, both might be received via realtime before the HTTP response of the first one arrives. Always compare the message `version` to determine which instance of a `Message` is newer. +The same out-of-order situation can happen between updates received over realtime and HTTP responses (e.g. when updating a message). In the situation where two concurrent updates happen, both might be received via realtime before the HTTP response of the first one arrives. Always compare the message `version` to determine which instance of a `Message` is newer. Example for handling updates: @@ -373,22 +372,13 @@ const { unsubscribe } = room.messages.subscribe((msg) => console.log(msg)); #### Handling deletes in realtime -Deletion messages received from realtime have the `action` parameter set to `ChatMessageActions.MessageDelete`, and the event received has the `type` set to `MessageEvents.Deleted`. -Just like `updates`, `deletion` messages are also full copies of the message, meaning that all that is needed to keep a state or UI up to date is to replace the old message with the received one. +Deletion messages received from the server have the `action` parameter set to `ChatMessageActions.MessageDelete`, and the event received has the `type` set to `MessageEvents.Deleted`. Similar to `updates`, `deletion` messages are also full copies of the message, meaning that all that is needed to keep a state or UI up to date is to replace the old message with the received one. -On rare occasions, deletes and updates might arrive over realtime out of order. -That is to say, should two concurrent actions happen in disparate regions, you will likely receive the action processed in the region closest to you first. -When the second action arrives, you will need to determine the order of these actions; -this is done by comparing their respective global orders, determined by the `version` field of the message. +On rare occasions, deletes and updates might arrive over realtime out of order. Again, should two concurrent actions happen in disparate regions, you will likely receive the action processed in the region closest to you first, for example. -To keep a correct state, the `Message` interface provides methods to compare two instances of the same base message to determine which action is newer:`actionBefore()`, `actionAfter()`, and `actionEqual()`. +When the second action arrives, you will need to determine the order of these actions; this is done deterministically by comparing the `version` field of the messages, using the standard `<` and `>` operators. For convenience, the `Message` interface provides methods to compare two instances of the same base message to determine which action is newer:`versionBefore()`, `versionAfter()`, and `versionEqual()`. -The same out-of-order situation can happen between deletions received over realtime and HTTP responses. - -In the situation where two concurrent deletes happen, both might be received via realtime before the HTTP response of the first one arrives. - -In short, always use `actionAfter()`, -`actionBefore()`, or `actionEqual()` to determine the global ordering of two `Message` actions. +The same out-of-order situation can happen between deletions received over realtime and HTTP responses, whereby both might be received via realtime before the HTTP response of the first one arrives. Example for handling deletes: @@ -400,7 +390,7 @@ room.messages.subscribe((event) => { case MessageEvents.Deleted: { const serial = event.message.serial; const index = messages.findIndex((m) => m.serial === serial); - if (index !== -1 && messages[index].actionBefore(event.message)) { + if (index !== -1 && messages[index].versionBefore(event.message)) { messages[index] = event.message; } break; From 1e2626e3fb960a0b1dafae83b8fd4b408779631a Mon Sep 17 00:00:00 2001 From: Steven Lindsay Date: Tue, 10 Dec 2024 17:47:12 +0000 Subject: [PATCH 3/5] Refactor: Fix typos and improve clarity in some comments Fixed a few typos across multiple files. Corrected the typedocs for getPreviousMessages in the use-messages.ts file, they now correctly state the direction of fetched messages is newest to oldest. --- src/core/chat-api.ts | 2 +- src/core/headers.ts | 4 ++-- src/core/id.ts | 2 +- src/core/message.ts | 4 ++-- src/core/messages.ts | 8 ++++---- src/core/metadata.ts | 2 +- src/react/helper/room-promise.ts | 4 ++-- src/react/hooks/use-messages.ts | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/core/chat-api.ts b/src/core/chat-api.ts index fd043170..99350598 100644 --- a/src/core/chat-api.ts +++ b/src/core/chat-api.ts @@ -61,7 +61,7 @@ export type DeleteMessageResponse = MessageOperationResponse; interface UpdateMessageParams { /** - * Message data to update. All fields are updated and if omitted they are + * Message data to update. All fields are updated and, if omitted, they are * set to empty. */ message: { diff --git a/src/core/headers.ts b/src/core/headers.ts index 75511584..876886c7 100644 --- a/src/core/headers.ts +++ b/src/core/headers.ts @@ -3,12 +3,12 @@ * * The headers are a flat key-value map and are sent as part of the realtime * message's extras inside the `headers` property. They can serve similar - * purposes as Metadata but as opposed to Metadata they are read by Ably and + * purposes as Metadata, but as opposed to Metadata they are read by Ably and * can be used for features such as * [subscription filters](https://faqs.ably.com/subscription-filters). * * Do not use the headers for authoritative information. There is no - * server-side validation. When reading the headers treat them like user + * server-side validation. When reading the headers, treat them like user * input. * */ diff --git a/src/core/id.ts b/src/core/id.ts index f4394f37..ab7d7ee0 100644 --- a/src/core/id.ts +++ b/src/core/id.ts @@ -1,5 +1,5 @@ /** - * Generates a random string that can be used as an identifier, for instance in identifying specific room + * Generates a random string that can be used as an identifier, for instance, in identifying specific room * objects. * * @returns A random string that can be used as an identifier. diff --git a/src/core/message.ts b/src/core/message.ts index 745830d7..beccf979 100644 --- a/src/core/message.ts +++ b/src/core/message.ts @@ -92,7 +92,7 @@ export interface Message { * This value is always set. If there are no headers, this is an empty object. * * Do not use the headers for authoritative information. There is no server-side - * validation. When reading the headers treat them like user input. + * validation. When reading the headers, treat them like user input. */ readonly headers: MessageHeaders; @@ -112,7 +112,7 @@ export interface Message { readonly timestamp: Date; /** - * The details of the operation that updated the message. This is only set for update and delete actions. It contains + * The details of the operation that modified the message. This is only set for update and delete actions. It contains * information about the operation: the clientId of the user who performed the operation, a description, and metadata. */ readonly operation?: Operation; diff --git a/src/core/messages.ts b/src/core/messages.ts index a58d8ce0..9662d816 100644 --- a/src/core/messages.ts +++ b/src/core/messages.ts @@ -133,7 +133,7 @@ export interface SendMessageParams { * emojis, etc. * * Do not use metadata for authoritative information. There is no server-side - * validation. When reading the metadata treat it like user input. + * validation. When reading the metadata, treat it like user input. * */ metadata?: MessageMetadata; @@ -143,12 +143,12 @@ export interface SendMessageParams { * * The headers are a flat key-value map and are sent as part of the realtime * message's extras inside the `headers` property. They can serve similar - * purposes as the metadata but they are read by Ably and can be used for + * purposes as the metadata, but they are read by Ably and can be used for * features such as * [subscription filters](https://faqs.ably.com/subscription-filters). * * Do not use the headers for authoritative information. There is no - * server-side validation. When reading the headers treat them like user + * server-side validation. When reading the headers, treat them like user * input. * */ @@ -219,7 +219,7 @@ export interface Messages extends EmitsDiscontinuities { subscribe(listener: MessageListener): MessageSubscriptionResponse; /** - * Unsubscribe all listeners from new messages in from chat room. + * Unsubscribe all listeners from new messages in the chat room. */ unsubscribeAll(): void; diff --git a/src/core/metadata.ts b/src/core/metadata.ts index 75e11f2a..d01365cb 100644 --- a/src/core/metadata.ts +++ b/src/core/metadata.ts @@ -6,7 +6,7 @@ * emojis, etc. * * Do not use metadata for authoritative information. There is no server-side - * validation. When reading the metadata treat it like user input. + * validation. When reading the metadata, treat it like user input. * */ export type Metadata = Record; diff --git a/src/react/helper/room-promise.ts b/src/react/helper/room-promise.ts index eed262ae..8c9e0294 100644 --- a/src/react/helper/room-promise.ts +++ b/src/react/helper/room-promise.ts @@ -69,10 +69,10 @@ class DefaultRoomPromise implements RoomPromise { /** * Wait for the room promise to resolve, then execute the onResolve callback, storing its response as an unmount function. - * If the component is unmounted before the promise resolves,then this will do nothing. + * If the component is unmounted before the promise resolves, then this will do nothing. * * @param promise The promise that resolves to a Room instance. - * @returns A promise that we simply resolve when its done. + * @returns A promise that we simply resolve when it's done. */ async mount(promise: Promise): Promise { this._logger.debug('DefaultRoomPromise(); mount', { roomId: this._roomId }); diff --git a/src/react/hooks/use-messages.ts b/src/react/hooks/use-messages.ts index c9645648..c0428842 100644 --- a/src/react/hooks/use-messages.ts +++ b/src/react/hooks/use-messages.ts @@ -57,7 +57,7 @@ export interface UseMessagesResponse extends ChatStatusResponse { * * This method is available only if a {@link MessageListener} has been provided in the {@link UseMessagesParams}. * Calling will return a promise that resolves to a paginated response of the previous messages received in the room, - * up until the listener was attached, in the oldest to newest order. + * up until the listener was attached, in newest-to-oldest order. * * It is advised to call this method after any discontinuity event; to retrieve messages that may have been missed * before the listener was re-attached. From 9eb0b090c8051cb218a853d451e8081fcdb50d5c Mon Sep 17 00:00:00 2001 From: Steven Lindsay Date: Tue, 10 Dec 2024 17:48:19 +0000 Subject: [PATCH 4/5] Refactor: Remove export from unused type The type was exported but not used anywhere. --- src/core/chat-api.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/chat-api.ts b/src/core/chat-api.ts index 99350598..488faea6 100644 --- a/src/core/chat-api.ts +++ b/src/core/chat-api.ts @@ -55,9 +55,9 @@ interface MessageOperationResponse { timestamp: number; } -export type UpdateMessageResponse = MessageOperationResponse; +type UpdateMessageResponse = MessageOperationResponse; -export type DeleteMessageResponse = MessageOperationResponse; +type DeleteMessageResponse = MessageOperationResponse; interface UpdateMessageParams { /** From 1a957f52134b8a1f0c73a3c012ee2959206a32b9 Mon Sep 17 00:00:00 2001 From: Andy Ford Date: Thu, 19 Dec 2024 11:05:42 +0000 Subject: [PATCH 5/5] react-native: add alternative installation for react native To avoid having to change module resolution settings in Expo, this change introduces a pseudo-package `@ably/chat-react-native` which can then be used instead of `@ably/chat/react`. Also includes README/CONTRIBUTING changes as required. --- CONTRIBUTING.md | 7 ++++--- package.json | 3 ++- react-native/package.json | 6 ++++++ src/react/README.md | 20 +++++++++++++++++++- 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 react-native/package.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 511333dd..8196415b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,9 +19,10 @@ - The second number represents a minor release, which lets users know new functionality or features have been added. - The third number represents a patch release, which represents bug-fixes and may be used when no action should be required from users. 2. The commit should update `package.json` and `package-lock.json`. Running `npm install` after changing `package.json` will update `package-lock.json`. - 3. The commit should also update `version.ts` to set the agent headers. - 4. Update the `CHANGELOG.md` with any customer-affecting changes since the last release. - 5. Update the README.md for any references to the new version. + 3. The commit should also update `react-native/package.json` to the appropriate version. + 4. The commit should also update `version.ts` to set the agent headers. + 5. Update the `CHANGELOG.md` with any customer-affecting changes since the last release. + 6. Update the README.md for any references to the new version. 3. Merge the commit into main. 4. Tag a release using [Github releases](https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository#creating-a-release). The version needs to match the one from the commit. Use the "Generate release notes" button to add changelog notes and update as required. diff --git a/package.json b/package.json index 96e60186..41af4d63 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,8 @@ }, "files": [ "dist/**", - "src/**" + "src/**", + "react-native/**" ], "repository": { "type": "git", diff --git a/react-native/package.json b/react-native/package.json new file mode 100644 index 00000000..551b1de9 --- /dev/null +++ b/react-native/package.json @@ -0,0 +1,6 @@ +{ + "name": "@ably/chat-react-native", + "version": "0.3.0", + "main": "../chat/dist/react/ably-chat-react.umd.cjs", + "types": "../chat/dist/react/index.d.ts" +} diff --git a/src/react/README.md b/src/react/README.md index b9add4ab..4dae579b 100644 --- a/src/react/README.md +++ b/src/react/README.md @@ -9,7 +9,9 @@ If you're using **React Native**, you may need to perform extra steps to use the The React package is exported as an ESM module `@ably/chat/react`, making use of the `exports` field in `package.json`. The Metro bundler used by React Native does not by default utilize this field, leading to imports not being found. -To use Chat with React Native, first set the `type` field of your React Native project to `module` and update your `tsconfig.json` +### Option 1: Enable Package Exports + +React Native has started to support the `exports` field of `package.json`. To use Chat with React Native in this way, first set the `type` field of your React Native project to `module` and update your `tsconfig.json` to set `"moduleResolution": "Bundler"`. Finally, include the `unstable_enablePackageExports` field in your `metro.config.cjs`, which will enable `exports` resolution. For example: @@ -27,6 +29,22 @@ module.exports = { }; ``` +### Option 2: Use Pseudo-package + +If the above isn't an option for you, you can instead use the `@ably/chat-react-native` pseudo-package with the Metro/Expo defaults. + +To do this, add the following to your `package.json`: + +```json +{ + "dependencies": { + "@ably/chat-react-native": "file:./node_modules/@ably/chat/react-native" + } +} +``` + +Then, replace any imports of `@ably/chat/react` with `@ably/chat-react-native`. + ## ChatClientProvider This provider is used to provide the `ChatClient` instance to all child components in your React component tree.