Skip to content

feat(realtime): v3 client implementation#995

Draft
grdsdev wants to merge 82 commits into
release/v3from
claude/charming-euler-49c5a1
Draft

feat(realtime): v3 client implementation#995
grdsdev wants to merge 82 commits into
release/v3from
claude/charming-euler-49c5a1

Conversation

@grdsdev

@grdsdev grdsdev commented May 7, 2026

Copy link
Copy Markdown
Contributor

Implements the Realtime v3 client in a new, isolated RealtimeV3 target (renamed to Realtime at cutover), per the v3 design proposal.

  • Phoenix v2 wire protocol (JSON text frames + binary broadcast frames), typed-throws API, AsyncStream-based broadcast / presence / postgres_changes.
  • Connection lifecycle: lazy connect, heartbeat, backoff reconnection with transparent channel re-join, and idle-close.
  • Tested with unit tests plus integration/e2e tests against a local Supabase instance.

Base: release/v3.

@github-actions github-actions Bot added the Realtime Work related to realtime package label May 7, 2026
@coveralls

coveralls commented Jun 27, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 28446934485

Coverage decreased (-0.03%) to 80.743%

Details

  • Coverage decreased (-0.03%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • 3 coverage regressions across 1 file.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

3 previously-covered lines in 1 file lost coverage.

File Lines Losing Coverage Coverage
Sources/Helpers/AnyJSON/AnyJSON.swift 3 97.35%

Coverage Stats

Coverage Status
Relevant Lines: 10235
Covered Lines: 8264
Line Coverage: 80.74%
Coverage Strength: 34.18 hits per line

💛 - Coveralls

grdsdev and others added 9 commits June 27, 2026 07:22
Greenfield Swift API redesign for the Realtime module, targeting Swift 6.2+.
Captures the locked design after grill-through review:

- realtime-v3.md — full API specification: explicit lifecycle, typed throws
  throughout, AsyncSequence as the canonical surface, register-then-subscribe
  pattern for postgres_changes (reflecting the Phoenix wire constraint that
  filters must be in the join payload), shared-by-topic channel identity,
  pluggable transport + clock for deterministic testing, 45+ locked decisions
  with rationale, and a V2 → V3 migration table.

- realtime-v3-questions-for-backend.md — assumption-vs-question pairs across
  16 topics (connection, channel lifecycle, broadcast WS + HTTP, replay,
  presence, postgres changes, auth, errors, rate limits, ordering, app
  lifecycle, protocol limits) for the Realtime backend team to validate
  before implementation begins.

Tracked in Linear:
https://linear.app/supabase/project/realtime-v3-idiomatic-swift-api-rfc-044c5935314f

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the two-type Channel + ActiveChannel split with a single post-join
type that conforms to AsyncSequence and owns broadcast send.

- subscribe() returns ChannelSubscription (was ActiveChannel)
- ChannelSubscription: AsyncSequence with Element = PhoenixMessage
- typed views: broadcasts(of:event:), events(for: token), presence
- broadcast send moves from Channel to ChannelSubscription — type-level
  gate replaces the runtime .channelNotJoined error
- presence accessor moves from Channel to ChannelSubscription
- subscribe() is now the only join path; no iteration-driven lazy-join
- 30-second tour, §2-§7, §11 migration table, §12 decisions, Appendix A
  all updated end-to-end

The new shape collapses asymmetry: Channel exposes registration + the join
verb; ChannelSubscription exposes everything else. Sending without a live
subscription is unrepresentable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…te accessor

- PhoenixMessage gains joinRef and ref fields for request/reply correlation
  visibility; raw iteration now includes internal phx_reply/phx_close/phx_error
  frames so advanced consumers can observe everything the SDK sees.
- Document raw iteration as the unfiltered escape hatch (the SDK still
  consumes these frames internally for ack correlation and lifecycle).
- Lock decisions 14k (raw PhoenixMessage shape) and 14l (defer
  ChannelSubscription.isAlive / state accessor — additive if needed).
- subscribe() remains async throws (no change); confirmed lock.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Including topic on the raw frame so consumers that pass PhoenixMessage
values across logging, debugging, or multi-topic aggregation surfaces
keep the routing key without threading it separately. Always matches the
ChannelSubscription's topic for in-iteration consumers.

Confirmed locks (no spec change needed):
- Socket-level RTT via ConnectionStatus.latency is sufficient (no per-channel
  / per-broadcast latency stream).
- ChannelSubscription stays as the type name.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lidates-subscription

Three improvements after consistency sweep:

1. ChangeRegistration generics simplified.
   - Variants (Insert/Update/Delete/AnyEvent) are themselves generic over T
     and conform to a ChangeEventVariant protocol declaring Element.
   - ChangeRegistration drops to a single generic parameter (the variant
     carries T): ChangeRegistration<Insert<Message>> instead of
     ChangeRegistration<Message, Insert>.
   - sub.events(for:) becomes a single overload dispatched on the variant.
   - Fixes a real type-system bug in the previous shape, where
     ChangeEventVariant.Element referenced T but T wasn't in scope.

2. Filter split into Filter<T: RealtimeTable> + UntypedFilter.
   - Untyped path no longer requires JSONValue to conform to RealtimeTable.
   - Untyped factories (channel.changes(schema:table:filter:), etc.) return
     ChangeRegistration<E<JSONValue>>; identical type to typed registrations
     just with a different variant T. Mix freely.

3. Tighten subscription lifecycle.
   - §2.1 invariants now state that manual leave() invalidates the
     subscription value; methods throw .channelClosed(.userRequested);
     iteration terminates; reconnects do NOT invalidate.
   - Decision 14m captures this; 14n/14o capture the type split.

Also drops .channelNotJoined from §7 references (already removed earlier;
Decision 26 still mentioned it — fixed).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bugs fixed:
- §1.2 Configuration: replace fictional .iso8601 / .automaticDefault statics
  with proper SDK-provided constants (JSONDecoder.realtimeDefault,
  LifecyclePolicy.automaticDefault). Add `& Sendable` to the clock type.
- §1.2: rename `handleAppLifecycle: Bool` to `lifecycle: LifecyclePolicy`
  so the §9.3 enum is actually wired in (was dead code before).
- §6.1: declare realtime.connect() — was referenced but never declared.
- §4: define PresenceKey (typealias for String).
- §5.2: add RealtimePostgresFilterValue constraint to .in factory.
- Appendix A: pass `me: UUID` through init (Self.currentUserID was
  undefined); rename ChatMessage to ChatBroadcast and define the type.

Inconsistencies fixed:
- §2.1: drop "joins lazily on first subscribe" (subscribe IS the join).
- §2.3: pipelined re-acquire returns the same Channel actor in
  unsubscribed state, not a "fresh Channel" (was contradicting Decision 1).
- §4: docstring referenced channel.leave(); generalize to "leave on any
  holder of the topic".
- §9.2: stale channel.broadcast(...) → sub.broadcast(...).
- §6.2: split disconnect()'s close reason from policy giveup —
  add CloseReason.clientDisconnected. Reconnection policy applies only
  to UNEXPECTED closes.
- §12: refresh Decisions 12, 13, 22 to reflect the typed/untyped filter
  split and the broadcast Data overload. Decision 14g merged into 26.

Ambiguities tightened:
- §6.3: clarify "same token" = byte-equal returned string, no rotation
  attempted; propagate .authenticationFailed.
- §6.4: document `since` (state-entry timestamp) and `latency` semantics.
- §7: explain .disconnected vs .channelClosed distinction.
- §7: add .unknownToken for events(for:) called with cross-channel tokens.
- §2.1 PhoenixMessage.joinRef: document v1 (always nil) vs v2 behavior.

No semantic changes — all locked decisions stand.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@grdsdev grdsdev force-pushed the claude/charming-euler-49c5a1 branch from ad44789 to d2d0987 Compare June 27, 2026 10:22
@grdsdev grdsdev changed the base branch from main to release/v3 June 27, 2026 10:23
grdsdev and others added 17 commits June 27, 2026 11:40
…ain actors)

Final review pass focused on Swift 6 idiom, grounded against the repo
(Swift tools 6.1, StrictConcurrency complete) and house style.

- Plain `public actor Realtime` / `public actor Channel` — drop `final`
  (an error on actors) and redundant `: Sendable`. Matches AuthClient /
  FunctionsClient house style.
- Explicit isolation contract: immutable metadata (topic, options),
  stream factories (broadcasts, postgresChanges, messages, state, presence,
  status), and postgres registration are `nonisolated` over a Sendable
  lock-protected hub; channel(_:), subscribe, leave, broadcast-send,
  httpBroadcast, and presence.track are isolated `async`. Resolves call
  sites in the examples that read members without `await`.
- channel(_:) is isolated (touches the actor's topic registry); callers
  `await`. Appendix A restructured to acquire the channel async in start().
- Raw feed is now `nonisolated var messages: AsyncStream<PhoenixMessage>`
  instead of an AsyncSequence conformance on the actor (avoids the awkward
  synchronous makeAsyncIterator() requirement and a public iterator type).
- Document AsyncStream single-consumer semantics: fan-out is per call;
  two consumers = two calls.
- New Decisions 8a (isolation contract) and updated 8, 14f.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… actor

Per review: remove the "nonisolated over a Sendable lock-protected hub"
concept. Channel is now a straightforward actor that is the single source of
truth for its state.

- `state` is an isolated property (stored in the actor), not nonisolated.
- Raw feed is `func messages() -> AsyncStream<PhoenixMessage>` — a method,
  since each call mints a fresh stream; isolated.
- broadcasts(of:event:), postgresChanges(for:), and the postgres registration
  factories (changes/inserts/updates/deletes) are isolated — they register a
  consumer / pending registration in the actor, so callers `await` them.
- realtime.status is isolated too (same actor-state-backed-stream situation).
- Only `topic`/`options` (immutable lets) and the `presence` accessor (wraps
  self; its stream methods register lazily) remain nonisolated.
- Rewrote the Isolation contract, Decisions 8a/14f, and updated the
  30-second tour, §5.3/§5.4 usage, and Appendix A to `await` the factories.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Aligns the design with the project's actual floor (AGENTS.md: iOS 16+;
package: swift-tools 6.1). Audited every higher-floor dependency:

- Swift 6.2-only: removed the isolated-deinit claim (Appendix C). The
  leaked-channel warning reads a nonisolated flag from the synchronous
  deinit, so no isolated deinit is needed. Typed throws is Swift 6.0, fine.
- iOS 17 withThrowingDiscardingTaskGroup → withThrowingTaskGroup(of: Void.self)
  + waitForAll() in both task-group examples (§5.3 usage, Appendix A).
- iOS 17 @observable → ObservableObject + @published in Appendix A (with a
  note that iOS 17+ uses @observable, and Perception back-ports below 17).
  Design Principle 4 reworded: the SDK surface is AsyncSequence-based and
  does not depend on Observation.
- Appendix C floor: iOS 16 / macOS 13 / tvOS 16 / watchOS 9 / visionOS 1.
  macOS pairs at 13 (not 12) because Duration/Clock/ContinuousClock — used
  for timeouts, backoff, and heartbeat RTT — are iOS 16 / macOS 13.

The core design (actors, AsyncStream, typed throws, macros, the isolation
contract) is unchanged — all of it is available on Swift 6.1 / iOS 16.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…annelState)

- JSONValue: typealias to AnyJSON for SDK interoperability
- RealtimeError: flat enum with 20 error cases (spec §7) + LocalizedError
- ChannelState + CloseReason: connection state machine (spec §2.4)
- Refactor InMemoryConnection.frames to use AsyncThrowingStream.makeStream()
  and store the bridging Task so close(code:reason:) can cancel it, preventing
  leaks when the consumer drops early.
- Remove the unused fileprivate yieldClientSent(_:) method from TransportServer.
- Remove the no-op nonisolated annotation from TransportServer.init.
- Add a NOTE comment at the connection-construction site explaining shared
  streams across reconnects.
- RefGenerator: LockIsolated monotonic counter producing "1", "2", ... refs
- InflightPushRegistry: actor with LockIsolated pending dict to race reply vs timeout
- RealtimeError: add Equatable conformance for #expect(throws:) in tests
Clamp jitter result to non-negative in exponentialBackoff, add an
explanatory comment on State about missing Equatable synthesis, and add
three new tests covering max-clamp, fixed with limit, and fixed unlimited.
…lazy connect

Add ChannelOptions/BroadcastOptions/PresenceOptions/ReplayOption (§2.2),
minimal Channel actor stub, and Realtime actor with idempotent/coalescing
connect(), topic→Channel registry (first-call-wins, Decision 33), and
status AsyncStream broadcast. Transport parameter is required (no default)
pending Task 11's URLSessionTransport.
…altimeError Equatable; fix connect task lifecycle
grdsdev added 28 commits June 29, 2026 11:18
…on reconnect

After a successful reconnect, all channels that were previously joined
(shouldRejoin=true) automatically re-send their phx_join frame with the
same baked postgres_changes registrations. On success, presence state is
re-tracked if isPresenceTracked was true (Decision 18). Open messages(),
broadcasts, postgres, and presence streams survive the transport gap
without interruption (Decision 6). On policy give-up, eligible channels
transition to .closed(.transportFailure), terminating all streams with
the appropriate error/finish, and are evicted from the channel registry.
Observes app background/foreground transitions when Configuration.lifecycle
== .automatic (the default on iOS/macOS/tvOS/visionOS). On returning to
foreground after a background drop, reconnects only if the socket is down
and no intentional disconnect was requested. Manual lifecycle policy and
explicit disconnect() both suppress the foreground reconnect. The lifecycle
source is injectable via an internal init parameter so tests drive it
deterministically without a real app.
Add RealtimeLogger protocol, LogEvent, LogLevel, Category types per spec §10.
Ship OSLogLogger (macOS 11+/iOS 14+ availability guard) and StdoutLogger.
Add Configuration.logger field (was TODO-deferred).

Emit log events at key lifecycle sites:
- connection: connect, connected, disconnect, reconnect (with attempt metric)
- channel: join, joined, leave, left, rejection
- presence: track, untrack
- postgres: subscription errors via system events

Metrics-as-logs: heartbeat.rtt_ms on every heartbeat reply,
reconnect.attempt on every reconnect loop iteration.

Realtime.log() is nonisolated (backed by nonisolated let logger) so
Channel can call it synchronously without await, keeping logging
non-throwing and non-async as required.
Tracks which channel topics have joined but not been explicitly left in a
nonisolated LockIsolated<Set<String>> on Realtime. A synchronous deinit
reads this set (no actor hop, no Swift 6.2 isolated deinit) and fires
reportIssue via IssueReporting if any topics remain joined. Channel.transition(to:)
wires _markJoined/_markLeft at join/close boundaries. disconnect() intentionally
does NOT clear joinedTopics (transport-level, not leave). Tests use
withExpectedIssue (Swift Testing) for the leak case and plain pass for the
no-warn case; deinit is made deterministic by scoping Realtime in an inner
function and calling disconnect() to cancel background task captures first.
…uration.encoder, send vsn

Fix #1: Channel.receive(_:) now routes phx_close, phx_error, and non-postgres
system error frames to terminal close transitions. Guards on current state so
a trailing phx_close after our own leave() does not overwrite .userRequested.
Clears shouldRejoin on server-initiated close to prevent auto-rejoin loops.
The existing transition(to: .closed) cascade finishes all broadcast, postgres,
presence, and messages streams so consumers receive the error cleanly.

Fix #2: All user-payload Encodable encode sites now use realtime.configuration.encoder
(Channel+Broadcast.swift broadcast<T>, Channel.sendPresenceTrack,
HttpBroadcast.swift _httpBroadcastBatch). PhoenixSerializer retains bare
JSONEncoder — it encodes protocol frame arrays (not user Codable types) and a
comment documents the intentional distinction.

Fix #3: _openConnection appends vsn=<configuration.protocolVersion.rawValue>
to the connect URL so the backend can negotiate the binary serializer format.

Tests: ServerCloseTests (serverPhxCloseTerminatesChannel,
serverSystemAuthErrorClosesUnauthorized, ownLeaveNotOverwrittenByTrailingPhxClose,
serverPhxErrorTerminatesChannel), ConfiguredEncoderTests
(configuredEncoderUsedForBroadcast), VsnConnectTests (vsnSentOnConnect,
vsnRespectsProtocolVersionConfig). All 129 RealtimeV3Tests pass, 0 warnings.
Wire the `Configuration.disconnectOnEmptyChannelsAfter` knob (Decision 39):
when the last live channel leaves, arm a timer on `configuration.clock`;
after the duration elapses with no new channels joining, close the socket
and transition status to `.idle`.

Key design choices:
- Live-channel count is tracked via the existing `joinedTopics` LockIsolated
  set (already updated by `_markJoined`/`_markLeft`); reusing it avoids a
  parallel counter and is semantically correct — a terminally-closed channel
  is `_markLeft`, so it is no longer counted.
- Idle close uses a separate `idleClosed` flag (not `intentionalDisconnect`)
  so the reconnect suppression is scoped to the idle close only. `connect()`
  clears `idleClosed` on entry, making the next `subscribe()` fully recover.
- `idleCloseTask` is cancelled on `_markJoined` (new channel joins), on
  `disconnect()` (avoid double teardown), and superseded on re-arm.
- Status after idle close is `.idle` (not `.closed(.clientDisconnected)`)
  to signal "recoverable idle" vs "explicit user disconnect".
…annel()

_openConnection() now appends `/websocket` to the base URL before dialling
the transport, guarding against double-append when the caller already ends
in `/websocket`. The HTTP broadcast client uses a separate httpBaseURL that
is derived from the original url (before path mutation) so it continues to
POST to `.../realtime/v1/api/broadcast` unchanged.

channel(_:configure:) now computes fullTopic = "realtime:<topic>" once, with
a hasPrefix guard to prevent double-prefix. The prefixed string IS channel.topic
from creation onward; no strip/dual-topic logic was added anywhere else.

Tests updated: all server-injected frames that carry a hardcoded topic string
now use the prefixed form ("realtime:room:1" etc.). UpdateTokenTests assertion
updated to match the prefixed topic. Integration tests switched to base URL
(no /websocket) and short topics — the SDK adds the prefix automatically.
…live supabase

IE-3 BroadcastE2ETests: WS round-trip between two clients, HTTP broadcast
delivery via httpBroadcastBatch (with SDK gap documented), ack mode.

IE-4 PresenceE2ETests: two-client presence sync — track, observe join,
cancel handle, observe leave.

IE-5 PostgresChangesE2ETests: INSERT with room_id filter (server-id routing
validated), UPDATE with old_record (REPLICA IDENTITY FULL confirmed), DELETE
with PK-only old_record (server security behavior documented).

IE-6 ReconnectionE2ETests: leave → disconnect → connect → subscribe cycle;
broadcast stream resumes post-reconnect. SDK gap documented: intentional
disconnect without prior leave() leaves channel in .joined state, making
subscribe() idempotent. Forced-drop reconnect covered by unit RejoinTests.

SDK gaps found:
- Channel.httpBroadcast sends full "realtime:<topic>" — server needs short topic
- HTTP broadcast endpoint requires service-role JWT, not anon apikey
- disconnect() without leave() strands channel in .joined state
…vent feed

Replace the seven per-type consumer/finisher registries on Channel
(broadcast/presence/postgres consumers + finishers + registrationConsumers)
with a single ChannelEvent feed. messages(), broadcasts(of:event:),
presence.observe/diffs, and postgresChanges(for:) are now transforms over a
fresh subscription to that feed, each filtering and decoding the frames it
cares about.

The close reason is carried in-band (.terminated(reason)) so throwing streams
finish with .channelClosed(reason) race-free. Per-consumer presence state
becomes task-local (drops LockIsolated), decoding moves off the actor's
critical path, and postgres server-id routing is read live per frame via a new
postgresServerIDs(for:) helper.
…elpers

Extract the repeated subscribe + drain-task + onTermination + terminal-close
handling into two generic Channel helpers, _makeStream and _makeThrowingStream,
parameterized by an inout per-subscription State. messages(), broadcasts,
presence observe/diffs, and postgresChanges now each reduce to a small body
closure over .message frames; the helper owns task lifecycle and translates a
terminal close to a clean finish (non-throwing) or .channelClosed(reason)
(throwing). Presence's running roster threads through State, so no external
storage or lock. No public API or behavior change.
… primitive

All nine frame-sending paths (broadcast x2, presence track/untrack/retrack,
join, rejoin, leave, access_token) re-implemented the same wire mechanics:
ref generation, text/binary encoding with error mapping, lazy-connect send, and
ack correlation. Extract that into Channel._push(event:body:ref:joinRef:ack:),
with a PushBody enum (text / broadcastJSON / broadcastData) and an AckPolicy
(none / require). Add _requireJoinedForSend() for the shared state gate and
_encodeToJSON() for the encoder round-trip.

Collapses the two divergent ack patterns into one: presence no longer
pre-registers a manual replyTask before sending — awaiting after send is
race-free thanks to the registry's early-reply buffering. No public API or
behavior change.
Drop _retrackPresence and the rejoin block that re-sent the last tracked
presence payload after a transparent reconnect, along with the now-dead
lastTrackedPresencePayload storage. isPresenceTracked stays (it keeps untrack
idempotent). After a rejoin, presence is no longer automatically re-tracked;
callers re-track explicitly if desired.
… funnel

Move the push primitive from Channel to Realtime (parameterized by topic) and
route every framed send through it, including the heartbeat. Channel._push is
now a thin wrapper supplying topic + the channel's joinRef. Add _rawSend (the
one place a frame reaches the socket) and a lazyConnect flag so the heartbeat
sends on the current connection without triggering a reconnect (a dead socket
surfaces as .disconnected/timeout instead). Replace sendText/sendBinary with
_rawSend. Heartbeater drops its encode/send/awaitReply/serializer plumbing and
becomes a loop that calls Realtime._sendHeartbeat (which routes through _push
and measures round-trip latency). No public API or behavior change.
Two quick wins enabled by the _push funnel:
- Wire the documented broadcast.ack_latency_ms metric: _push measures the
  send-to-ack round trip and logs it for acked broadcasts (heartbeat keeps its
  own heartbeat.rtt_ms; other acks have no defined metric). Factor the
  Duration-to-ms math into a Duration.inMilliseconds helper reused by both.
- Move _encodeToJSON to Realtime (nonisolated; reads the Sendable config) so
  HTTP broadcast and channel broadcast/presence share one encoder round-trip
  instead of three copies. Channel._encodeToJSON is now a thin wrapper.
…hannel joined

A join whose payload carries postgres_changes registrations is not actually
subscribed when the phx_reply arrives — the server sets up replication
asynchronously and confirms with a system event (extension postgres_changes,
status ok). Transitioning to .joined on the reply alone drops the first changes
(the recurring IE cold-start flake).

_performJoin and rejoin now subscribe to the channel event feed before sending
the join and, when registrations are present, await the system confirmation
(via _awaitPostgresSubscribed, racing joinTimeout) before .joined: status ok
proceeds, status error throws .postgresSubscriptionFailed, timeout throws
.channelJoinTimeout. No-registration joins keep reply-only behavior. The test
transport now emits the system ok after a join carrying a non-empty
postgres_changes set, mirroring the real server.
…n files

Both Realtime.swift (~1150) and Channel.swift (~1050) were over the 800-line
house soft-max. Carve out cohesive extensions (no behavior change):

- Realtime+Push.swift      — nextRef/_rawSend/_push/_encodeToJSON/awaitReply/accessTokenForJoin
- Realtime+Reconnection.swift — handleConnectionLost + reconnection loop + rejoin/give-up
- Realtime+Heartbeat.swift  — startHeartbeat/_sendHeartbeat/updateLatency
- Channel+Routing.swift     — receive + server-close/error + system routing + server-id routing
- Channel+Presence.swift    — gains the presence track/untrack send seam

Stored properties stay in the primary declarations; members reached across the
new file boundaries are widened from private to internal (Swift private does not
cross files), each annotated with why. Realtime.swift → 778, Channel.swift → 786.
… rejoin

_performJoin (subscribe path) and rejoin (reconnect path) were ~80% parallel —
generate ref, subscribe the postgres feed, build payload, push join, await
reply, build server-id routing, await the postgres system confirmation — and
had already drifted once (the postgres-system wait was added to both by hand).

Extract _sendJoin(ref:realtime:) for that shared wire handshake, returning a
JoinOutcome (.joined / .rejected) and throwing on wire failures. Each caller
keeps its own error policy: _performJoin throws (rejection -> .unauthorized +
.channelJoinRejected); rejoin maps outcome/error to state transitions (auth ->
.unauthorized, transport -> recoverable .transportFailure). Behavior preserved,
including the shouldRejoin=true ordering before the postgres wait.
…dcaster from Realtime

First step in decomposing the Realtime god-actor (Tier 1). Pull two concerns
that are not part of the socket state machine into focused value types held as
actor-isolated stored properties (no separate actors, so no new hops or
reentrancy windows, and no Sendable gymnastics):

- ChannelRegistry — the topic→Channel collection: lookup, insert, evict,
  snapshot. Replaces the raw dict scattered across connect/reconnect/routing/token.
- ConnectionStatusBroadcaster — current status + subscriber fan-out. Backs the
  status stream and transition()/updateLatency.

transition(), status, and channel(_:) stay as thin wrappers, so call sites are
unchanged. The socket mechanism (connect/reconnect/heartbeat/idle/routing/push)
stays cohesive in Realtime by design — splitting it across actors would
reintroduce the connection-state coordination the single-actor model prevents.
No behavior change.
…tionTasks

disconnect(), _performIdleClose(), and handleConnectionLost() each repeated the
same sequence: cancel the heartbeat + frame-routing tasks and failAll in-flight
pushes. Extract it into _teardownConnectionTasks(failPushesWith:). Each caller
keeps what's genuinely its own — claiming/clearing connection, the socket close
(distinct code/reason), caller-specific task/flag cancellation, and the status
transition. No behavior change.
- connect(): preserve a specific RealtimeError from the connect task instead of
  flattening every failure into .transportFailure(underlying:).
- Gate the _test_* shims behind #if DEBUG so they're compiled out of release.
- Extract _connectURL(base:apiKey:vsn:) as a pure, nonisolated static helper and
  cover it with ConnectURLTests (websocket append idempotency, query dedup).
- Replace the four invariant-justified as! casts in postgresChanges with a
  throwing postgresElement helper (never-crash policy).
- Introduce SystemEventPayload to centralize the postgres_changes/system wire
  keys + parse shape shared by _awaitPostgresSubscribed, _routeSystemEvent, and
  the postgres transform. No behavior change.
…annelHost

Channel held a weak reference to the concrete Realtime actor and reached into
its internals. Introduce a ChannelHost protocol capturing exactly the surface
Channel consumes (configuration, nextRef, log, _markJoined/_markLeft,
_encodeToJSON, accessTokenForJoin, _push, _httpBroadcastBatch) and depend on
`any ChannelHost` instead. Realtime conforms declaratively — every member
already has matching isolation (the earlier _push/_encodeToJSON consolidation is
what shrank the surface to 9 members).

Decouples the two types: Channel can be exercised against a test double, and the
host's identity becomes an implementation detail (de-risking a future
connection-controller split). No behavior change.
@grdsdev grdsdev changed the title docs(realtime): v3 API design proposal (RFC) feat(realtime): v3 client implementation Jun 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Potential Breaking API Changes Detected

This PR appears to contain breaking API changes. Please review the changes below:

API Check Output
** Checking required environment variables...
** Fetching baseline: https://github.com/supabase/supabase-swift.git#release/v3...
From https://github.com/supabase/supabase-swift
 * branch            release/v3 -> FETCH_HEAD
** Checking for API changes since https://github.com/supabase/supabase-swift.git#release/v3 (811d2f1acfe6da61a97a4752e7e52a5c79c86dac)...
Fetching https://github.com/apple/swift-argument-parser.git
Fetching https://github.com/mattt/Replay.git
[1/711] Fetching replay
Fetched https://github.com/mattt/Replay.git from cache (0.58s)
Fetching https://github.com/pointfreeco/swift-snapshot-testing
[1/17949] Fetching swift-argument-parser
Fetched https://github.com/apple/swift-argument-parser.git from cache (0.99s)
Fetching https://github.com/WeTransfer/Mocker
[1/1889] Fetching mocker
Fetched https://github.com/WeTransfer/Mocker from cache (0.59s)
Fetching https://github.com/pointfreeco/swift-clocks
[1/16173] Fetching swift-snapshot-testing
[648/17589] Fetching swift-snapshot-testing, swift-clocks
Fetched https://github.com/pointfreeco/swift-clocks from cache (0.57s)
Fetching https://github.com/apple/swift-crypto.git
[2265/16173] Fetching swift-snapshot-testing
[12778/33934] Fetching swift-snapshot-testing, swift-crypto
Fetched https://github.com/pointfreeco/swift-snapshot-testing from cache (2.94s)
Fetching https://github.com/pointfreeco/xctest-dynamic-overlay
[2309/17761] Fetching swift-crypto
[17762/23651] Fetching swift-crypto, xctest-dynamic-overlay
Fetched https://github.com/apple/swift-crypto.git from cache (2.01s)
Fetching https://github.com/pointfreeco/swift-custom-dump
[413/5890] Fetching xctest-dynamic-overlay
Fetched https://github.com/pointfreeco/xctest-dynamic-overlay from cache (0.99s)
Fetching https://github.com/apple/swift-http-types
[1/5609] Fetching swift-custom-dump
Fetched https://github.com/pointfreeco/swift-custom-dump from cache (0.68s)
Fetching https://github.com/apple/swift-asn1.git
[1/1219] Fetching swift-http-types
Fetched https://github.com/apple/swift-http-types from cache (0.62s)
Fetching https://github.com/pointfreeco/swift-concurrency-extras
[1/1914] Fetching swift-asn1
[1915/2953] Fetching swift-asn1, swift-concurrency-extras
Fetched https://github.com/apple/swift-asn1.git from cache (0.80s)
[42/1039] Fetching swift-concurrency-extras
Fetching https://github.com/swiftlang/swift-syntax
Fetched https://github.com/pointfreeco/swift-concurrency-extras from cache (0.62s)
Computing version for https://github.com/mattt/Replay.git
Computed https://github.com/mattt/Replay.git at 0.4.0 (6.37s)
Fetching https://github.com/swift-server/async-http-client.git
[1/75758] Fetching swift-syntax
[30305/91757] Fetching swift-syntax, async-http-client
Fetched https://github.com/swift-server/async-http-client.git from cache (1.39s)
[75758/75758] Fetching swift-syntax
Computing version for https://github.com/WeTransfer/Mocker
Fetched https://github.com/swiftlang/swift-syntax from cache (6.34s)
Computed https://github.com/WeTransfer/Mocker at 3.0.2 (7.85s)
Computing version for https://github.com/pointfreeco/xctest-dynamic-overlay
Computed https://github.com/pointfreeco/xctest-dynamic-overlay at 1.9.0 (0.56s)
Computing version for https://github.com/pointfreeco/swift-snapshot-testing
Computed https://github.com/pointfreeco/swift-snapshot-testing at 1.18.9 (0.42s)
Computing version for https://github.com/pointfreeco/swift-custom-dump
Computed https://github.com/pointfreeco/swift-custom-dump at 1.6.0 (0.50s)
Computing version for https://github.com/pointfreeco/swift-concurrency-extras
Computed https://github.com/pointfreeco/swift-concurrency-extras at 1.3.2 (0.47s)
Computing version for https://github.com/pointfreeco/swift-clocks
Computed https://github.com/pointfreeco/swift-clocks at 1.0.6 (0.52s)
Computing version for https://github.com/apple/swift-http-types.git
Computed https://github.com/apple/swift-http-types.git at 1.3.1 (0.74s)
Computing version for https://github.com/apple/swift-crypto.git
Computed https://github.com/apple/swift-crypto.git at 4.5.0 (1.98s)
Computing version for https://github.com/apple/swift-argument-parser.git
Computed https://github.com/apple/swift-argument-parser.git at 1.7.1 (0.68s)
Computing version for https://github.com/swiftlang/swift-syntax
Computed https://github.com/swiftlang/swift-syntax at 600.0.1 (0.86s)
Computing version for https://github.com/apple/swift-asn1.git
Computed https://github.com/apple/swift-asn1.git at 1.3.1 (0.78s)
Computing version for https://github.com/swift-server/async-http-client.git
Computed https://github.com/swift-server/async-http-client.git at 1.34.0 (0.62s)
Fetching https://github.com/apple/swift-distributed-tracing.git
Fetching https://github.com/apple/swift-algorithms.git
[1/5857] Fetching swift-distributed-tracing
[2/11927] Fetching swift-distributed-tracing, swift-algorithms
Fetched https://github.com/apple/swift-algorithms.git from cache (0.94s)
Fetched https://github.com/apple/swift-distributed-tracing.git from cache (0.94s)
Fetching https://github.com/apple/swift-log.git
Fetching https://github.com/apple/swift-atomics.git
[1/7604] Fetching swift-log
[78/9472] Fetching swift-log, swift-atomics
Fetched https://github.com/apple/swift-log.git from cache (0.74s)
Fetched https://github.com/apple/swift-atomics.git from cache (0.74s)
Fetching https://github.com/apple/swift-nio-transport-services.git
Fetching https://github.com/apple/swift-nio-extras.git
[1/2860] Fetching swift-nio-transport-services
[345/9403] Fetching swift-nio-transport-services, swift-nio-extras
Fetched https://github.com/apple/swift-nio-transport-services.git from cache (0.65s)
[3795/6543] Fetching swift-nio-extras
Fetching https://github.com/apple/swift-nio-http2.git
Fetched https://github.com/apple/swift-nio-extras.git from cache (0.78s)
Fetching https://github.com/apple/swift-nio-ssl.git
[1/12141] Fetching swift-nio-http2
[10564/27721] Fetching swift-nio-http2, swift-nio-ssl
Fetched https://github.com/apple/swift-nio-http2.git from cache (1.38s)
Fetching https://github.com/apple/swift-nio.git
[10906/15580] Fetching swift-nio-ssl
Fetched https://github.com/apple/swift-nio-ssl.git from cache (1.81s)
[1/84155] Fetching swift-nio
Fetched https://github.com/apple/swift-nio.git from cache (3.99s)
Computing version for https://github.com/apple/swift-distributed-tracing.git
Computed https://github.com/apple/swift-distributed-tracing.git at 1.4.1 (8.25s)
Fetching https://github.com/apple/swift-service-context.git
[1/1301] Fetching swift-service-context
Fetched https://github.com/apple/swift-service-context.git from cache (0.60s)
Computing version for https://github.com/apple/swift-algorithms.git
Computed https://github.com/apple/swift-algorithms.git at 1.2.1 (1.19s)
Fetching https://github.com/apple/swift-numerics.git
[1/6441] Fetching swift-numerics
Fetched https://github.com/apple/swift-numerics.git from cache (0.73s)
Computing version for https://github.com/apple/swift-nio.git
Computed https://github.com/apple/swift-nio.git at 2.101.2 (1.46s)
Fetching https://github.com/apple/swift-collections.git
Fetching https://github.com/apple/swift-system.git
[1/5941] Fetching swift-system
[239/31213] Fetching swift-system, swift-collections
Fetched https://github.com/apple/swift-system.git from cache (0.80s)
[5813/25272] Fetching swift-collections
Fetched https://github.com/apple/swift-collections.git from cache (1.48s)
Computing version for https://github.com/apple/swift-atomics.git
Computed https://github.com/apple/swift-atomics.git at 1.3.1 (1.99s)
Computing version for https://github.com/apple/swift-service-context.git
Computed https://github.com/apple/swift-service-context.git at 1.3.0 (0.56s)
Computing version for https://github.com/apple/swift-numerics.git
Computed https://github.com/apple/swift-numerics.git at 1.1.1 (0.53s)
Computing version for https://github.com/apple/swift-nio-transport-services.git
Computed https://github.com/apple/swift-nio-transport-services.git at 1.28.0 (0.43s)
Computing version for https://github.com/apple/swift-nio-http2.git
Computed https://github.com/apple/swift-nio-http2.git at 1.44.0 (0.41s)
Computing version for https://github.com/apple/swift-nio-ssl.git
Computed https://github.com/apple/swift-nio-ssl.git at 2.37.1 (0.41s)
Computing version for https://github.com/apple/swift-log.git
Computed https://github.com/apple/swift-log.git at 1.14.0 (0.35s)
Computing version for https://github.com/apple/swift-system.git
Computed https://github.com/apple/swift-system.git at 1.7.2 (0.35s)
Computing version for https://github.com/apple/swift-nio-extras.git
Computed https://github.com/apple/swift-nio-extras.git at 1.34.1 (0.40s)
Fetching https://github.com/swift-server/swift-service-lifecycle.git
Fetching https://github.com/apple/swift-async-algorithms.git
[1/2770] Fetching swift-service-lifecycle
[2771/9354] Fetching swift-service-lifecycle, swift-async-algorithms
Fetched https://github.com/swift-server/swift-service-lifecycle.git from cache (0.62s)
[264/6584] Fetching swift-async-algorithms
Fetching https://github.com/apple/swift-certificates.git
Fetched https://github.com/apple/swift-async-algorithms.git from cache (0.77s)
Fetching https://github.com/apple/swift-http-structured-headers.git
[1/1249] Fetching swift-http-structured-headers
[101/8577] Fetching swift-http-structured-headers, swift-certificates
Fetched https://github.com/apple/swift-http-structured-headers.git from cache (0.59s)
[74/7328] Fetching swift-certificates
Fetched https://github.com/apple/swift-certificates.git from cache (1.11s)
Computing version for https://github.com/swift-server/swift-service-lifecycle.git
Computed https://github.com/swift-server/swift-service-lifecycle.git at 2.11.0 (2.13s)
Computing version for https://github.com/apple/swift-async-algorithms.git
Computed https://github.com/apple/swift-async-algorithms.git at 1.1.5 (0.40s)
Computing version for https://github.com/apple/swift-http-structured-headers.git
Computed https://github.com/apple/swift-http-structured-headers.git at 1.7.0 (0.31s)
Computing version for https://github.com/apple/swift-certificates.git
Computed https://github.com/apple/swift-certificates.git at 1.19.2 (0.62s)
Computing version for https://github.com/apple/swift-collections.git
Computed https://github.com/apple/swift-collections.git at 1.6.0 (0.54s)
Creating working copy for https://github.com/pointfreeco/swift-concurrency-extras
Working copy of https://github.com/pointfreeco/swift-concurrency-extras resolved at 1.3.2
Creating working copy for https://github.com/apple/swift-async-algorithms.git
Working copy of https://github.com/apple/swift-async-algorithms.git resolved at 1.1.5
Creating working copy for https://github.com/apple/swift-numerics.git
Working copy of https://github.com/apple/swift-numerics.git resolved at 1.1.1
Creating working copy for https://github.com/apple/swift-service-context.git
Working copy of https://github.com/apple/swift-service-context.git resolved at 1.3.0
Creating working copy for https://github.com/swift-server/async-http-client.git
Working copy of https://github.com/swift-server/async-http-client.git resolved at 1.34.0
Creating working copy for https://github.com/apple/swift-collections.git
Working copy of https://github.com/apple/swift-collections.git resolved at 1.6.0
Creating working copy for https://github.com/pointfreeco/swift-custom-dump
Working copy of https://github.com/pointfreeco/swift-custom-dump resolved at 1.6.0
Creating working copy for https://github.com/pointfreeco/swift-clocks
Working copy of https://github.com/pointfreeco/swift-clocks resolved at 1.0.6
Creating working copy for https://github.com/apple/swift-certificates.git
Working copy of https://github.com/apple/swift-certificates.git resolved at 1.19.2
Creating working copy for https://github.com/WeTransfer/Mocker
Working copy of https://github.com/WeTransfer/Mocker resolved at 3.0.2
Creating working copy for https://github.com/apple/swift-nio-extras.git
Working copy of https://github.com/apple/swift-nio-extras.git resolved at 1.34.1
Creating working copy for https://github.com/apple/swift-nio.git
Working copy of https://github.com/apple/swift-nio.git resolved at 2.101.2
Creating working copy for https://github.com/apple/swift-argument-parser.git
Working copy of https://github.com/apple/swift-argument-parser.git resolved at 1.7.1
Creating working copy for https://github.com/pointfreeco/swift-snapshot-testing
Working copy of https://github.com/pointfreeco/swift-snapshot-testing resolved at 1.18.9
Creating working copy for https://github.com/apple/swift-crypto.git
Working copy of https://github.com/apple/swift-crypto.git resolved at 4.5.0
Creating working copy for https://github.com/swift-server/swift-service-lifecycle.git
Working copy of https://github.com/swift-server/swift-service-lifecycle.git resolved at 2.11.0
Creating working copy for https://github.com/swiftlang/swift-syntax
Working copy of https://github.com/swiftlang/swift-syntax resolved at 600.0.1
Creating working copy for https://github.com/apple/swift-nio-http2.git
Working copy of https://github.com/apple/swift-nio-http2.git resolved at 1.44.0
Creating working copy for https://github.com/apple/swift-nio-ssl.git
Working copy of https://github.com/apple/swift-nio-ssl.git resolved at 2.37.1
Creating working copy for https://github.com/apple/swift-http-structured-headers.git
Working copy of https://github.com/apple/swift-http-structured-headers.git resolved at 1.7.0
Creating working copy for https://github.com/apple/swift-distributed-tracing.git
Working copy of https://github.com/apple/swift-distributed-tracing.git resolved at 1.4.1
Creating working copy for https://github.com/apple/swift-algorithms.git
Working copy of https://github.com/apple/swift-algorithms.git resolved at 1.2.1
Creating working copy for https://github.com/apple/swift-http-types
Working copy of https://github.com/apple/swift-http-types resolved at 1.3.1
Creating working copy for https://github.com/apple/swift-atomics.git
Working copy of https://github.com/apple/swift-atomics.git resolved at 1.3.1
Creating working copy for https://github.com/apple/swift-log.git
Working copy of https://github.com/apple/swift-log.git resolved at 1.14.0
Creating working copy for https://github.com/apple/swift-system.git
Working copy of https://github.com/apple/swift-system.git resolved at 1.7.2
Creating working copy for https://github.com/mattt/Replay.git
Working copy of https://github.com/mattt/Replay.git resolved at 0.4.0
Creating working copy for https://github.com/pointfreeco/xctest-dynamic-overlay
Working copy of https://github.com/pointfreeco/xctest-dynamic-overlay resolved at 1.9.0
Creating working copy for https://github.com/apple/swift-nio-transport-services.git
Working copy of https://github.com/apple/swift-nio-transport-services.git resolved at 1.28.0
Creating working copy for https://github.com/apple/swift-asn1.git
Working copy of https://github.com/apple/swift-asn1.git resolved at 1.3.1
[1/1] Compiling plugin ReplayPlugin
[2/2] Compiling plugin GenerateManual
[3/3] Compiling plugin GenerateDoccReference
Building for debugging...
[3/36] Copying PrivacyInfo.xcprivacy
[4/36] Write sources
[34/36] Compiling _SwiftSyntaxCShims dummy.c
[35/36] Write swift-version--79AA4F9932D1E87A.txt
[37/42] Emitting module SwiftSyntax600
[38/42] Compiling SwiftSyntax600 Empty.swift
[39/42] Emitting module SwiftSyntax509
[40/42] Compiling SwiftSyntax509 Empty.swift
[41/42] Emitting module SwiftSyntax510
[42/42] Compiling SwiftSyntax510 Empty.swift
[43/73] Compiling IssueReportingPackageSupport _Test.swift
[44/73] Emitting module IssueReportingPackageSupport
[45/122] Emitting module SwiftSyntax
[46/145] Compiling SwiftSyntax AbsolutePosition.swift
[47/145] Compiling SwiftSyntax AbsoluteRawSyntax.swift
[48/147] Compiling Mocker OnRequestHandler.swift
[49/147] Compiling Mocker XCTest+Mocker.swift
[50/147] Emitting module Mocker
[51/147] Compiling SwiftSyntax AbsoluteSyntaxInfo.swift
[52/147] Compiling SwiftSyntax Assert.swift
[53/162] Emitting module SnapshotTesting
[54/173] Emitting module IssueReporting
[55/180] Compiling IssueReporting UncheckedSendable.swift
[56/180] Compiling IssueReporting Warn.swift
[57/180] Compiling IssueReporting XCTest.swift
[58/180] Compiling IssueReporting IsTesting.swift
[59/180] Compiling IssueReporting IssueReporter.swift
[60/180] Compiling IssueReporting BreakpointReporter.swift
[61/180] Compiling IssueReporting DefaultReporter.swift
[62/180] Compiling IssueReporting ErrorReporting.swift
[63/180] Compiling IssueReporting AppHostWarning.swift
[64/180] Compiling IssueReporting Deprecations.swift
[65/180] Compiling IssueReporting FailureObserver.swift
[66/180] Compiling IssueReporting LockIsolated.swift
[67/180] Compiling IssueReporting Rethrows.swift
[68/180] Compiling IssueReporting SwiftTesting.swift
[69/180] Compiling IssueReporting FatalErrorReporter.swift
[70/180] Compiling IssueReporting IssueSeverity.swift
[71/180] Compiling IssueReporting ReportIssue.swift
[72/180] Compiling IssueReporting TestContext.swift
[73/180] Compiling IssueReporting Unimplemented.swift
[74/180] Compiling IssueReporting WithExpectedIssue.swift
[75/180] Compiling IssueReporting WithIssueContext.swift
[85/187] Compiling SwiftSyntax SyntaxArena.swift
[86/187] Compiling SwiftSyntax SyntaxArenaAllocatedBuffer.swift
[87/187] Emitting module HTTPTypes
[88/189] Compiling HTTPTypes ISOLatin1String.swift
[89/189] Compiling HTTPTypes NIOLock.swift
[90/189] Compiling HTTPTypes HTTPField.swift
[91/189] Compiling HTTPTypes HTTPFieldName.swift
[92/189] Compiling HTTPTypes HTTPFields.swift
[93/189] Compiling HTTPTypes HTTPParsedFields.swift
[94/189] Compiling HTTPTypes HTTPRequest.swift
[95/189] Compiling HTTPTypes HTTPResponse.swift
[108/192] Compiling SnapshotTesting NSView.swift
[109/192] Compiling SnapshotTesting NSViewController.swift
[110/192] Compiling SnapshotTesting SceneKit.swift
[111/192] Compiling SnapshotTesting SpriteKit.swift
[112/192] Compiling SnapshotTesting String.swift
[113/192] Compiling SnapshotTesting SwiftUIView.swift
[114/192] Compiling SnapshotTesting UIBezierPath.swift
[115/192] Compiling SnapshotTesting UIImage.swift
[116/192] Compiling SnapshotTesting UIView.swift
[117/192] Compiling SnapshotTesting UIViewController.swift
[118/192] Compiling SnapshotTesting URLRequest.swift
[119/192] Emitting module XCTestDynamicOverlay
[120/192] Compiling XCTestDynamicOverlay Exports.swift
[121/192] Compiling XCTestDynamicOverlay Deprecations.swift
[122/250] Emitting module ConcurrencyExtras
[123/253] Compiling ConcurrencyExtras Locking.swift
[124/253] Compiling ConcurrencyExtras UncheckedBox.swift
[125/253] Compiling ConcurrencyExtras LockIsolated.swift
[126/253] Compiling ConcurrencyExtras MainSerialExecutor.swift
[127/253] Compiling ConcurrencyExtras ActorIsolated.swift
[128/253] Compiling ConcurrencyExtras AnyHashableSendable.swift
[129/253] Compiling ConcurrencyExtras AsyncStream.swift
[130/253] Compiling ConcurrencyExtras AsyncThrowingStream.swift
[131/253] Compiling ConcurrencyExtras Result.swift
[132/253] Compiling ConcurrencyExtras Task.swift
[133/253] Compiling ConcurrencyExtras UncheckedSendable.swift
[134/274] Emitting module Crypto
[135/298] Compiling Crypto Insecure_HashFunctions.swift
[136/298] Compiling Crypto MLKEM_boring.swift
[137/298] Compiling Crypto MLKEM_wrapper.swift
[138/298] Compiling Crypto XWing_boring.swift
[139/298] Compiling Crypto KEM-Errors.swift
[140/298] Compiling Crypto KEM.swift
[141/298] Compiling Crypto MLKEM.swift
[142/298] Compiling Crypto XWing.swift
[143/298] Compiling Crypto ECDH_boring.swift
[144/298] Compiling Crypto DH.swift
[145/298] Compiling Crypto ECDH.swift
[146/298] Compiling Crypto ANSIx963.swift
[147/298] Compiling Crypto HKDF.swift
[148/298] Compiling Crypto AESWrap.swift
[149/298] Compiling Crypto AESWrap_boring.swift
[150/298] Compiling Crypto Ed25519_boring.swift
[151/298] Compiling Crypto NISTCurvesKeys_boring.swift
[152/298] Compiling Crypto X25519Keys_boring.swift
[153/298] Compiling Crypto Curve25519.swift
[154/298] Compiling Crypto Ed25519Keys.swift
[155/298] Compiling Crypto NISTCurvesKeys.swift
[156/298] Compiling Crypto X25519Keys.swift
[157/298] Compiling Crypto SymmetricKeys.swift
[158/298] Compiling Crypto HMAC.swift
[159/321] Compiling CustomDump CoreImage.swift
[160/321] Compiling CustomDump CoreLocation.swift
[161/321] Compiling CustomDump CoreMotion.swift
[162/321] Compiling CustomDump Foundation.swift
[163/321] Compiling CustomDump GameKit.swift
[164/321] Compiling CustomDump KeyPath.swift
[165/321] Compiling CustomDump Photos.swift
[166/321] Compiling CustomDump Speech.swift
[167/321] Compiling CustomDump StoreKit.swift
[168/321] Compiling CustomDump Swift.swift
[169/321] Compiling CustomDump SwiftUI.swift
[170/321] Compiling CustomDump UIKit.swift
[171/321] Compiling CustomDump UniformTypeIdentifiers.swift
[172/321] Compiling CustomDump UserNotifications.swift
[173/321] Compiling CustomDump UserNotificationsUI.swift
[174/321] Compiling CustomDump CustomDumpReflectable.swift
[175/321] Compiling CustomDump CustomDumpRepresentable.swift
[176/321] Compiling CustomDump CustomDumpStringConvertible.swift
[177/321] Compiling CustomDump Diff.swift
[178/321] Compiling CustomDump Dump.swift
[179/321] Compiling Crypto HPKE-Context.swift
[180/321] Compiling Crypto HPKE-KeySchedule.swift
[181/321] Compiling Crypto HPKE-Modes.swift
[182/321] Compiling Crypto Insecure.swift
[183/321] Compiling Crypto AES-GCM.swift
[184/321] Compiling Crypto AES-GCM_boring.swift
[185/321] Compiling Crypto ChaChaPoly_boring.swift
[186/321] Compiling Crypto ChaChaPoly.swift
[187/321] Compiling Crypto Cipher.swift
[188/321] Compiling Crypto Nonces.swift
[189/321] Compiling Crypto ASN1.swift
[190/321] Compiling Crypto ASN1Any.swift
[191/321] Compiling Crypto ASN1BitString.swift
[192/321] Compiling Crypto ASN1Boolean.swift
[193/321] Compiling Crypto ASN1Identifier.swift
[194/321] Compiling Crypto ASN1Integer.swift
[195/321] Compiling Crypto ASN1Null.swift
[196/321] Compiling Crypto ASN1OctetString.swift
[197/321] Compiling Crypto ASN1Strings.swift
[198/321] Compiling Crypto ArraySliceBigint.swift
[199/321] Compiling Crypto GeneralizedTime.swift
[200/321] Compiling Crypto ObjectIdentifier.swift
[201/321] Compiling Crypto ECDSASignature.swift
[202/321] Compiling Crypto PEMDocument.swift
[203/321] Compiling Crypto PKCS8PrivateKey.swift
[204/321] Compiling Crypto SEC1PrivateKey.swift
[205/321] Compiling Crypto SubjectPublicKeyInfo.swift
[206/321] Compiling Crypto CryptoError_boring.swift
[207/321] Compiling Crypto MACFunctions.swift
[208/321] Compiling Crypto MessageAuthenticationCode.swift
[209/321] Compiling Crypto AES.swift
[210/321] Compiling Crypto ECDSASignature_boring.swift
[211/321] Compiling Crypto ECDSA_boring.swift
[212/321] Compiling Crypto EdDSA_boring.swift
[213/321] Compiling Crypto MLDSA_boring.swift
[214/321] Compiling Crypto MLDSA_wrapper.swift
[215/321] Compiling Crypto ECDSA.swift
[216/321] Compiling Crypto Ed25519.swift
[217/321] Compiling Crypto MLDSA.swift
[218/321] Compiling Crypto Signature.swift
[219/321] Compiling Crypto CryptoKitErrors_boring.swift
[220/321] Compiling Crypto Optional+withUnsafeBytes_boring.swift
[221/321] Compiling Crypto RNG_boring.swift
[222/321] Compiling Crypto SafeCompare_boring.swift
[223/321] Compiling Crypto Zeroization_boring.swift
[224/321] Compiling Crypto _CryptoModuleAnchor.swift
[225/321] Compiling Crypto PrettyBytes.swift
[226/321] Compiling Crypto SafeCompare.swift
[227/321] Compiling Crypto SecureBytes.swift
[228/321] Compiling Crypto Zeroization.swift
[229/321] Compiling Crypto resource_bundle_accessor.swift
[230/328] Compiling Clocks _AsyncTimerSequence.swift
[231/328] Compiling Clocks SwiftUI.swift
[232/328] Compiling Clocks TestClock.swift
[233/328] Compiling Clocks AnyClock.swift
[234/328] Compiling Clocks ImmediateClock.swift
[235/328] Compiling Clocks Lock.swift
[278/328] Emitting module Clocks
[285/330] Compiling Clocks Timer.swift
[286/330] Compiling Clocks UnimplementedClock.swift
[287/330] Emitting module CustomDump
[288/358] Compiling CustomDump ExpectDifference.swift
[289/358] Compiling CustomDump ExpectNoDifference.swift
[290/358] Compiling CustomDump AnyType.swift
[291/358] Compiling CustomDump CollectionDifference.swift
[292/358] Compiling CustomDump Identifiable.swift
[293/358] Compiling CustomDump Mirror.swift
[294/358] Compiling CustomDump String.swift
[295/358] Compiling CustomDump Unordered.swift
[296/358] Compiling CustomDump XCTAssertDifference.swift
[297/358] Compiling CustomDump XCTAssertNoDifference.swift
[298/358] Compiling Helpers HTTPRequest.swift
[299/358] Compiling Helpers HTTPResponse.swift
[300/358] Compiling Helpers LoggerInterceptor.swift
[301/358] Compiling Helpers RetryRequestInterceptor.swift
[302/358] Compiling Helpers JWT.swift
[303/358] Compiling Helpers OSLogSupabaseLogger.swift
[304/358] Compiling Helpers SupabaseLogger.swift
[308/358] Compiling Helpers AnyJSON+Codable.swift
[309/358] Compiling Helpers AnyJSON.swift
[310/358] Compiling Helpers AsyncValueSubject.swift
[311/358] Compiling Helpers Base64URL.swift
[312/358] Compiling Helpers Codable.swift
[313/358] Compiling Helpers DateFormatter.swift
[314/358] Compiling Helpers EventEmitter.swift
[315/358] Compiling Helpers FoundationExtensions.swift
[316/358] Compiling Helpers HTTPClient.swift
[317/358] Compiling Helpers HTTPFields.swift
[318/360] Emitting module SnapshotTestingCustomDump
[319/360] Compiling SnapshotTestingCustomDump CustomDump.swift
[320/360] Emitting module Helpers
[338/368] Compiling Helpers HTTPError.swift
[339/368] Compiling Helpers PostgrestError.swift
[340/368] Compiling Helpers Task+withTimeout.swift
[341/368] Compiling Helpers TaskLocalHelpers.swift
[342/368] Compiling Helpers URLSession+AsyncAwait.swift
[343/368] Compiling Helpers Version.swift
[344/368] Compiling Helpers _Clock.swift
[345/368] Compiling Helpers _HTTPClient.swift
error: emit-module command failed with exit code 1 (use -v to see invocation)
[346/403] Emitting module RealtimeV3
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[347/415] Emitting module Storage
[348/419] Compiling RealtimeV3 Heartbeater.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[349/419] Compiling RealtimeV3 InflightPush.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[350/419] Compiling RealtimeV3 JoinPayload.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[351/419] Compiling RealtimeV3 RefGenerator.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[352/419] Compiling RealtimeV3 SystemEventPayload.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[353/419] Compiling RealtimeV3 JSONValue.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[354/419] Compiling RealtimeV3 LifecycleObserver.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[355/419] Compiling RealtimeV3 LifecyclePolicy.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[356/419] Compiling RealtimeV3 RealtimeLogger.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[357/419] Compiling RealtimeV3 PhoenixMessage.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[358/419] Compiling RealtimeV3 ChangeRegistration.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[359/419] Compiling RealtimeV3 RealtimePostgresFilterValue.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:23:26: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
21 | 
22 |   private let heartbeat: Duration
23 |   private let clock: any Clock<Duration> & Sendable
   |                          `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
24 |   private let beat: Beat
25 |   private let onConnectionLost: OnConnectionLost

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[360/419] Compiling RealtimeV3 Channel+Broadcast.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[361/419] Compiling RealtimeV3 Channel+Postgres.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[362/419] Compiling RealtimeV3 Channel+Presence.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[363/419] Compiling RealtimeV3 Channel+Routing.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[364/419] Compiling RealtimeV3 Channel.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[365/419] Compiling RealtimeV3 ChannelHost.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[366/419] Compiling RealtimeV3 ChannelOptions.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[367/419] Compiling RealtimeV3 ChannelState.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[368/419] Compiling Storage StorageTransferTask.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[369/419] Compiling Storage TUSUploadEngine.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[370/419] Compiling Storage Types.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[371/419] Compiling Storage UploadSource.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[372/419] Compiling RealtimeV3 ConnectionStatusBroadcaster.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Channel.swift:598:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
596 |     _ events: AsyncStream<ChannelEvent>,
597 |     timeout: Duration,
598 |     clock: any Clock<Duration> & Sendable
    |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
599 |   ) async throws(RealtimeError) {
600 |     let outcome: Result<Void, RealtimeError> = await withTaskGroup(

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.
[373/419] Compiling RealtimeV3 UntypedFilter.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[374/419] Compiling RealtimeV3 Realtime+FrameRouting.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[375/419] Compiling RealtimeV3 Realtime+Heartbeat.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[376/419] Compiling RealtimeV3 Realtime+Push.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[377/419] Compiling RealtimeV3 Realtime+Reconnection.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[378/419] Compiling RealtimeV3 Realtime.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[379/419] Compiling RealtimeV3 RealtimeError.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
55 | 
56 |   /// Additional HTTP headers sent with the WebSocket upgrade request.

/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Internal/Heartbeater.swift:29:16: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
27 |   init(
28 |     heartbeat: Duration,
29 |     clock: any Clock<Duration> & Sendable,
   |                `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
30 |     beat: @escaping Beat,
31 |     onConnectionLost: @escaping OnConnectionLost
[380/419] Compiling RealtimeV3 RealtimeV3.swift
/Users/runner/work/supabase-swift/supabase-swift/Sources/RealtimeV3/Configuration.swift:54:25: error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a protocol-constrained type
52 | 
53 |   /// Clock used for timers and scheduling. Default: `ContinuousClock`.
54 |   public var clock: any Clock<Duration> & Sendable = ContinuousClock()
   |                         `- error: non-protocol, non-class type 'Clock<Duration>' cannot be used within a ...*[Comment body truncated]*

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Realtime Work related to realtime package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants