Skip to content

[spike] tsunami full-context build — review only, do not merge - #583

Draft
MiloszFilimowski wants to merge 26 commits into
tsunami-migrationfrom
spike/tsunami-full
Draft

[spike] tsunami full-context build — review only, do not merge#583
MiloszFilimowski wants to merge 26 commits into
tsunami-migrationfrom
spike/tsunami-full

Conversation

@MiloszFilimowski

Copy link
Copy Markdown
Collaborator

Reference implementation from the Phase A full-context build. Not for merging — extraction happens PR-by-PR per EXTRACTION_MAP.md.

  • react-client fully on tsunami (all hooks are store/controller adapters; old internals deleted)
  • FCE-3030 suite 69/69; single deliberate test change: the FCE-3574 quirk assertion flip in screenShare.spec.ts
  • Consumers: vanilla demo + Angular 20 zoneless example (3-line signal bridge, 34-test behavioral suite)
  • Design notes and verdicts: SPIKE_NOTES.md; commit↔ticket map: EXTRACTION_MAP.md
  • Validated live: fishjam-chat on iOS sim ↔ vanilla web peer, same staging room

…creenShare/useCustomSource

tsunami: ScreenShareController (getDisplayMedia via IDeviceManager, dual-
track publish, ended-listener auto-stop, disconnect teardown, persisted
TracksMiddleware re-applied on restart - fixes FCE-3574); CustomSource-
Controller (queued setSource, pending-publish on join, orphan cleanup,
re-publish after reconnect); ClientState grows screenShare + customSources
slices; client API startScreenShare/stopScreenShare/
setScreenShareTracksMiddleware/setCustomSource.

react-client: ScreenshareContext + CustomSourceContext become store-backed
memo adapters in the provider; useScreenshareManager + useCustomSourceManager
deleted; manager types moved to types/internal.

ONE deliberate test-file change: the FCE-3574 quirk assertion in
screenShare.spec.ts flips per its own documented intent (bug now fixed).
All other specs unaltered; 69/69 green.
utils/track.ts + utils/bandwidth.ts have no non-test importers; provider
logger unused after manager adapters. No ClientState slices added for
dataChannel/bandwidth/VAD - the remaining hooks pass on events+delegation
with no store consumer (FCE-3579 finding: no current consumer, defer).
Extracted from the RFC spike, adapted to the real ClientState (no
speculative slices), plus a remote-video grid driven by getRemoteTracks()
on store notifications. Runs against tsunami sources via vite alias
(no build step); examples/tsunami/* workspace glob added.
Client now reaches all four controllers uniformly (screen-share wrappers
dropped); unused constraint consts, dead trackUtils export, and react-client
legacy device-error machinery deleted. TrackPublisher and snapshot
memoization deliberately kept (verdicts in SPIKE_NOTES).
Found live on the iOS simulator: RN's polyfilled navigator.mediaDevices has
no addEventListener; onDeviceChange now feature-detects and no-ops. Finding
recorded: mobile should eventually inject ReactNativeDeviceManager via a
provider seam instead of inheriting WebDeviceManager.
examples/tsunami/angular: Angular 20 zoneless standalone app on tsunami
sources; store-to-signal bridge is 3 lines; 34-scenario behavioral suite
(7 files) mirroring FCE-3030 with its own signallingClient/mediaDevices
fakes - the cross-framework proof.

Findings applied to tsunami: CustomSourceController no longer emits a
redundant notification on disconnect when nothing was published; sources
now compile clean under noImplicitOverride/noImplicitReturns so consumers
can alias tsunami sources with strict Angular tsconfigs.

Recorded for later: platform-type casts repeat at every web render
boundary (consider a web-narrowed surface); getRemoteTracks() is the one
non-store seam (remote-track ClientState slice when a consumer demands
it); events CJS dep triggers Angular bailout warning.
Connection panel now takes Fishjam ID, Sandbox API URL, room and peer
name - the app mints the peer token and builds the ws url itself
(fishjam-chat model). Values persist in localStorage.
The workspace tsc script emitted js next to sources (tsconfig lacked
noEmit) and a bulk add swept them in; check-only now.
…ulk adds swept them in; noEmit guard now prevents this)
state/peerViews.ts: single bucketing core (deduplicates the byte-identical
local/remote pair) behind explicit localPeerWithTracks / remotePeerWithTracks;
remote views take a narrow RemoteTrackQualitySetter. usePeers is now pure
shape conversion (branded ids + DOM casts). peers.spec unaltered.
ClientState gains dataChannel {status: idle|creating|ready, error};
events map one-update-per-event (disconnected resets status, preserves
error); createDataChannels gains an idle-dedup guard and rejects
DataChannelsNotConnectedError ('Peer is not connected') with the same
object mirrored per FCE-3580; publishData mirrors sync throws and
rethrows. useDataChannel is now a store adapter - the never-removed
dataChannelsError listener leak is gone by construction.
dataChannel.spec unaltered.
VoiceActivityMonitor lives outside the state store (remote activity mirrors
signalling events, local activity polls mic audio level while subscribed).
useVAD becomes a useSyncExternalStore wrapper; useLocalVAD is absorbed.
Angular example switches to the tsunami sandbox/url helpers.
…injection points

An injected manager owns persistence (persistLastDevice is skipped entirely),
which is what lets mobile drop its localStorage polyfill later. clientType
flows through the tsunami config into ts-client, so mobile can stop
constructing a signalling client of its own.
…undary

IDeviceManager grows createMediaStream; the controller exposes a render-ready
stream scoped to the active track (the shared initializeDevices stream never
leaks the other kind's track into a preview), and useCamera/useMicrophone/
useLivestreamStreamer stop calling the MediaStream global. The global now
survives only for the legacy ts-client/webrtc-client core.
Fixes the real classification bug: react-native-webrtc rejects with a
MediaStreamError that is not an Error and names permission denial
SecurityError, which used to surface as UNHANDLED_ERROR. Permission warnings
move from the navigator.mediaDevices monkey-patch onto the actual acquisition
path. getDisplayMedia gains native screen-capture options; onDeviceChange
becomes an honest no-op (the fork never emits devicechange), deleting the
FCE-3689 cast workaround here.
FishjamProvider moves to its own module and declares what mobile is
(clientType 'mobile', ReactNativeDeviceManager) instead of constructing a
signalling client per render. Device acquisition no longer flows through the
fake navigator.mediaDevices.
… else dies

registerGlobals() is gone; globals.ts installs RTCPeerConnection (the
getConfiguration-caching subclass), RTCIceCandidate, and MediaStream from
direct fork imports — the exact set the legacy connection core resolves from
globals. The navigator.mediaDevices fake, the in-memory localStorage, the
EventTarget global, and the getUserMedia permission monkey-patch are deleted.
Breaking for apps that used the removed globals directly (README note).
…ript

tsunami sat at 0.0.0 while every other package tracks 0.29.0, and the release
script's package list omitted it entirely — so each release would have left it
further behind. It stays private:true; that flag is the remaining switch to
flip when it actually goes out.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant