@fishjam-cloud/react-client 0.28.3 → 0.30.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"useCustomSourceManager.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useCustomSourceManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAsC,MAAM,0BAA0B,CAAC;AAG/G,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,KAAK,wBAAwB,GAAG;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAC;CAChE,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,aAAa,EACb,UAAU,EACV,MAAM,GACP,EAAE,wBAAwB,GAAG,mBAAmB,CA8GhD"}
1
+ {"version":3,"file":"useCustomSourceManager.d.ts","sourceRoot":"","sources":["../../../src/hooks/internal/useCustomSourceManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAsC,MAAM,0BAA0B,CAAC;AAG/G,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,KAAK,wBAAwB,GAAG;IAC9B,aAAa,EAAE,aAAa,CAAC;IAC7B,UAAU,EAAE,UAAU,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAC;CAChE,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,aAAa,EACb,UAAU,EACV,MAAM,GACP,EAAE,wBAAwB,GAAG,mBAAmB,CAkKhD"}
@@ -1,7 +1,17 @@
1
1
  import { TrackTypeError } from "@fishjam-cloud/ts-client";
2
- import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
3
  export function useCustomSourceManager({ fishjamClient, peerStatus, logger, }) {
4
4
  const [sources, setSources] = useState({});
5
+ // setStream reads the current sources synchronously (to diff against the old stream and to
6
+ // remove stale tracks), but must stay referentially stable so consumers can safely depend on
7
+ // it in effects. Reading through a ref keeps it out of the useCallback deps.
8
+ const sourcesRef = useRef(sources);
9
+ sourcesRef.current = sources;
10
+ // Replacing a source's stream issues two setStream calls in the same tick (unpublish the old,
11
+ // publish the new). Run concurrently they would read the same snapshot and race to remove the
12
+ // same track IDs — and when the publish call loses that race, the new stream is never
13
+ // published. This chain serializes the calls instead.
14
+ const setStreamQueue = useRef(Promise.resolve());
5
15
  const pendingSources = useMemo(() => Object.entries(sources).filter(([_, source]) => source.trackIds === undefined), [sources]);
6
16
  const getDisplayName = useCallback(() => {
7
17
  const name = fishjamClient.getLocalPeer()?.metadata?.peer?.displayName;
@@ -50,36 +60,67 @@ export function useCustomSourceManager({ fishjamClient, peerStatus, logger, }) {
50
60
  await Promise.all(promises);
51
61
  }, [fishjamClient]);
52
62
  const getSource = useCallback((sourceId) => sources[sourceId], [sources]);
53
- const setStream = useCallback(async (sourceId, stream) => {
54
- const oldSource = sources[sourceId];
63
+ // Updates both the state (what consumers render) and the ref (what queued setStream calls
64
+ // read synchronously, before React re-renders).
65
+ const updateSources = useCallback((update) => {
66
+ sourcesRef.current = update(sourcesRef.current);
67
+ setSources(update);
68
+ }, []);
69
+ const applySetStream = useCallback(async (sourceId, stream) => {
70
+ const oldSource = sourcesRef.current[sourceId];
55
71
  if (stream === oldSource?.stream)
56
72
  return;
57
73
  if (oldSource?.trackIds)
58
74
  await removeTracks(oldSource.trackIds);
59
75
  if (stream !== null) {
60
- setSources((old) => ({ ...old, [sourceId]: { stream } }));
61
- return;
76
+ updateSources((old) => ({ ...old, [sourceId]: { stream } }));
62
77
  }
63
- if (!oldSource)
64
- return;
65
- setSources((old) => Object.fromEntries(Object.entries(old).filter(([id, _]) => id !== sourceId)));
66
- }, [sources, removeTracks]);
78
+ else if (oldSource) {
79
+ updateSources((old) => Object.fromEntries(Object.entries(old).filter(([id]) => id !== sourceId)));
80
+ }
81
+ }, [removeTracks, updateSources]);
82
+ const setStream = useCallback((sourceId, stream) => {
83
+ const run = setStreamQueue.current.then(() => applySetStream(sourceId, stream));
84
+ // Chain a never-rejecting link so one failed call cannot poison the queue; the caller
85
+ // still observes failures through the returned promise.
86
+ setStreamQueue.current = run.catch(() => undefined);
87
+ return run;
88
+ }, [applySetStream]);
67
89
  useEffect(() => {
68
90
  const onConnected = async () => {
69
91
  if (pendingSources.length === 0)
70
92
  return;
71
- const patch = Object.fromEntries(await Promise.all(pendingSources.map(async ([id, source]) => [id, await startStreaming(source)])));
72
- setSources((old) => ({ ...old, ...patch }));
93
+ const results = await Promise.all(pendingSources.map(async ([id, source]) => [id, await startStreaming(source)]));
94
+ // While the tracks were being added, setStream may have unpublished the source or replaced
95
+ // its stream. Record track IDs only where the entry is still the one we started streaming
96
+ // (same stream, still no track IDs) — anything else must not be patched (it would resurrect
97
+ // an unpublished source or attach the IDs to a different stream), and the tracks we just
98
+ // added for it are orphans to unpublish again.
99
+ const isStillCurrent = ([id, started]) => {
100
+ const current = sourcesRef.current[id];
101
+ return current !== undefined && current.stream === started.stream && current.trackIds === undefined;
102
+ };
103
+ const patch = results.filter(isStillCurrent);
104
+ const orphans = results.filter((result) => !isStillCurrent(result));
105
+ if (patch.length > 0) {
106
+ updateSources((old) => ({ ...old, ...Object.fromEntries(patch) }));
107
+ }
108
+ for (const [, started] of orphans) {
109
+ if (started.trackIds)
110
+ await removeTracks(started.trackIds);
111
+ }
73
112
  };
74
113
  const onDisconnected = () => {
75
- setSources((old) => Object.fromEntries(Object.entries(old).map(([id, source]) => [id, { ...source, trackIds: undefined }])));
114
+ updateSources((old) => Object.fromEntries(Object.entries(old).map(([id, source]) => [id, { ...source, trackIds: undefined }])));
76
115
  };
116
+ // addTrack can reject for reasons other than TrackTypeError (e.g. a disconnect mid-add);
117
+ // surface it instead of leaving an unhandled rejection.
77
118
  if (peerStatus === "connected")
78
- onConnected();
119
+ onConnected().catch((error) => logger.error("Failed to publish custom sources", error));
79
120
  fishjamClient.on("disconnected", onDisconnected);
80
121
  return () => {
81
122
  fishjamClient.off("disconnected", onDisconnected);
82
123
  };
83
- }, [pendingSources, fishjamClient, peerStatus, startStreaming]);
124
+ }, [pendingSources, fishjamClient, peerStatus, startStreaming, removeTracks, updateSources, logger]);
84
125
  return { setStream, getSource };
85
126
  }
@@ -1,5 +1,7 @@
1
1
  /**
2
2
  * This hook can register/deregister a custom MediaStream with Fishjam.
3
+ *
4
+ * @param sourceId - Stable id identifying this custom source.
3
5
  * @group Hooks
4
6
  */
5
7
  export declare function useCustomSource<T extends string>(sourceId: T): {
@@ -1 +1 @@
1
- {"version":3,"file":"useCustomSource.d.ts","sourceRoot":"","sources":["../../src/hooks/useCustomSource.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC;IAczD;;;OAGG;2BARS,WAAW,GAAG,IAAI;IAU9B;;OAEG;;EAGN"}
1
+ {"version":3,"file":"useCustomSource.d.ts","sourceRoot":"","sources":["../../src/hooks/useCustomSource.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,QAAQ,EAAE,CAAC;IAczD;;;OAGG;2BARS,WAAW,GAAG,IAAI;IAU9B;;OAEG;;EAGN"}
@@ -2,6 +2,8 @@ import { useCallback, useContext, useMemo } from "react";
2
2
  import { CustomSourceContext } from "../contexts/customSource";
3
3
  /**
4
4
  * This hook can register/deregister a custom MediaStream with Fishjam.
5
+ *
6
+ * @param sourceId - Stable id identifying this custom source.
5
7
  * @group Hooks
6
8
  */
7
9
  export function useCustomSource(sourceId) {
@@ -1 +1 @@
1
- {"version":3,"file":"usePeers.d.ts","sourceRoot":"","sources":["../../src/hooks/usePeers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,QAAQ,EAAwC,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAMvH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAW,MAAM,iBAAiB,CAAC;AAE3E;;;;GAIG;AACH,MAAM,MAAM,cAAc,CAAC,YAAY,EAAE,cAAc,EAAE,CAAC,SAAS,KAAK,GAAG,KAAK,IAAI;IAClF,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,WAAW,CAAC,EAAE,CAAC,CAAC;IAChB,eAAe,CAAC,EAAE,CAAC,CAAC;IACpB,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACvB,iBAAiB,EAAE,CAAC,EAAE,CAAC;CACxB,CAAC;AAuEF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA0BrG;;;OAGG;IACH;;OAEG;IACH;;;;OAIG;;IAEH;;;;OAIG;yCAvBQ,MAAM,EAAE,WAAW,OAAO;EA0BxC"}
1
+ {"version":3,"file":"usePeers.d.ts","sourceRoot":"","sources":["../../src/hooks/usePeers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,QAAQ,EAIR,OAAO,EACR,MAAM,0BAA0B,CAAC;AAMlC,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAW,MAAM,iBAAiB,CAAC;AAE3E;;;;GAIG;AACH,MAAM,MAAM,cAAc,CAAC,YAAY,EAAE,cAAc,EAAE,CAAC,SAAS,KAAK,GAAG,KAAK,IAAI;IAClF,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,QAAQ,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAClD,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,WAAW,CAAC,EAAE,CAAC,CAAC;IAChB,eAAe,CAAC,EAAE,CAAC,CAAC;IACpB,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,qBAAqB,CAAC,EAAE,CAAC,CAAC;IAC1B,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACvB,iBAAiB,EAAE,CAAC,EAAE,CAAC;CACxB,CAAC;AA2EF;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IA0BrG;;;OAGG;IACH;;OAEG;IACH;;;;OAIG;;IAEH;;;;OAIG;yCAvBQ,MAAM,EAAE,WAAW,OAAO;EA0BxC"}
@@ -13,6 +13,8 @@ function trackContextToTrack(track) {
13
13
  function trackContextToRemoteTrack(track, fishjamClient) {
14
14
  return {
15
15
  ...trackContextToTrack(track),
16
+ encoding: track.encoding,
17
+ encodingReason: track.encodingReason,
16
18
  setReceivedQuality: (encoding) => {
17
19
  fishjamClient.setTargetTrackEncoding(track.trackId, encoding);
18
20
  },
@@ -1,4 +1,4 @@
1
- import type { DataCallback, DataChannelOptions, SimulcastConfig, TrackMetadata, Variant } from "@fishjam-cloud/ts-client";
1
+ import type { DataCallback, DataChannelOptions, EncodingReason, SimulcastConfig, TrackMetadata, Variant } from "@fishjam-cloud/ts-client";
2
2
  export type InitializeDevicesStatus = "initialized" | "failed" | "initialized_with_errors" | "already_initialized";
3
3
  export type InitializeDevicesResult = {
4
4
  status: InitializeDevicesStatus;
@@ -18,6 +18,8 @@ export type Track = {
18
18
  track: MediaStreamTrack | null;
19
19
  };
20
20
  export type RemoteTrack = Track & {
21
+ encoding?: Variant;
22
+ encodingReason?: EncodingReason;
21
23
  setReceivedQuality: (quality: Variant) => void;
22
24
  };
23
25
  export type MiddlewareResult = {
@@ -1 +1 @@
1
- {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/types/public.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/types/public.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fishjam-cloud/react-client",
3
- "version": "0.28.3",
3
+ "version": "0.30.0-rc.0",
4
4
  "description": "React client library for Fishjam",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Fishjam Team",
@@ -32,9 +32,10 @@
32
32
  }
33
33
  },
34
34
  "scripts": {
35
- "build": "tsc",
35
+ "build": "tsc -p tsconfig.build.json",
36
36
  "e2e": "NODE_OPTIONS=--dns-result-order=ipv4first playwright test",
37
37
  "test": "vitest run",
38
+ "tsc": "tsc --noEmit",
38
39
  "docs": "typedoc src src/experimental",
39
40
  "format": "prettier --write . --ignore-path ./.eslintignore",
40
41
  "format:check": "prettier --check . --ignore-path ./.eslintignore",
@@ -55,6 +56,8 @@
55
56
  "@types/react": "19.1.0",
56
57
  "fake-mediastreamtrack": "^2.0.0",
57
58
  "jsdom": "^26.0.0",
59
+ "react": "19.1.0",
60
+ "react-dom": "19.1.0",
58
61
  "typed-emitter": "^2.1.0",
59
62
  "typedoc": "^0.28.2",
60
63
  "typedoc-plugin-mdn-links": "^5.0.1",
@@ -62,7 +65,7 @@
62
65
  "vitest": "^3.1.1"
63
66
  },
64
67
  "dependencies": {
65
- "@fishjam-cloud/ts-client": "0.28.3",
68
+ "@fishjam-cloud/ts-client": "0.30.0-rc.0",
66
69
  "events": "3.3.0",
67
70
  "lodash.isequal": "4.5.0"
68
71
  },
package/readme.md CHANGED
@@ -16,11 +16,7 @@ There is also [API documentation](https://docs.fishjam.io/api/web/) available.
16
16
 
17
17
  # Examples
18
18
 
19
- There are [few example apps](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client#examples-for-fishjam-client) that shows how to use Fishjam SDKs and service.
20
-
21
- - [Fishjam Chat](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client/fishjam-chat) - example video chat app
22
- - [minimal-react](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client/minimal-react) - minimal example that shows how to connect and share your screen
23
- - [broadcast](https://github.com/fishjam-cloud/web-client-sdk/tree/main/examples/react-client/broadcast) - minimal example showing how to consume a broadcast stream
19
+ Check out the [examples repository](https://github.com/fishjam-cloud/examples) for apps demonstrating the Fishjam SDKs, such as the [minimal-react example](https://github.com/fishjam-cloud/examples/tree/main/web-react/minimal-react) showing how to connect and share your screen.
24
20
 
25
21
  ## License
26
22
 
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=useCurrentCallback.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useCurrentCallback.spec.d.ts","sourceRoot":"","sources":["../../src/tests/useCurrentCallback.spec.ts"],"names":[],"mappings":""}
@@ -1,49 +0,0 @@
1
- import { renderHook } from "@testing-library/react";
2
- import { describe, expect, it, vi } from "vitest";
3
- import { useCurrentCallback } from "../hooks/internal/useCurrentCallback";
4
- describe("useCurrentCallback", () => {
5
- it("returns a stable function reference across re-renders", () => {
6
- const { result, rerender } = renderHook((handler) => useCurrentCallback(handler), {
7
- initialProps: () => undefined,
8
- });
9
- const firstRef = result.current;
10
- rerender(() => undefined);
11
- rerender(() => undefined);
12
- expect(result.current).toBe(firstRef);
13
- });
14
- it("invokes the latest handler when called after a re-render", () => {
15
- const first = vi.fn();
16
- const second = vi.fn();
17
- const { result, rerender } = renderHook((handler) => useCurrentCallback(handler), {
18
- initialProps: first,
19
- });
20
- result.current();
21
- expect(first).toHaveBeenCalledTimes(1);
22
- expect(second).not.toHaveBeenCalled();
23
- rerender(second);
24
- result.current();
25
- expect(first).toHaveBeenCalledTimes(1);
26
- expect(second).toHaveBeenCalledTimes(1);
27
- });
28
- it("forwards arguments and returns the handler's value", () => {
29
- const handler = vi.fn((a, b) => a + b);
30
- const { result } = renderHook(() => useCurrentCallback(handler));
31
- const sum = result.current(2, 3);
32
- expect(handler).toHaveBeenCalledWith(2, 3);
33
- expect(sum).toBe(5);
34
- });
35
- it("the wrapper captured before a re-render still calls the latest handler", () => {
36
- const first = vi.fn(() => "first");
37
- const second = vi.fn(() => "second");
38
- const { result, rerender } = renderHook((handler) => useCurrentCallback(handler), {
39
- initialProps: first,
40
- });
41
- // Simulates a consumer capturing the reference (e.g. inside a useEffect
42
- // closure) before the handler closure has changed.
43
- const captured = result.current;
44
- rerender(second);
45
- expect(captured()).toBe("second");
46
- expect(second).toHaveBeenCalledTimes(1);
47
- expect(first).not.toHaveBeenCalled();
48
- });
49
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=useHandleTrackEnd.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useHandleTrackEnd.spec.d.ts","sourceRoot":"","sources":["../../src/tests/useHandleTrackEnd.spec.ts"],"names":[],"mappings":""}
@@ -1,14 +0,0 @@
1
- import { renderHook } from "@testing-library/react";
2
- import { FakeMediaStreamTrack } from "fake-mediastreamtrack";
3
- import { describe, expect, it, vi } from "vitest";
4
- import { useHandleTrackEnd } from "../hooks/internal/devices/useHandleTrackEnd";
5
- describe("useHandleTrackEnd", () => {
6
- it("should clear stream on track ended event", () => {
7
- const clearStream = vi.fn();
8
- const track = new FakeMediaStreamTrack({ kind: "it literally doesn't matter" });
9
- renderHook(() => useHandleTrackEnd(track, clearStream));
10
- expect(track.onended).toBeDefined();
11
- track.remoteStop();
12
- expect(clearStream).toHaveBeenCalled();
13
- });
14
- });