Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DTP-1118] Apply ConnectionDetails.maxMessageSize limit to state messages #1963

Open
wants to merge 4 commits into
base: DTP-1138/map-counter-creates
Choose a base branch
from

Conversation

VeskeR
Copy link
Contributor

@VeskeR VeskeR commented Jan 27, 2025

Message size calculation algorithm is based on https://github.com/ably/realtime/blob/d0557b715a5dbace6dce456b14127eea75d6f019/go/realtime/lib/ablyrpc/state.go#L452, with changes:

  • object ids are not added to the size (DTP-1136), except when MAP_SET operation is referencing another object (TBD)
  • createOp in the object messages also contributes to the message size (TBD)

Message size calculation tests are based on https://github.com/ably/realtime/blob/d0557b715a5dbace6dce456b14127eea75d6f019/nodejs/realtime/test/unit/encoding.ts#L1055

Resolves DTP-1118

Summary by CodeRabbit

Release Notes

  • New Features

    • Enhanced message size validation across multiple components
    • Expanded support for calculating message sizes with new utility methods
  • Improvements

    • Improved error message formatting using template literals
    • Added more flexible data type handling for size calculations
  • Bug Fixes

    • Implemented stricter checks to prevent oversized message transmission
  • Tests

    • Added comprehensive test cases for message size constraints and state message handling
    • Introduced new utility functions to improve error handling in tests

Copy link

coderabbitai bot commented Jan 27, 2025

Warning

Rate limit exceeded

@VeskeR has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 19 minutes and 33 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 908ddae and 187473e.

📒 Files selected for processing (8)
  • src/common/lib/client/defaultrealtime.ts (2 hunks)
  • src/common/lib/client/realtimechannel.ts (1 hunks)
  • src/common/lib/client/restchannel.ts (1 hunks)
  • src/common/lib/util/utils.ts (2 hunks)
  • src/plugins/liveobjects/liveobjects.ts (1 hunks)
  • src/plugins/liveobjects/statemessage.ts (1 hunks)
  • test/common/modules/private_api_recorder.js (2 hunks)
  • test/realtime/live_objects.test.js (16 hunks)

Walkthrough

This pull request introduces enhancements to message size handling and encoding across multiple files in the Ably Realtime library. The changes focus on implementing message size validation, particularly for state messages, by adding new methods to calculate message sizes, updating error handling, and extending utility functions to support more data types. The modifications aim to improve message transmission reliability by enforcing size limits and providing more detailed error information.

Changes

File Change Summary
src/common/lib/client/defaultrealtime.ts Added _MessageEncoding static property
src/common/lib/client/realtimechannel.ts Updated error message to use template literals
src/common/lib/client/restchannel.ts Updated error message to use template literals
src/common/lib/util/utils.ts Extended dataSizeBytes() to support more input types
src/plugins/liveobjects/liveobjects.ts Added message size validation for state messages
src/plugins/liveobjects/statemessage.ts Added getMessageSize() and supporting size calculation methods
test/common/modules/private_api_recorder.js Updated private API identifiers
test/realtime/live_objects.test.js Added new test cases for message size and state message handling

Assessment against linked issues

Objective Addressed Explanation
Ensure ConnectionDetails maxMessageSize limit is applied to state messages (DTP-1118)
Align StateMessage GetSize implementation (DTP-1136)

Possibly related PRs

Suggested reviewers

  • mschristensen
  • lawrence-forooghian

Poem

🐰 Bytes dancing, limits tight,
Messages sized with rabbit's might,
Encoding secrets, size constraints clear,
A realtime symphony, performance dear!
Code hops forward, message wisdom bright 🚀


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@VeskeR VeskeR requested a review from mschristensen January 27, 2025 09:26
@github-actions github-actions bot temporarily deployed to staging/pull/1963/features January 27, 2025 09:27 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1963/bundle-report January 27, 2025 09:27 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1963/typedoc January 27, 2025 09:27 Inactive
@VeskeR
Copy link
Contributor Author

VeskeR commented Jan 27, 2025

@mschristensen Please let me know if these two changes are in-line with your idea for DTP-1136:

