Skip to content

docs(liveobjects): migrate Swift documentation to the path-based API - #3515

Open
sacOO7 wants to merge 3 commits into
mainfrom
feature/path-based-liveobjects-docs-swift
Open

docs(liveobjects): migrate Swift documentation to the path-based API#3515
sacOO7 wants to merge 3 commits into
mainfrom
feature/path-based-liveobjects-docs-swift

Conversation

@sacOO7

@sacOO7 sacOO7 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates the Swift LiveObjects documentation from the deprecated callback-based API to the new path-based typed API, bringing the Swift content in line with the JavaScript and Java path-based docs (#3462).

The old Swift surface (channel.objects, getRoot(), createMap()/createCounter(), live LiveMap/LiveCounter handles, .on(event: .deleted)) is replaced throughout with the current API shipped in ably-cocoa's AblyLiveObjects product:

Old (removed) New
channel.objectsRealtimeObjects channel.object (extension property, any RealtimeObject)
try await channel.objects.getRoot() try await channel.object.get()any LiveMapPathObject
objects.createMap() / createCounter() LiveMap.create(entries:) / LiveCounter.create(initialCount:) blueprints, assigned via set(key:value:)
Live LiveMap / LiveCounter handles path layer (LiveMapPathObject/LiveCounterPathObject) + instance layer (LiveMapInstance/LiveCounterInstance)
counter.on(event: .deleted) deletion observed via an Instance subscription (operation.action == .objectDelete)

What changed

Getting started

  • quickstart/swift.mdx — full rewrite converging on the JS/Java quickstart structure: channel.object.get(), plugin registration via clientOptions.plugins = [.liveObjects: Plugin.self], channel modes, and the path-based create → subscribe → update flow. Install is SPM only (the CocoaPods Ably pod does not package the LiveObjects sources); platform minimums iOS 14 / macOS 11 / tvOS 14, Xcode 16.3+. Removes the manual attach() step (attach is implicit via get()).

Concepts

  • concepts/objects.mdx, operations.mdx — Channel object / PathObject / Instance sections opened to Swift; the old Root-object, aliasing/cyclic-reference, and stale-reference regions removed (not expressible in the path model); ObjectMessage/ObjectOperation/ObjectData tables extended to Swift (ObjectOperationAction with seven lowerCamelCase cases, ObjectsMapSemantics.lww, Data for binary).
  • concepts/path-object.mdx, instance.mdx — Swift added to every code block (25 and 19 fences respectively), plus Swift Type inference sections. The path layer keeps the never-throwing-casts story (wrong reads → nil, wrong writes → local ARTErrorInfo 92007 before anything is sent); the instance layer diverges deliberately: Instance is a Swift enum, so discrimination is an exhaustive switch/if case and Java's throwing-cast mismatch path cannot occur. The #typing, #read-values and #get-a-compact-object anchors are preserved under the Swift toggle.

Object types

  • map.mdx, counter.mdx — path-based Swift fences added beside the JS/Java ones in every section; the entire old-API Swift tails deleted (duplicate #create/#set/#remove/#size/#value anchors collapse to one definition each; retired Swift-only anchors verified referrer-free).

Feature pages

  • lifecycle.mdx — sync events via zero-arg on(event:) returning StatusSubscription (per-token off(), no offAll()); deletion detection rewritten as an Instance subscription, source-verified: objectDelete is delivered only through Instance subscriptions, which auto-unsubscribe after one final notification.
  • typing.mdx — Swift Type inference section (#type-inference, #path-layer-casts, #instance-layer-casts, #get-type); TS content stays JS-gated.
  • inband-objects.mdx — Swift fences for the [meta]objects Pub/Sub examples; fixed three link toggles that previously excluded Swift (including the plugin link that pointed at the JavaScript quickstart).
  • batch.mdx, storage.mdx, index.mdx, synchronization.mdx — Swift toggles aligned with the Java treatment (channel object wording, factual batch note).

API reference & supporting config

  • api/realtime-sdk/channels.mdx — Swift joins the #### object accessor (extension property wording); the old Swift-only #### objects entry removed.
  • data/nav/liveobjects.ts — Swift SDK reference link repointed to the ably-cocoa-hosted DocC build (with a TODO to verify once published); label renamed "Swift plugin" → "Swift SDK".
  • data/languages/languageData.ts — Swift LiveObjects version 0.41.2 (the plugin now ships inside ably-cocoa).

Asynchronous API guidance

Swift's surface has no blocking variants and no .join() analogue, so the Java CompletableFuture guidance is replaced by a simpler story, stated once in the quickstart and echoed by a short aside on the mutation-heavy pages:

  • Mutations and get() suspend — call them with try await. Reads, navigation and casts are synchronous and local.
  • Reads never throw for a type mismatch or absent path (they return nil/empty); they throw only when the channel is detached/failed or the object_subscribe mode is missing.
  • Subscription callbacks fire on ably-cocoa's callback queue (main queue by default), so UI updates need no queue hop.
  • Alongside closure-based subscribe, the docs show the for await event in try object.events() AsyncStream form; terminating the stream unsubscribes automatically.

Guarantees & validation

  • JavaScript and Java content is unchanged except <If lang> gate widenings — verified against the diff: every removed line is old Swift-only content, an in-place Swift fence rewrite, or a gate-value change.
  • Every Swift snippet (95 fences) compiles against the real AblyLiveObjects product (throwaway SwiftPM harness on the ably-cocoa checkout, Swift 6.1).
  • Full Gatsby production build passes; all language gates balanced; one definition per anchor id per page.
  • Section-by-section parity audit against the Java rendering: identical skeleton (headings, anchors, asides, tables), with the only content divergences being those forced by the API (enum-based Instance layer, single asPrimitive() cast, type() naming, async model).
  • The retired #root-object and channels#objects anchors have zero remaining referrers repo-wide.

Features not expressible in Swift (documented as such, not fabricated)

JS/Java feature Swift treatment
batch() Not supported — each mutation publishes individually and is atomic on its own
compact() Swift documents compactJson() only
Per-primitive casts (asString(), asNumber(), …) Single asPrimitive() returning the Primitive enum, pattern-matched by the caller
Throwing Instance casts (92007) Instance is an enum — discrimination is compile-time exhaustive
offAll() Per-token off() only
TS generics Replaced by the typed-throws + enum story

Follow-ups

  • The Swift SDK DocC link in nav/liveobjects.ts carries a TODO — verify it resolves once the ably-cocoa-hosted AblyLiveObjects documentation is published.
  • ably-cocoa carries two stale in-source doc comments worth an upstream fix: the Plugin.swift docstring still shows the removed channel.objects.getRoot() example, and NotImplemented.swift's "skeleton" note predates the completed implementation.

🤖 Generated with Claude Code

Replaces the deprecated callback-based Swift API (channel.objects,
getRoot(), live LiveMap/LiveCounter handles) with the path-based typed
API (channel.object.get(), PathObject/Instance layers) across all
LiveObjects pages, mirroring the Java migration in #3462.

Every Swift snippet compiles against ably-cocoa's AblyLiveObjects
product; JS/Java content is unchanged except language-gate widenings.
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5bd5f66a-a1f1-43ac-9317-5dfa8d571a6d

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sacOO7 sacOO7 added the review-app Create a Heroku review app label Aug 6, 2026
@sacOO7
sacOO7 requested a lite review from Copilot August 6, 2026 13:52
@sacOO7 sacOO7 added review-app Create a Heroku review app and removed review-app Create a Heroku review app labels Aug 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR migrates the Swift LiveObjects documentation from the deprecated callback-based/root-handle API to the new path-based typed API (channel.object.get(), PathObject/Instance layers, blueprints via LiveMap.create / LiveCounter.create), aligning Swift with the existing Java/JavaScript documentation structure.

Changes:

  • Rewrites the Swift quickstart and updates concept pages to document the path layer + instance layer model, including async guidance and subscription patterns.
  • Adds Swift code tabs across LiveMap/LiveCounter/typing/lifecycle/inband objects pages, and removes old Swift-only API sections.
  • Updates supporting configuration (Swift SDK link in nav; LiveObjects Swift version in language data; channel accessor docs).

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
src/pages/docs/liveobjects/typing.mdx Adds Swift “Type inference” section and examples for path- vs instance-layer typing.
src/pages/docs/liveobjects/storage.mdx Updates storage wording to reference the channel object consistently.
src/pages/docs/liveobjects/quickstart/swift.mdx Rewrites Swift quickstart around channel.object.get() and blueprint-based creation/updates/subscriptions.
src/pages/docs/liveobjects/map.mdx Adds Swift path-based examples throughout LiveMap usage and removes old Swift API tail.
src/pages/docs/liveobjects/lifecycle.mdx Updates Swift lifecycle/sync/deletion docs to the path/instance subscription model.
src/pages/docs/liveobjects/index.mdx Updates Swift availability note for batch operations.
src/pages/docs/liveobjects/inband-objects.mdx Adds Swift examples for enabling and consuming inband [meta]objects messages.
src/pages/docs/liveobjects/counter.mdx Adds Swift path-based examples throughout LiveCounter usage and removes old Swift API tail.
src/pages/docs/liveobjects/concepts/synchronization.mdx Aligns Swift sync notes with “awaited mutation” semantics.
src/pages/docs/liveobjects/concepts/path-object.mdx Adds Swift coverage for PathObject navigation, typing, compact snapshots, and subscriptions.
src/pages/docs/liveobjects/concepts/operations.mdx Extends operations docs/tables with Swift types and examples using the new model.
src/pages/docs/liveobjects/concepts/objects.mdx Migrates Swift examples to channel-object/path-based API and updates conceptual sections accordingly.
src/pages/docs/liveobjects/concepts/instance.mdx Adds Swift Instance enum guidance and examples for navigation, typing, compact snapshots, and subscriptions.
src/pages/docs/liveobjects/batch.mdx Updates Swift note to “not supported” with REST API guidance.
src/pages/docs/api/realtime-sdk/channels.mdx Documents Swift channel.object accessor (plugin-provided) and removes old Swift objects entry.
src/data/nav/liveobjects.ts Updates Swift SDK DocC link target/label (with TODO to verify).
src/data/languages/languageData.ts Bumps LiveObjects Swift version displayed in language selector.
Suppressed comments (17)

src/pages/docs/liveobjects/concepts/instance.mdx:105

  • instance() returns an Optional, so this if case needs ? to match .some(...). As written it won’t compile against Instance?.
if case .liveCounter(let visits) = visitsInstance {

src/pages/docs/liveobjects/concepts/instance.mdx:261

  • instance() returns an Optional; the if case needs to handle the Optional result by adding ? (or using .some(...)).
if case .liveMap(let settings) = try rootObject.get(key: "settings").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:203

  • instance() returns an Optional; add ? to pattern-match the Optional result. Otherwise this example won’t compile.
if case .liveCounter(let visits) = try rootObject.get(key: "visits").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:328

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveMap(let user) = try rootObject.get(key: "user").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:337

  • get(key:) returns an Optional when the entry is missing, so this if case needs ? to match the Optional.
    if case .liveCounter(let visits) = try user.get(key: "visits") {

src/pages/docs/liveobjects/concepts/instance.mdx:384

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveMap(let user) = try rootObject.get(key: "user").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:480

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveMap(let settings) = try rootObject.get(key: "settings").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:545

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveMap(let settings) = try rootObject.get(key: "settings").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:716

  • Even though the channel object always exists, instance() is still an Optional-returning API per the rest of the page. This if case should unwrap the Optional with ? to compile.
if case .liveMap(let rootInstance) = try rootObject.instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:766

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveMap(let settings) = try rootObject.get(key: "settings").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:772

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveCounter(let visits) = try rootObject.get(key: "visits").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:841

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveCounter(let visits) = try rootObject.get(key: "visits").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:888

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveCounter(let visits) = try rootObject.get(key: "visits").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:940

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveCounter(let visits) = try rootObject.get(key: "visits").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:1004

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveCounter(let visits) = try rootObject.get(key: "visits").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:1061

  • instance() returns an Optional; add ? so the pattern matches .some(...).
if case .liveMap(let settings) = try rootObject.get(key: "settings").instance() {

src/pages/docs/liveobjects/concepts/instance.mdx:1072

  • get(key:) returns an Optional when the entry is missing, so this if case needs ? to match the Optional.
    if case .liveMap(let preferences) = try settings.get(key: "preferences") {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


// A typed read returns the value, or nil when the path is missing
// or holds a value of a different type
let theme = try rootObject.at(path: "settings.theme").asPrimitive().value()?.stringValue // String or nil

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No change needed here: try covers the whole expression, and the throwing call in this chain is value() (throws(ARTErrorInfo)) — at(path:) is indeed non-throwing navigation. Swift requires marking the expression that contains a throwing call, so the line is correct as written (and compiles in our snippet harness against ably-cocoa).

Comment thread src/pages/docs/liveobjects/map.mdx Outdated
Comment thread src/pages/docs/liveobjects/typing.mdx Outdated
try await visits.increment(amount: 1)

// A read through the wrong inferred type returns nil instead of throwing
let theme = try rootObject.at(path: "settings.theme").asPrimitive().value()?.stringValue // String or nil

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

No change needed here: try covers the whole expression, and the throwing call in this chain is value() (throws(ARTErrorInfo)) — at(path:) is indeed non-throwing navigation. Swift requires marking the expression that contains a throwing call, so the line is correct as written (and compiles in our snippet harness against ably-cocoa).

Comment thread src/pages/docs/liveobjects/map.mdx Outdated
Comment thread src/pages/docs/liveobjects/lifecycle.mdx Outdated
Comment thread src/pages/docs/liveobjects/index.mdx Outdated
Comment thread src/pages/docs/liveobjects/concepts/instance.mdx Outdated
Comment thread src/pages/docs/liveobjects/concepts/instance.mdx Outdated
Comment thread src/pages/docs/liveobjects/concepts/instance.mdx Outdated
sacOO7 added 2 commits August 6, 2026 19:46
rest-api-usage#updating-objects-by-id -> #update-by-id and
rest-api-usage#fetching-objects-list-values -> #fetching-objects;
neither anchor exists on the target page. Found during the Swift
migration link audit; affects all languages.
…amples; grammar fix

Normalize 33 bare enum-case patterns matching Optional scrutinees
(instance()/get(key:) results) to the explicit '...(let x)? =' form,
for consistency with the counter/objects/operations/path-object pages
and to make the optionality visible to readers. The bare form compiled
as written (Swift matches enum-case patterns through Optionals), so
this is a readability/consistency change, not a correctness fix.
Four bare patterns are deliberately kept where the scrutinee is
non-optional (if-let-unwrapped values and event.object), where adding
'?' would not compile. All edited fences re-verified with swift build
against ably-cocoa.

Also fixes subject-verb agreement in the shared batch-operations
sentence on the index page (addresses Copilot review on #3515).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-app Create a Heroku review app

Development

Successfully merging this pull request may close these issues.

2 participants