Skip to content

Add Ably LiveObjects - Merge integration/liveobjects into main #2007

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

Merged
merged 223 commits into from
May 8, 2025

Conversation

VeskeR
Copy link
Contributor

@VeskeR VeskeR commented Apr 16, 2025

Merge integration/liveobjects into main branch to add Objects plugin to the library (implementation of LiveObjects feature).

All changes were reviewed in the underlying PRs and this PR mainly needs a review from the Ecosystems team regarding the plugin structure, public README and documentation, and library changes in general:

Summary by CodeRabbit

  • New Features

    • Introduced the Objects plugin, enabling real-time collaborative LiveMap and LiveCounter objects on channels.
    • Added support for batch operations, object lifecycle events, and atomic updates to live objects.
    • Enhanced type safety and autocompletion for LiveObjects with TypeScript typings.
    • Expanded SDK exports to include the Objects plugin for modular and UMD builds.
  • Documentation

    • Added comprehensive documentation covering LiveObjects usage, configuration, API reference, and type integration.
  • Bug Fixes

    • Improved error handling and validation for object operations and channel state.
  • Tests

    • Added extensive tests for LiveObjects, including browser and node scenarios, and updated test helpers for broader protocol/transport coverage.
  • Chores

    • Updated build, test, and deployment scripts to support the new Objects plugin and ensure correct CDN distribution.

VeskeR and others added 30 commits October 2, 2024 03:56
Base code, tests and build setup for new LiveObjects plugin. Adds a new
`.liveObjects` property for RealtimeChannel.

Plugin setup is based on Web Push plugin PR [1], and CDN setup for Push
plugin PR [2].

Resolves DTP-947

[1] #1775
[2] #1861
Decoupling between underlying data and client-held reference will be
achieved using `_dataRef` property on ancestor LiveObject class.

Resolves DTP-953
[DTP-947] Expose LiveObjects as a plugin
[DTP-952, DTP-953] Add base implementation for abstract LiveObject, concrete LiveMap/LiveCounter classes
[DTP-960, DTP-961] Add Live Objects access API
…eserializedWithDependencies`

This is in preparation for following changes where `fromDeserialized`
function would require a LiveObjectsPlugin to create StateMessage
classes. We can't include LiveObjectsPlugin in the core library, so this
plugin will need to be provided by the tests.
This is in preparation for adding decoding messages to StateMessage.
StateMessage has multiple data/encoding entries and requires a more
generic function to decode its data, instead of a previous `decode`
function that expected data and encoding to be present on a Message
class
STATE_SYNC message processing in `RealtimeChannel.processMessage` is
based on the process for `PRESENCE` message.

Resolves DTP-950
Plugins can't import EventEmitter class directly as that would increase
the bundle size of a plugin
@VeskeR
Copy link
Contributor Author

VeskeR commented Apr 30, 2025

Note before merging:
remove feature flag for liveobjects feature on apps from tests once realtime enabled it by default

UPDATE: removed in 671243c

VeskeR added 2 commits May 7, 2025 14:46
Leaf values for objects are now stored in type keys on ObjectData object
instead of a single `value` key with a union type.

The new approach caused an issue with comet transports (only
implemented in ably-js) as comet transports do not support msgpack
protocol. We can't rely on the usual `client.options.useBinaryProtocol`
option to identify the protocol used, as comet transport changes the
selected protocol in its implementation. Instead we get the current
active transport object and its format.

Resolves PUB-1666
@github-actions github-actions bot temporarily deployed to staging/pull/2007/bundle-report May 7, 2025 15:09 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2007/features May 7, 2025 15:09 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/2007/typedoc May 7, 2025 15:09 Inactive
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: 1

♻️ Duplicate comments (4)
src/plugins/objects/objectmessage.ts (1)

294-295: ⚠️ Potential issue

encodeInitialValue() still fires ObjectMessage.encode() without awaiting

ObjectMessage.encode() returns a Promise, but the call remains un-awaited, so the asynchronous encoding chain may still be running while the message is being serialised for the wire. This re-introduces the data-race described in the earlier review (see past comment 283-301).
Consider awaiting the promise (or making the surrounding function sync if possible).

-ObjectMessage.encode(msg, client.MessageEncoding);
+await ObjectMessage.encode(msg, client.MessageEncoding);
src/plugins/objects/livemap.ts (3)

560-614: 🛠️ Refactor suggestion

_updateFromDataDiff() still emits empty updates + unnecessary continues

Earlier feedback pointed out that returning { update: {} } when nothing changed causes superfluous notifyUpdated() calls. The logic remains unchanged.
Additionally, the continue at line 609 is redundant once update.update[typedKey] = 'updated' has executed.

Please:

  1. Return a { noop: true } marker when update.update is empty.
  2. Drop the extra continue statements flagged by Biome.
🧰 Tools
🪛 Biome (1.9.4)

[error] 609-609: Unnecessary continue statement

Unsafe fix: Delete the unnecessary continue statement

(lint/correctness/noUnnecessaryContinue)


823-837: ⚠️ Potential issue

Null-guard still missing on entry.data

entry.data can be undefined for tombstoned entries, yet the code dereferences it unconditionally (entry.data.objectId, etc.).
This will crash the sync loop on a perfectly valid tombstone message.

Please apply the earlier guard (see past comment “Missing data null-guard …”).


887-903: ⚠️ Potential issue

Entries pointing to unknown objects should count as tombstoned

_isMapEntryTombstoned() still treats a missing referenced object as not tombstoned, leading to phantom keys in entries()/keys()/values() and an incorrect size().
The previous review suggested treating both missing and tombstoned referenced objects as tombstoned.

-    if ('objectId' in data) {
-      const refObject = this._objects.getPool().get(data.objectId);
-
-      if (refObject?.isTombstoned()) {
-        return true;
-      }
-    }
+    if ('objectId' in data) {
+      const refObject = this._objects.getPool().get(data.objectId);
+      if (!refObject || refObject.isTombstoned()) {
+        return true;
+      }
+    }
🧹 Nitpick comments (1)
src/plugins/objects/objectmessage.ts (1)

483-485: toJSON() protocol detection is fragile

Relying on arguments.length to infer the protocol couples the implementation to current (undocumented) behaviour of JSON/MsgPack serializers.
A safer option is to pass the format explicitly from the caller or cache the client’s useBinaryProtocol flag on construction.

This is a nice-to-have, but it will prevent future regressions if the serialiser implementation changes.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between c47738c and 540bf1e.

📒 Files selected for processing (6)
  • ably.d.ts (8 hunks)
  • src/common/lib/client/realtimechannel.ts (12 hunks)
  • src/common/lib/transport/connectionmanager.ts (2 hunks)
  • src/plugins/objects/livemap.ts (1 hunks)
  • src/plugins/objects/objectmessage.ts (1 hunks)
  • test/common/modules/private_api_recorder.js (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • test/common/modules/private_api_recorder.js
  • src/common/lib/transport/connectionmanager.ts
  • src/common/lib/client/realtimechannel.ts
  • ably.d.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/plugins/objects/livemap.ts

[error] 609-609: Unnecessary continue statement

Unsafe fix: Delete the unnecessary continue statement

(lint/correctness/noUnnecessaryContinue)

⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: test-browser (webkit)
  • GitHub Check: test-node (20.x)
  • GitHub Check: test-node (18.x)
  • GitHub Check: test-browser (firefox)
  • GitHub Check: test-node (16.x)
  • GitHub Check: test-browser (chromium)

VeskeR added 6 commits May 8, 2025 14:16
See Simon's comment [1]. The `channel` property should not be expected
in the wire protocol for object messages, just like it isn't present in
a message or presencemessage.

[1] ably/specification#279 (comment)
`MapEntry.data` will not be set for tombstone properties in a map, this
commit ensures we handle it correctly.
@VeskeR VeskeR mentioned this pull request May 8, 2025
VeskeR added 3 commits May 8, 2025 17:48
…with HAS_OBJECTS=false

Object references must be kept the same whenever possible so that
end-user keeps the correct reference and its subscriptions to the object
whenever resynchronization happens, see [1].

On channel DETACHED or FAILED only the objects data should be removed,
and no update events should be emitted, see [2].

[1] https://ably.atlassian.net/wiki/spaces/LOB/pages/3382738945/LODR-022+Realtime+Client+read-only+internal+spec#7.-Decoupling-of-the-underlying-state-data-and-LiveObject-class-instances
[2] https://ably.atlassian.net/wiki/spaces/LOB/pages/3784933378/LODR-032+Realtime+Client+behavior+under+channel+states
@VeskeR VeskeR merged commit 37b5815 into main May 8, 2025
11 of 14 checks passed
@VeskeR VeskeR deleted the integration/liveobjects branch May 8, 2025 17:19
@VeskeR VeskeR changed the title Merge integration/liveobjects into main Add Ably LiveObjects - Merge integration/liveobjects into main May 8, 2025
VeskeR added a commit to ably/docs that referenced this pull request May 9, 2025
Decided to rename to `AblyObjectsTypes` to avoid using a generic name
like `ObjectsTypes` in a global namespace, see [1]

[1] ably/ably-js#2007 (comment)
VeskeR added a commit to ably/docs that referenced this pull request May 9, 2025
Decided to rename to `AblyObjectsTypes` to avoid using a generic name
like `ObjectsTypes` in a global namespace, see [1]

[1] ably/ably-js#2007 (comment)
VeskeR added a commit to ably/docs that referenced this pull request May 12, 2025
Decided to rename to `AblyObjectsTypes` to avoid using a generic name
like `ObjectsTypes` in a global namespace, see [1]

[1] ably/ably-js#2007 (comment)
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.

2 participants