-
Notifications
You must be signed in to change notification settings - Fork 42
docs: add path-based LiveObjects API proposal #1190
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
base: main
Are you sure you want to change the base?
Conversation
WalkthroughA new comprehensive documentation file is added that specifies a planned path-based API architecture for LiveObjects in Java/Kotlin and Python. The specification details typed path objects, deferred resolution, subscriptions, and includes usage examples, design decisions, and migration guidance from the existing API. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In `@liveobjects/PATH_BASED_API_JAVA_PYTHON.md`:
- Around line 88-99: The fenced code block that begins with "Value (all types
that can be stored)" is missing a language tag (MD040); update the opening
triple-backtick to include a language identifier such as "text" or "console"
(e.g., ```text) so the block is language-tagged and markdownlint passes, leaving
the block content unchanged.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds a new design/proposal document describing a planned path-based LiveObjects API for Java/Kotlin and Python, including core concepts, proposed interfaces, examples, and migration notes.
Changes:
- Introduces a comprehensive implementation plan + proposed type system and interfaces for a path-based LO API.
- Adds end-to-end usage examples (creation, mutation, subscriptions, compact snapshots, instance API).
- Documents migration guidance and open design questions/next steps.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| **Java:** | ||
| ```java | ||
| LiveMapPathObject myObject = channel.getObject().get(); // The singular object |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Java examples use both channel.getObject().get() and channel.object().get() to retrieve the root object; the document should pick one canonical API shape and use it consistently (and align Python/Java naming where intended).
| LiveMapPathObject myObject = channel.getObject().get(); // The singular object | |
| LiveMapPathObject myObject = channel.object().get(); // The singular object |
| PathObject get(String key); | ||
| PathObject at(String path); | ||
| LiveMap instance() throws AblyException; |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LiveMapPathObject.instance() is declared as returning a non-null LiveMap, but the later example checks if (playerInstance != null). Clarify whether instance() can return null (and reflect that in the signature, e.g., @Nullable/Optional) or remove the null-check and describe the error behavior.
| // Update primitive value | ||
| myObject.at("user.name").asLiveMap().set( | ||
| "name", | ||
| Primitive.create("Bob") | ||
| ); | ||
|
|
||
| // Or navigate to parent and set | ||
| LiveMapPathObject user = myObject.get("user").asLiveMap(); |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mutation example navigates to "user.name" (a primitive path) and then casts to LiveMap before calling set("name", ...), which is internally inconsistent. To update a primitive, the example should operate on the parent map path ("user") or the API should define a direct primitive setter for PathObject/StringPathObject.
| // Update primitive value | |
| myObject.at("user.name").asLiveMap().set( | |
| "name", | |
| Primitive.create("Bob") | |
| ); | |
| // Or navigate to parent and set | |
| LiveMapPathObject user = myObject.get("user").asLiveMap(); | |
| // Update primitive value via parent map path | |
| myObject.at("user").asLiveMap().set( | |
| "name", | |
| Primitive.create("Bob") | |
| ); | |
| // Or fetch parent map object and then set | |
| LiveMapPathObject user = myObject.at("user").asLiveMap(); |
| # Update player position | ||
| move_options = MessageOptions( | ||
| id=f"move-{time.time()}", | ||
| extras={"action": "move", "timestamp": time.time()} | ||
| ) |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Python complete example uses time.time() when building move_options, but time is not imported in the snippet. Add import time (or avoid time usage) so the example runs as written.
| ```java | ||
| // Path to nested value | ||
| StringPathObject colour = myObject.at("shape.colour").asStringPrimitive(); | ||
| String value = colour.value(); // "red" |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The document uses both colour and color as field/key names across examples (shape.colour vs later "color"). Pick one spelling for keys/paths and use it consistently to avoid implying different schema fields.
| PathObject get(String key); | ||
| PathObject at(String path); | ||
| LiveMap instance() throws AblyException; | ||
|
|
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LiveMapPathObject.set/remove take a required MessageOptions options parameter here, but most Java examples call set(...)/remove(...) without providing options. Either document overloads/default options (e.g., options nullable or a MessageOptions.none()), or update the examples so they compile against the proposed signatures.
| // Convenience overloads using default message options | |
| void set(String key, Value value) throws AblyException; | |
| void remove(String key) throws AblyException; | |
| // Full-control overloads with explicit message options |
| Double value() throws AblyException; | ||
| void increment(Number amount, MessageOptions options) throws AblyException; |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LiveCounterPathObject.increment/decrement require MessageOptions options here, but later examples call increment(1) / decrement(25) with no options. Align the method signatures and examples (overload vs optional/default options) so the sample code is implementable as written.
| Double value() throws AblyException; | |
| void increment(Number amount, MessageOptions options) throws AblyException; | |
| Double value() throws AblyException; | |
| void increment(Number amount) throws AblyException; | |
| void increment(Number amount, MessageOptions options) throws AblyException; | |
| void decrement(Number amount) throws AblyException; |
| }, SubscriptionOptions.depth(2)); | ||
|
|
||
| // Update game state | ||
| game.at("state").asLiveMap().set("state", Primitive.create("started")); |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
game.at("state") refers to a string primitive (see initialization game.set("state", Primitive.create(...))), so casting it to asLiveMap() and setting a "state" key is inconsistent. This should update the root key (e.g., game.set("state", ...)) or operate on the correct parent map path.
| game.at("state").asLiveMap().set("state", Primitive.create("started")); | |
| game.set("state", Primitive.create("started")); |
| ) | ||
|
|
||
| # Update game state | ||
| game.at("state").as_live_map().set("state", Primitive.create("started")) |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Python example updates state via game.at("state").as_live_map().set(...), but state was initialized as a primitive string. Adjust the example to set the root key directly or change the data model so state is a map if that’s the intention.
| game.at("state").as_live_map().set("state", Primitive.create("started")) | |
| game.at("state").as_primitive().set(Primitive.create("started")) |
New API for LO
Summary by CodeRabbit
Documentation