except when MAP_SET operation is referencing another object (TBD)
createOp in the object messages also contributes to the message size (TBD)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (10)
test/realtime/live_objects.test.js (7)

75-76: State message creator function

stateMessageFromValues() is a neat helper to generate StateMessage instances. If used extensively, consider adding validations (e.g., type checks) for the input values object to preempt unexpected runtime errors.


458-459: Repeated buffer instrumentation calls

Repeated calls to the private API for buffer operations confirm consistent usage. Consider grouping them if code duplication occurs frequently in extended tests.


919-919: Context object destructuring repeated

This pattern is repeated in multiple scenarios. Consider a single utility function that returns the context to reduce repetition if more logic is needed in the future.


946-947: Instrumenting buffer equality checks

Consistent with other instrumentation lines. Keep an eye on performance impact if large amounts of data are tested in the future.


2073-2074: Ensuring up-to-date references when tests run

After buffering operations, code references the root object again. Consider verifying that references to local variables do not become stale if concurrency is introduced.


2302-2302: Expanding test coverage on edge cases

Line 2302 indicates we set up primitive data in the root map. Consider adding extreme edge cases (e.g., zero-length strings, extremely large strings, null bytes) to solidify coverage.


2661-2662: Multiple calls to BufferUtils

Frequent usage is probably expected in these tests. If performance becomes an issue, caching or grouping tests might help.

src/common/lib/util/utils.ts (1)

282-298: LGTM! Consider adding JSDoc comments.

The function has been correctly extended to handle additional data types with appropriate size calculations. The error message is clear and descriptive.

Consider adding JSDoc comments to document the function's purpose, parameters, return value, and the size calculation rules for each data type:

