feat(realtime): use phoenix's js lib inside realtime-js#2119
Merged
mandarini merged 74 commits intosupabase:masterfrom Mar 16, 2026
Merged
feat(realtime): use phoenix's js lib inside realtime-js#2119mandarini merged 74 commits intosupabase:masterfrom
mandarini merged 74 commits intosupabase:masterfrom
Conversation
…pabase phonix git dep (#3) * feat(realtime): add submodule for phoenix, change deps * fix(realtime): add temporary types since types/phoenix was removed * feat(realtime): use phoenix consts * fix(realtime): rename vitest extension * fix(realtime): cannot import form path * feat(realtime): add phoenixAdapter with basic stuff * fix(realtime): add path to compile project * feat(realtime): make presence use phoenixAdapter * feat(realtime): use github path instead of git submodules * fix(realtime): update phoenix github dependency * fix(realtime): properly export constatns with types form phoenix * fix(realtime): use proper types in phoenixAdapter, fix package-lock file * fix(realtime): small changes * fix(realtime): add and remove comments * fix(realtime): use proper url string * fix(realtime): better imports, fix constatns * fix(realtime): point to branch, fix commnet place * fix(realtime): change config file extension * feat(realtime): update phoenix dep, remove ts-ignore * fix(realtime): fix config extension * fix(realtime): generic helper function in phoenixAdapter * feat(realtime): update dep to supabase/phoenix * fix(realtime): remove unuse function * feat(realtime): better presence translation code, split into files * fix(realtime): fix cloneDeep function * fix(realtime): change privarte to internal in docs
Removed tests check behavior that is also checked in phoenix codebase.
* feat(realtime): add phoenixAdapter, refactor RealtimePresence, use supabase phonix git dep (#3) * feat(realtime): add submodule for phoenix, change deps * fix(realtime): add temporary types since types/phoenix was removed * feat(realtime): use phoenix consts * fix(realtime): rename vitest extension * fix(realtime): cannot import form path * feat(realtime): add phoenixAdapter with basic stuff * fix(realtime): add path to compile project * feat(realtime): make presence use phoenixAdapter * feat(realtime): use github path instead of git submodules * fix(realtime): update phoenix github dependency * fix(realtime): properly export constatns with types form phoenix * fix(realtime): use proper types in phoenixAdapter, fix package-lock file * fix(realtime): small changes * fix(realtime): add and remove comments * fix(realtime): use proper url string * fix(realtime): better imports, fix constatns * fix(realtime): point to branch, fix commnet place * fix(realtime): change config file extension * feat(realtime): update phoenix dep, remove ts-ignore * fix(realtime): fix config extension * fix(realtime): generic helper function in phoenixAdapter * feat(realtime): update dep to supabase/phoenix * fix(realtime): remove unuse function * feat(realtime): better presence translation code, split into files * fix(realtime): fix cloneDeep function * fix(realtime): change privarte to internal in docs * feat(realtime): move PoC for RealtimeClient and RealtimeChannel * fix(realtime): fix phoenixAdapter, make realtime work * fix(realtime): clear code, add types, make consistent * fix(realtime): cleaning, making supabase tests work * fix(realtime): more cleaning and checking * fix(realtime): import directly from pheonix, use type instead of interface * fix(realtime): use functions directly from channelAdapter * fix(realtime): use websocket factory * fix(realtime): remove infered types, make trigger more private, small fixes * fix(realtime): add ts-ignore for connectionState
* fix(realtime): fix joinedOnce * fix(realtime): fix conn
* fix(realtime): update types from phoenix * fix(realtime): fix type import/export * fix(realtime): cleaner types
* fix(realtime): better error message on connect * fix(realtime): remove unused method * feat(realtime): make disconnect and async function to wait for the end of phoenix disconnect * fix(realtime): remove not necessary testing stuff * fix(realtime): fix conn in test * fix(realtime): test websocket factory in different way * fix(realtime): disconnect is async * fix(realtime): better websocket server mocking * wip * fix(realtime): update types from phoenix * fix(realtime): fix type import/export * Revert "wip" This reverts commit d2e4342. * fix(realtime): fix lifecycle tests * fix(realtime): remove unnecessary lines in test * fix(realtime): cleanup after tests with testClient * fix(realtime): post merge fix
* fix(realtime): update types from phoenix * fix(realtime): fix type import/export * fix(realtime): first test fixed * fix(realtime): fix second test * fix(realtime): add dataSpy to auth tests, better auth helpers * fix(realtime): fix token setting and updates tests * fix(realtime): fix som auth tests by using helpers * fix(realtime): auth test more fixes * fix(realtime): add reconnect test for auth * feat(realtime): add shuffle for tests * fix(realtime): fix sendHeartbeat * fix(realtime): override heartbeatCallback with auth, use phoenix heartbeatCallback * fix(realtime): small changes * fix(realtime): heartbeat changes * fix(realtime): better test helpers. fix auth tests * fix(realtime): cr changes
* feat(realtime): add return values in adapters * fix(realtime): fix bindings filter, remove return type in realtime
* fix(realtime): better setup * fix(realtime): fix lifecycle test * fix(realtime): fix resilience tests * fix(realtime): cleaning in error tests * fix(realtime): remove tests which are in phoenix
…ore/merge-master chore(realtime): merge master
* fix(realtime): fix setup helper with passing apikey and params * fix(realtime): fix config tests * feat(realtime): add test for choosing correct encoder * fix(realtime): undo removing test
* fix(realtime): fix first auth test * fix(realtime): cleanup and add default phx join payload * fix(realtime): fix auth resubscribe tests * fix(realtime): refactor test to look ok
* fix(realtime): test setups * fix(realtime): fix presence state management * fix(realtime): fix format of onJoin and onLeave * fix(realtime): fix message filtering tests, add new test case * fix(realtime): add on typing, parse currentPresences when passed to triggers * fix(realtime): fix presence helper tests * fix(realtime): fix presence tests * fix(realtime): import as type
* fix(realtime): realtimechannel constructor tests * fix(realtime): fix lifecycle tests * feat(realtime): add getCallback method * fix(realtime): fix constant CHANNEL_STATES * fix(realtime): better typing of encode, decode and logger * fix(realtime): better typing in RealtimeChannel, remove unused import, fix subscribe callback * fix(realtime): throw error on adding presence callback after subscribe * fix(realtime): remove unused method * fix(realtime): example lock restored * fix(realtime): use expect instead of assert
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/core/realtime-js/src/RealtimeChannel.ts`:
- Around line 352-353: The call to this.unsubscribe() in the error path is not
awaited so any rejection will be swallowed; change it to await
this.unsubscribe() inside the async handler (or append .catch(...) to log the
failure) before setting this.state = CHANNEL_STATES.errored so unsubscribe
errors are surfaced or at least logged; update the method that contains
this.unsubscribe() (the RealtimeChannel unsubscribe/error handling branch) to
either await the promise or handle rejection with a logger (e.g.,
this.unsubscribe().catch(err => this.logger.error(...))).
---
Duplicate comments:
In `@packages/core/realtime-js/src/RealtimeChannel.ts`:
- Line 175: The public field bindings on class RealtimeChannel (bindings:
Record<string, Binding[]>) is undocumented; add a concise JSDoc comment above
the bindings declaration describing its purpose, shape, and intended visibility
(e.g., "map of event names to listener bindings") or, if this is not part of the
public API, mark it as `@internal` in the JSDoc and explain why consumers should
not use it; ensure the comment mentions the Binding type and any invariants
(e.g., ownership/lifecycle) so readers understand how to interact with or avoid
the field.
In `@packages/core/realtime-js/src/RealtimeClient.ts`:
- Around line 116-181: The proxy getters on RealtimeClient (endPoint, timeout,
transport, heartbeatCallback, heartbeatIntervalMs, heartbeatTimer,
pendingHeartbeatRef, reconnectTimer, vsn, encode, decode, reconnectAfterMs,
sendBuffer, stateChangeCallbacks) are missing JSDoc visibility; if these are not
part of the public API mark each getter with `@internal` JSDoc (or add brief
public JSDoc if they should be public) so the intent is clear and the TypeDoc
output is correct; update the comment block above each getter (or a shared block
above the group) to include `@internal` and a one-line description, and ensure the
stateChangeCallbacks return-type annotation remains accurate.
In `@packages/core/realtime-js/test/RealtimeClient.resilience.test.ts`:
- Around line 6-14: The resilience tests manipulate reconnection and heartbeat
timing but currently run with real timers, which can cause flakiness; update the
test setup to enable fake timers in the beforeEach where testClient is
initialized (call the test runner's fake timer API, e.g., vi.useFakeTimers or
jest.useFakeTimers) and restore real timers in afterEach alongside
testClient.cleanup (e.g., vi.useRealTimers or jest.useRealTimers), and adjust
any timing-based assertions in tests to use the timer-control helpers
(advanceTimersByTime/advanceTimersToNextTimer) to drive reconnection/heartbeat
behavior deterministically for functions/setupRealtimeTest and the surrounding
beforeEach/afterEach.
mandarini
reviewed
Feb 17, 2026
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/core/realtime-js/src/phoenix/presenceAdapter.ts`:
- Around line 17-37: The onJoin/onLeave handlers emit raw Phoenix metas
(newPresence['metas'] / leftPresence['metas']) while transformState normalizes
to presence_ref, causing inconsistent payload shapes; update the handlers in
presence.onJoin and presence.onLeave to map/normalize each meta to the same
shape used by transformState (replace phx_ref with presence_ref and preserve
other fields) before passing currentPresences/newPresences/leftPresences to
channel.getChannel().trigger so join/leave events match transformState output
(use parseCurrentPresences and the same normalization routine applied in
transformState).
There was a problem hiding this comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@packages/core/realtime-js/src/phoenix/presenceAdapter.ts`:
- Around line 96-116: transformState currently mutates Phoenix's presence metas
by deleting phx_ref and phx_ref_prev, which corrupts Phoenix internal state used
by onLeavePayload (via parseCurrentPresences). Change transformState to return
new objects without mutation (e.g. for each meta create a new object: extract
phx_ref and phx_ref_prev and return { ...rest, presence_ref: phx_ref }) so phx_*
fields are not deleted from the original metas; ensure parseCurrentPresences
continues to call transformState and does not pass through live references.
* fix(realtime): use expect.any, use fake timers * fix(realtime): small changes * fix(realtime): format
* fix(postgrest): enforce type safety for table and view names in from() method (supabase#2058) * docs(auth): clarify updateUserById does not trigger client listeners (supabase#2114) * fix(auth): resolve Firefox content script Promise.then() security errors in locks (supabase#2112) * build(deps): bump qs from 6.14.1 to 6.14.2 in the npm_and_yarn group across 1 directory (supabase#2118) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(release): version 2.96.0 changelogs (supabase#2121) Co-authored-by: supabase-releaser[bot] <supabase-releaser[bot]@users.noreply.github.com> * docs(supabase): document UNUSED_EXTERNAL_IMPORT build warning as false positive (supabase#2122) * feat(auth): add skipAutoInitialize option to prevent constructor auto-init (supabase#2123) * chore(release): version 2.97.0 changelogs (supabase#2124) Co-authored-by: supabase-releaser[bot] <supabase-releaser[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Vaibhav <117663341+7ttp@users.noreply.github.com> Co-authored-by: Katerina Skroumpelou <mandarini@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: supabase-releaser[bot] <223506987+supabase-releaser[bot]@users.noreply.github.com> Co-authored-by: supabase-releaser[bot] <supabase-releaser[bot]@users.noreply.github.com>
This reverts commit 3c4518c.
…master fix(realtime): wrong merge of master fixed
mandarini
reviewed
Feb 20, 2026
mandarini
reviewed
Mar 16, 2026
mandarini
approved these changes
Mar 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🔍 Description
Make
realtime-jsusephoenixjs library to handle most of the logic.What changed?
Most of the code now uses adapters to use phoenix API
Why was this change needed?
It shifts the responsibility for creating, handling, and cleaning connections and channels to
phoenixjs library. Only Supabase related logic for auth, and bindings filtering/formatting along exposing proper API is contained in therealtime-js🔄 Breaking changes
subscribeafterunsusbcirbe- it wasn't working properly in the original implementationWebSocketimplementation errors will be thrown inconstructor(instead ofconnect) -sincegetWebsocketConstructoris used inRealtimeClient.constructoronwithpresenceafter subscribe will result in error - due to no resubscribe funcitonalityteardownonRealtimeClient.disconnect- now channels are maintaining it's information and when socket is reconnected they keep working (this is the wayphoenixdoes it)onmethod) can takejoinRefas a 3rd parameter📋 Checklist
<type>(<scope>): <description>npx nx formatto ensure consistent code formatting📝 Additional notes
In this PR some tests are removed because they are moved to https://github.com/supabase/phoenix