+/**
+ * Calculates the size in bytes of the input data.
+ * @param data The input data to calculate the size for
+ * @returns The size in bytes:
+ *   - For strings: Uses platform-specific string byte size calculation
+ *   - For numbers: Returns 8 bytes
+ *   - For booleans: Returns 1 byte
+ *   - For Buffer/ArrayBuffer: Returns the buffer length
+ * @throws Error if the input type is not supported
+ */
 export function dataSizeBytes(data: string | number | boolean | Buffer | ArrayBuffer): number {
src/plugins/liveobjects/statemessage.ts (2)

453-464: LGTM! Consider using reduce for clarity.

The method correctly calculates the map size, but could be more concise using reduce.

Consider using reduce for a more functional approach:

 private _getStateMapSize(map: StateMap): number {
-  let size = 0;
-
-  Object.entries(map.entries ?? {}).forEach(([key, entry]) => {
-    size += key?.length ?? 0;
-    if (entry) {
-      size += this._getStateMapEntrySize(entry);
-    }
-  });
-
-  return size;
+  return Object.entries(map.entries ?? {}).reduce(
+    (size, [key, entry]) => 
+      size + (key?.length ?? 0) + (entry ? this._getStateMapEntrySize(entry) : 0),
+    0
+  );
 }

474-482: LGTM! Consider simplifying the implementation.

The method correctly calculates the entry size, but could be more concise.

Consider simplifying the implementation:

 private _getStateMapEntrySize(entry: StateMapEntry): number {
-  let size = 0;
-
-  if (entry.data) {
-    size += this._getStateDataSize(entry.data);
-  }
-
-  return size;
+  return entry.data ? this._getStateDataSize(entry.data) : 0;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a33d69 and f48f2af.

📒 Files selected for processing (8)
  • src/common/lib/client/defaultrealtime.ts (2 hunks)
  • src/common/lib/client/realtimechannel.ts (1 hunks)
  • src/common/lib/client/restchannel.ts (1 hunks)
  • src/common/lib/util/utils.ts (1 hunks)
  • src/plugins/liveobjects/liveobjects.ts (1 hunks)
  • src/plugins/liveobjects/statemessage.ts (1 hunks)
  • test/common/modules/private_api_recorder.js (2 hunks)
  • test/realtime/live_objects.test.js (16 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/common/lib/client/realtimechannel.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: test-browser (webkit)
  • GitHub Check: test-node (20.x)
  • GitHub Check: test-browser (firefox)
  • GitHub Check: test-node (18.x)
  • GitHub Check: test-browser (chromium)
  • GitHub Check: test-node (16.x)
🔇 Additional comments (29)
test/realtime/live_objects.test.js (14)

12-13: Use of Ably Realtime internal properties

Using Ably.Realtime.Utils and Ably.Realtime._MessageEncoding aligns with the new message encoding logic. However, _MessageEncoding is underscored, hinting it's an internal property. If it's stable and intentionally exposed, consider renaming or documenting so it’s clear it's officially supported.


63-73: Ensure robust error validation in async tests

Replacing the boolean flag with savedError clarifies error handling. This block might benefit from validating the entire error object, e.g., verifying error code, stack trace, or additional fields where relevant.


449-450: Buffer decoding instrumentation

Recording private API calls for buffer decoding fosters better test coverage and debugging capabilities. No further changes suggested.


703-703: Clarify scenario context parameter

Destructuring { root, liveObjectsHelper, channelName, helper } helps keep code readable. Ensure the context is well-documented so new team members understand each property’s usage and scope in these test scenarios.


744-745: Helper methods for buffer comparisons

Similar to lines 449-450, these calls are consistent. No issues found.


1804-1804: Buffered operation application in tests

Line 1804 logs the test arrangement for applying buffered operations after STATE_SYNC. The approach is clear, and the test is thorough.


1833-1834: Private API usage for buffer checks

No concerns. Maintains consistency with prior lines.


2034-2034: Manage scenario context meticulously

When injecting additional state operations, always confirm the channel state is valid, especially under concurrency scenarios or potential race conditions.


2306-2306: Verifying base64 decode calls

Coordinates well with line 2302’s setup. No immediate issues.


2315-2316: Further instrumentation on buffer operations

Across the file, instrumentation is consistent. This approach is suitable for diagnosing issues quickly without cluttering production code.


2628-2628: Creating maps with initial values

This code sets the stage for thorough testing of LiveMap objects. Consider logging or validating final states to catch any silent logic regressions.


2634-2634: Handling base64-encoded values upon map creation

No issues. If additional encodings are introduced, ensure they’re handled consistently across the entire codebase.


3567-3614: Test for enforcing max message size

Great scenario verifying that an error is thrown when exceeding connectionDetails.maxMessageSize. This ensures state message publish adheres to the size limit. The error code 40009 is well-defined. Consider adding boundary tests at exactly the size limit to confirm off-by-one correctness.


3616-3789: Comprehensive tests for message size calculations

This block thoroughly validates data size measurement across different object types (maps, counters, booleans, etc.). The coverage is high. For maintainability, ensure this remains in sync if the underlying size calculation logic evolves.

src/common/lib/client/defaultrealtime.ts (2)

22-22: Introducing MessageEncoding import

The newly imported MessageEncoding expands the encoding handling. Confirm that no existing logic depends on older encoding constants, and ensure this seamlessly integrates with _MessageEncoding.


75-75: New static property: _MessageEncoding

Exporting _MessageEncoding for external use is helpful for testing. If it’s truly part of the public API, consider removing the underscore prefix; otherwise, it’s best to clarify through documentation that this is intended for internal use/testing only.

test/common/modules/private_api_recorder.js (3)

19-19: Tracking LiveObject getObjectId

Newly tracking 'call.LiveObject.getObjectId' in the recorder ensures deeper introspection of object IDs. No concerns unless performance overhead arises from many calls.


29-31: StateMessage-related instrumentation

Adding 'call.StateMessage.encode', 'call.StateMessage.fromValues', and 'call.StateMessage.getMessageSize' extends your private API recording. This ensures test coverage for newly introduced logic in StateMessage and helps identify usage patterns.


33-33: Expanded coverage for dataSizeBytes

Capturing 'call.Utils.dataSizeBytes' is consistent with the broader instrumentation strategy. No immediate issues found.

src/plugins/liveobjects/liveobjects.ts (1)

226-234: LGTM! Size validation is correctly implemented.

The implementation correctly validates the total size of state messages before publishing:

  1. Retrieves the maximum size limit from client options
  2. Calculates total size by summing individual message sizes
  3. Throws a descriptive error if the limit is exceeded
src/plugins/liveobjects/statemessage.ts (8)

401-416: LGTM! Message size calculation is comprehensive.

The method correctly calculates the total message size by:

  1. Summing the sizes of all relevant fields
  2. Handling optional fields safely
  3. Delegating complex calculations to specialized methods

418-435: LGTM! State operation size calculation is well-structured.

The method correctly calculates the operation size by delegating to specialized methods for each field type.


437-451: LGTM! State object size calculation is well-structured.

The method correctly calculates the object size by delegating to specialized methods for each field type.


466-472: LGTM! Counter size calculation is correct.

The method correctly returns:

  • 8 bytes for a defined count (number size)
  • 0 bytes for undefined/null count

484-494: LGTM! Map operation size calculation is correct.

The method correctly calculates the size by:

  1. Including the key length (if present)
  2. Adding the data size (if present)

496-502: LGTM! Counter operation size calculation is correct.

The method correctly returns:

  • 8 bytes for a defined amount (number size)
  • 0 bytes for undefined/null amount

504-515: LGTM! State data size calculation is correct.

The method correctly calculates the size by:

  1. Including the objectId size using dataSizeBytes
  2. Adding the value size using specialized method

517-519: LGTM! State value size calculation is correct.

The method correctly uses the enhanced dataSizeBytes utility which supports all StateValue types.

src/common/lib/client/restchannel.ts (1)

120-120: LGTM! Error message readability improved.

The error message has been updated to use template literals, making it more readable while maintaining the same information.

@VeskeR VeskeR force-pushed the DTP-1118/apply-maxMessageSize-for-state branch from f48f2af to 908ddae Compare January 27, 2025 09:50
@github-actions github-actions bot temporarily deployed to staging/pull/1963/bundle-report January 27, 2025 09:50 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1963/features January 27, 2025 09:50 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1963/typedoc January 27, 2025 09:50 Inactive
@VeskeR
Copy link
Contributor Author

VeskeR commented Jan 27, 2025

Removed except when MAP_SET operation is referencing another object as discussed on the stand-up (it is now also not included in calculation) in https://github.com/ably/ably-js/compare/f48f2af001f548b0e331c8b709c8883d9cfdc132..908ddaeb839a9866684a40a032d1c654ae03969e

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/plugins/liveobjects/statemessage.ts (3)

400-416: Consider using _utils.dataSizeBytes() for consistency when measuring clientId and extras

Currently, clientId is measured with this.clientId?.length, and extras is measured via JSON.stringify(this.extras).length. Meanwhile, other fields (e.g., map data, counters) use _utils.dataSizeBytes(...). For coherence and to correctly handle multi-byte characters and buffer data, consider measuring these fields using _utils.dataSizeBytes(...) as well.


466-472: Validate fixed 8-byte assumption for counters

_getStateCounterSize returns 8 if count != null. This implies all counter values, regardless of magnitude, are stored as 8 bytes (often a float64). Confirm that this is consistent with how counters are serialized elsewhere in the system.


484-494: Handle references in _getStateMapOpSize

This method calculates the size of mapOp.key and, when present, the data’s value. If mapOp.data?.objectId is set, confirm it should be excluded or included. The PR suggests possibly counting object references in some contexts.

test/realtime/live_objects.test.js (1)

449-450: Instrumentation calls to record private API usage

These lines log calls to BufferUtils functions and other internals. Ensure these logging statements don’t impair performance or clutter logs in production.

Also applies to: 458-459, 946-947, 1833-1834, 2073-2074, 2302-2306, 2315-2316

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f48f2af and 908ddae.

📒 Files selected for processing (5)
  • src/common/lib/client/defaultrealtime.ts (2 hunks)
  • src/plugins/liveobjects/liveobjects.ts (1 hunks)
  • src/plugins/liveobjects/statemessage.ts (1 hunks)
  • test/common/modules/private_api_recorder.js (2 hunks)
  • test/realtime/live_objects.test.js (16 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/common/lib/client/defaultrealtime.ts
  • test/common/modules/private_api_recorder.js
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: test-browser (webkit)
  • GitHub Check: test-browser (firefox)
  • GitHub Check: test-node (20.x)
  • GitHub Check: test-node (18.x)
  • GitHub Check: test-browser (chromium)
  • GitHub Check: test-node (16.x)
🔇 Additional comments (13)
src/plugins/liveobjects/statemessage.ts (6)

418-435: Verify omission of objectId, nonce, and initial values in _getStateOperationSize

The current size calculation omits operation.objectId, nonce, initialValue, and initialValueEncoding. The PR objectives mention excluding object IDs in most cases except potentially for references (e.g., MAP_SET referencing another object). Confirm that these fields are indeed intentionally omitted or if you need to incorporate them under specific conditions.


437-451: Check for consistency when omitting objectId in _getStateObjectSize

_getStateObjectSize includes map, counter, and createOp fields but does not account for obj.objectId. According to the PR discussion, object IDs are generally excluded from the size calculation, which may be correct. Ensure this is fully aligned with the updated design.


453-464: Confirm ignoring semantics in _getStateMapSize

_getStateMapSize skips map.semantics. If this property was discussed for exclusion from size calculations, that’s fine; just verify it aligns with the requirements from [DTP-1136].


474-482: Tombstone consideration in _getStateMapEntrySize

_getStateMapEntrySize only accounts for entry.data. If tombstone or timeserial fields must be included in the size count, ensure that skipping them is intentional.


496-502: Fixed 8-byte assumption for _getStateCounterOpSize

Similar to _getStateCounterSize, this returns a fixed 8 bytes for any amount. Confirm that the numeric type is consistently stored as an 8-byte float or if you need more nuanced handling (e.g., big integer scenarios).


504-516: Confirm ignoring objectId in _getStateDataSize

_getStateDataSize focuses on data.value, calling _getStateValueSize(value). If data.objectId is present, it’s not counted. Verify this aligns with the latest decision to exclude object IDs except in certain MAP_SET references.

src/plugins/liveobjects/liveobjects.ts (1)

226-234: Verify undefined or zero edge cases when enforcing maxMessageSize

The code throws an error if size > maxMessageSize, assuming maxMessageSize is a positive number. If this._client.options.maxMessageSize is missing or zero, a publish may fail unexpectedly (e.g., size > undefined is false, but size > 0 is always true if size is positive). Consider short-circuiting if this value is not set or is invalid.

test/realtime/live_objects.test.js (6)

12-13: Imports for Utils and MessageEncoding look good

The references to Ably.Realtime.Utils and Ably.Realtime._MessageEncoding are well-placed.


63-73: Enhanced error-check helper

This new expectRejectedWith(fn, errorStr) utility improves test readability by returning the captured error. Consider expanding it to validate error codes or properties if needed.


75-76: Convenient factory for StateMessage

stateMessageFromValues neatly wraps StateMessage.fromValues. This should simplify test logic.


3568-3571: Coverage references in code comments

References to @spec TO3l8 and @spec RSL1i are helpful for traceability of specification coverage. No issues spotted.


3572-3614: Test for connectionDetails.maxMessageSize limit

This test thoroughly validates that exceeding the configured limit yields the correct error code and message. Good job ensuring the code 40009 is checked.


3616-3837: Comprehensive tests for StateMessage.getMessageSize

The scenario-driven approach covers various data types, verifying that getMessageSize ignores object IDs and handles strings, buffers, booleans, and numbers. This is excellent coverage.

@VeskeR VeskeR force-pushed the DTP-1118/apply-maxMessageSize-for-state branch from 908ddae to 7206725 Compare January 30, 2025 02:52
@github-actions github-actions bot temporarily deployed to staging/pull/1963/features January 30, 2025 02:53 Inactive
…d more generic Buffer type

This is in preparation for message size calculation for StateMessages,
which can have numbers and booleans as user provided data [1].
Also should use platform agnostic `Bufferlike` type provided by the
Platform module to have better support for node.js/browser buffers.

[1] https://ably.atlassian.net/browse/DTP-1118
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant