@meshagent/meshagent-react 0.38.2 → 0.38.4

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +17 -1
  2. package/README.md +78 -41
  3. package/dist/cjs/client-toolkits.d.ts +2 -2
  4. package/dist/cjs/client-toolkits.js +143 -10
  5. package/dist/cjs/document-connection-scope.d.ts +7 -12
  6. package/dist/cjs/document-connection-scope.js +88 -82
  7. package/dist/cjs/index.d.ts +3 -2
  8. package/dist/cjs/index.js +3 -2
  9. package/dist/cjs/livekit-client.d.ts +23 -0
  10. package/dist/cjs/livekit-client.js +66 -0
  11. package/dist/cjs/livekit-protocol.d.ts +21 -0
  12. package/dist/cjs/livekit-protocol.js +97 -0
  13. package/dist/cjs/room-connection-scope.d.ts +16 -16
  14. package/dist/cjs/room-connection-scope.js +207 -90
  15. package/dist/cjs/room-participants.d.ts +2 -0
  16. package/dist/cjs/room-participants.js +46 -0
  17. package/dist/esm/client-toolkits.d.ts +2 -2
  18. package/dist/esm/client-toolkits.js +145 -12
  19. package/dist/esm/document-connection-scope.d.ts +7 -12
  20. package/dist/esm/document-connection-scope.js +88 -81
  21. package/dist/esm/index.d.ts +3 -2
  22. package/dist/esm/index.js +3 -2
  23. package/dist/esm/livekit-client.d.ts +23 -0
  24. package/dist/esm/livekit-client.js +61 -0
  25. package/dist/esm/livekit-protocol.d.ts +21 -0
  26. package/dist/esm/livekit-protocol.js +60 -0
  27. package/dist/esm/room-connection-scope.d.ts +16 -16
  28. package/dist/esm/room-connection-scope.js +205 -89
  29. package/dist/esm/room-participants.d.ts +2 -0
  30. package/dist/esm/room-participants.js +43 -0
  31. package/package.json +2 -2
  32. package/dist/cjs/chat.d.ts +0 -33
  33. package/dist/cjs/chat.js +0 -207
  34. package/dist/cjs/file-upload.d.ts +0 -43
  35. package/dist/cjs/file-upload.js +0 -168
  36. package/dist/esm/chat.d.ts +0 -33
  37. package/dist/esm/chat.js +0 -201
  38. package/dist/esm/file-upload.d.ts +0 -43
  39. package/dist/esm/file-upload.js +0 -163
@@ -1,32 +1,165 @@
1
- import { useEffect } from 'react';
2
- import { startHostedToolkit } from '@meshagent/meshagent';
3
- export const useClientToolkits = ({ room, toolkits, public: isPublic = false }) => {
1
+ import { useEffect, useRef } from "react";
2
+ import { startHostedToolkit } from "@meshagent/meshagent";
3
+ const sharedHostedToolkits = new WeakMap();
4
+ function getToolkitDefinition(toolkit, isPublic) {
5
+ return JSON.stringify({
6
+ public: isPublic,
7
+ name: toolkit.name,
8
+ title: toolkit.title,
9
+ description: toolkit.description,
10
+ thumbnailUrl: toolkit.thumbnailUrl ?? null,
11
+ rules: [...toolkit.rules],
12
+ tools: toolkit.tools.map((tool) => ({
13
+ name: tool.name,
14
+ title: tool.title,
15
+ description: tool.description,
16
+ inputSpec: tool.inputSpec?.toJson() ?? null,
17
+ outputSpec: tool.outputSpec?.toJson() ?? null,
18
+ thumbnailUrl: tool.thumbnailUrl ?? null,
19
+ })),
20
+ });
21
+ }
22
+ function getOrCreateSharedRoomToolkits(room) {
23
+ const existing = sharedHostedToolkits.get(room);
24
+ if (existing !== undefined) {
25
+ return existing;
26
+ }
27
+ const created = new Map();
28
+ sharedHostedToolkits.set(room, created);
29
+ return created;
30
+ }
31
+ async function releaseHostedToolkitLease(room, toolkitName, entry) {
32
+ const roomToolkits = sharedHostedToolkits.get(room);
33
+ if (roomToolkits?.get(toolkitName) !== entry || entry.refs === 0) {
34
+ return;
35
+ }
36
+ entry.refs -= 1;
37
+ if (entry.refs > 0) {
38
+ return;
39
+ }
40
+ if (entry.stopPromise !== null) {
41
+ await entry.stopPromise;
42
+ return;
43
+ }
44
+ entry.stopPromise = (async () => {
45
+ try {
46
+ const hostedToolkit = await entry.startedToolkit;
47
+ await hostedToolkit.stop();
48
+ }
49
+ finally {
50
+ const latestRoomToolkits = sharedHostedToolkits.get(room);
51
+ if (latestRoomToolkits?.get(toolkitName) === entry) {
52
+ latestRoomToolkits.delete(toolkitName);
53
+ if (latestRoomToolkits.size === 0) {
54
+ sharedHostedToolkits.delete(room);
55
+ }
56
+ }
57
+ entry.stopPromise = null;
58
+ }
59
+ })();
60
+ await entry.stopPromise;
61
+ }
62
+ async function acquireHostedToolkitLease({ room, toolkit, public_: isPublic, }) {
63
+ const definition = getToolkitDefinition(toolkit, isPublic);
64
+ while (true) {
65
+ const roomToolkits = getOrCreateSharedRoomToolkits(room);
66
+ const existing = roomToolkits.get(toolkit.name);
67
+ if (existing === undefined) {
68
+ const entry = {
69
+ definition,
70
+ refs: 1,
71
+ startedToolkit: startHostedToolkit({
72
+ room,
73
+ toolkit,
74
+ public_: isPublic,
75
+ }),
76
+ stopPromise: null,
77
+ };
78
+ roomToolkits.set(toolkit.name, entry);
79
+ try {
80
+ await entry.startedToolkit;
81
+ }
82
+ catch (error) {
83
+ if (roomToolkits.get(toolkit.name) === entry) {
84
+ roomToolkits.delete(toolkit.name);
85
+ if (roomToolkits.size === 0) {
86
+ sharedHostedToolkits.delete(room);
87
+ }
88
+ }
89
+ throw error;
90
+ }
91
+ return {
92
+ release: () => releaseHostedToolkitLease(room, toolkit.name, entry),
93
+ };
94
+ }
95
+ if (existing.stopPromise !== null) {
96
+ await existing.stopPromise;
97
+ continue;
98
+ }
99
+ if (existing.definition !== definition) {
100
+ throw new Error(`toolkit '${toolkit.name}' is already hosted for this room with a different definition`);
101
+ }
102
+ existing.refs += 1;
103
+ try {
104
+ await existing.startedToolkit;
105
+ }
106
+ catch (error) {
107
+ existing.refs -= 1;
108
+ if (existing.refs === 0 && roomToolkits.get(toolkit.name) === existing) {
109
+ roomToolkits.delete(toolkit.name);
110
+ if (roomToolkits.size === 0) {
111
+ sharedHostedToolkits.delete(room);
112
+ }
113
+ }
114
+ throw error;
115
+ }
116
+ return {
117
+ release: () => releaseHostedToolkitLease(room, toolkit.name, existing),
118
+ };
119
+ }
120
+ }
121
+ export const useClientToolkits = ({ room, toolkits, public: isPublic = false, }) => {
122
+ const cleanupRef = useRef(Promise.resolve());
4
123
  useEffect(() => {
5
124
  let disposed = false;
6
- const startedToolkits = [];
7
- void (async () => {
125
+ const toolkitLeases = [];
126
+ const waitForPreviousCleanup = cleanupRef.current;
127
+ const startPromise = (async () => {
128
+ await waitForPreviousCleanup;
8
129
  try {
9
130
  for (const toolkit of toolkits) {
10
- const hostedToolkit = await startHostedToolkit({
131
+ if (disposed) {
132
+ return;
133
+ }
134
+ const lease = await acquireHostedToolkitLease({
11
135
  room,
12
136
  toolkit,
13
137
  public_: isPublic,
14
138
  });
15
139
  if (disposed) {
16
- await hostedToolkit.stop();
17
- continue;
140
+ await lease.release();
141
+ return;
18
142
  }
19
- startedToolkits.push(hostedToolkit);
143
+ toolkitLeases.push(lease);
20
144
  }
21
145
  }
22
146
  catch (error) {
23
- await Promise.all(startedToolkits.map((toolkit) => toolkit.stop()));
24
- console.error("unable to start client toolkits", error);
147
+ const leasesToRelease = toolkitLeases.splice(0);
148
+ await Promise.all(leasesToRelease.map((lease) => lease.release()));
149
+ if (!disposed) {
150
+ console.error("unable to start client toolkits", error);
151
+ }
25
152
  }
26
153
  })();
27
154
  return () => {
28
155
  disposed = true;
29
- void Promise.all(startedToolkits.map((toolkit) => toolkit.stop()));
156
+ cleanupRef.current = (async () => {
157
+ await startPromise;
158
+ const leasesToRelease = toolkitLeases.splice(0);
159
+ await Promise.all(leasesToRelease.map((lease) => lease.release()));
160
+ })().catch((error) => {
161
+ console.error("unable to stop client toolkits", error);
162
+ });
30
163
  };
31
164
  }, [room, toolkits, isPublic]);
32
165
  };
@@ -1,7 +1,9 @@
1
- import { MeshDocument, RoomClient, RemoteParticipant } from '@meshagent/meshagent';
1
+ import { MeshDocument, MeshSchema, RoomClient } from '@meshagent/meshagent';
2
2
  export interface UseDocumentConnectionProps {
3
3
  room: RoomClient;
4
4
  path: string;
5
+ schema?: MeshSchema;
6
+ initialJson?: Record<string, unknown>;
5
7
  onConnected?: (document: MeshDocument) => void;
6
8
  onError?: (error: unknown) => void;
7
9
  }
@@ -13,18 +15,11 @@ export interface UseDocumentConnectionResult {
13
15
  }
14
16
  /**
15
17
  * Connects to a Mesh document inside an existing RoomClient and keeps it in sync.
16
- *
17
- * The function retries with an exponential back‑off (capped at 60 s) until the
18
- * document becomes available or the component unmounts.
19
- *
20
- * @param room An already‑connected RoomClient.
21
- * @param path Path to the document inside the room.
22
18
  */
23
- export declare function useDocumentConnection({ room, path, onConnected, onError }: UseDocumentConnectionProps): UseDocumentConnectionResult;
24
- type onChangedHandler = (document: MeshDocument) => void;
25
- export declare function useDocumentChanged({ document, onChanged }: {
19
+ export declare function useDocumentConnection({ room, path, schema, initialJson, onConnected, onError, }: UseDocumentConnectionProps): UseDocumentConnectionResult;
20
+ type OnChangedHandler = (document: MeshDocument) => void;
21
+ export declare function useDocumentChanged({ document, onChanged, }: {
26
22
  document: MeshDocument | null;
27
- onChanged: onChangedHandler;
23
+ onChanged: OnChangedHandler;
28
24
  }): void;
29
- export declare function useRoomParticipants(room: RoomClient | null): Iterable<RemoteParticipant>;
30
25
  export {};
@@ -1,107 +1,114 @@
1
1
  import { useEffect, useRef, useState } from 'react';
2
+ function getRetryDelayMs(retryCount) {
3
+ return Math.min(60000, 500 * 2 ** retryCount);
4
+ }
5
+ async function closeDocument(room, path) {
6
+ try {
7
+ await room.sync.close(path);
8
+ }
9
+ catch {
10
+ }
11
+ }
2
12
  /**
3
13
  * Connects to a Mesh document inside an existing RoomClient and keeps it in sync.
4
- *
5
- * The function retries with an exponential back‑off (capped at 60 s) until the
6
- * document becomes available or the component unmounts.
7
- *
8
- * @param room An already‑connected RoomClient.
9
- * @param path Path to the document inside the room.
10
14
  */
11
- export function useDocumentConnection({ room, path, onConnected, onError }) {
12
- const [schemaFileExists, setSchemaFileExists] = useState(null);
15
+ export function useDocumentConnection({ room, path, schema, initialJson, onConnected, onError, }) {
16
+ const [schemaFileExists, setSchemaFileExists] = useState(schema != null);
13
17
  const [document, setDocument] = useState(null);
14
18
  const [error, setError] = useState(null);
15
- const openedRef = useRef(false);
16
- const retryCountRef = useRef(0);
17
- const timeoutRef = useRef(null);
18
- const pathExtension = path.split('.').pop()?.toLowerCase();
19
- const schemaFile = `.schemas/${pathExtension}.json`;
19
+ const onConnectedRef = useRef(onConnected);
20
+ const onErrorRef = useRef(onError);
21
+ useEffect(() => {
22
+ onConnectedRef.current = onConnected;
23
+ }, [onConnected]);
24
+ useEffect(() => {
25
+ onErrorRef.current = onError;
26
+ }, [onError]);
20
27
  useEffect(() => {
21
28
  let cancelled = false;
22
- const openDocument = async () => {
23
- try {
24
- const schemaExists = await room.storage.exists(schemaFile);
25
- if (schemaExists) {
26
- setSchemaFileExists(true);
27
- }
28
- else {
29
- setSchemaFileExists(false);
30
- return;
31
- }
32
- const doc = await room.sync.open(path);
33
- if (cancelled)
34
- return;
35
- openedRef.current = true;
36
- // sleep for 100 ms to ensure the document is ready
37
- await new Promise(resolve => setTimeout(resolve, 100));
38
- setDocument(doc);
39
- setError(null);
40
- if (onConnected) {
41
- onConnected(doc);
42
- }
29
+ let retryTimeout = null;
30
+ let opened = false;
31
+ let nextRetryCount = 0;
32
+ const clearRetryTimeout = () => {
33
+ if (retryTimeout != null) {
34
+ clearTimeout(retryTimeout);
35
+ retryTimeout = null;
43
36
  }
44
- catch (err) {
45
- console.error('Failed to open document:', err);
46
- if (cancelled)
37
+ };
38
+ const waitForRetry = (delayMs) => new Promise((resolve) => {
39
+ retryTimeout = setTimeout(() => {
40
+ retryTimeout = null;
41
+ resolve();
42
+ }, delayMs);
43
+ });
44
+ setDocument(null);
45
+ setError(null);
46
+ setSchemaFileExists(schema != null);
47
+ void (async () => {
48
+ while (!cancelled) {
49
+ try {
50
+ if (schema == null) {
51
+ const pathExtension = path.split('.').pop()?.toLowerCase();
52
+ const schemaFile = `.schemas/${pathExtension}.json`;
53
+ const nextSchemaExists = await room.storage.exists(schemaFile);
54
+ if (cancelled) {
55
+ return;
56
+ }
57
+ setSchemaFileExists(nextSchemaExists);
58
+ if (!nextSchemaExists) {
59
+ return;
60
+ }
61
+ }
62
+ const nextDocument = await room.sync.open(path, { initialJson, schema });
63
+ if (cancelled) {
64
+ await closeDocument(room, path);
65
+ return;
66
+ }
67
+ opened = true;
68
+ nextRetryCount = 0;
69
+ setDocument(nextDocument);
70
+ setError(null);
71
+ onConnectedRef.current?.(nextDocument);
47
72
  return;
48
- setError(err);
49
- if (onError) {
50
- onError(err);
51
73
  }
52
- // Exponential back‑off: 500 ms, 1 s, 2 s, … up to 60 s.
53
- const delay = Math.min(60000, 500 * 2 ** retryCountRef.current);
54
- retryCountRef.current += 1;
55
- timeoutRef.current = setTimeout(openDocument, delay);
74
+ catch (nextError) {
75
+ if (cancelled) {
76
+ return;
77
+ }
78
+ setDocument(null);
79
+ setError(nextError);
80
+ onErrorRef.current?.(nextError);
81
+ await waitForRetry(getRetryDelayMs(nextRetryCount));
82
+ nextRetryCount += 1;
83
+ }
56
84
  }
57
- };
58
- openDocument();
85
+ })();
59
86
  return () => {
60
87
  cancelled = true;
61
- if (timeoutRef.current !== null) {
62
- clearTimeout(timeoutRef.current);
63
- timeoutRef.current = null;
64
- }
65
- if (openedRef.current) {
66
- room.sync.close(path);
88
+ clearRetryTimeout();
89
+ if (opened) {
90
+ void closeDocument(room, path);
67
91
  }
68
- setDocument(null);
69
- retryCountRef.current = 0;
70
- openedRef.current = false;
71
92
  };
72
- }, [path]);
93
+ }, [initialJson, path, room, schema]);
73
94
  return {
74
95
  document,
75
96
  error,
76
- loading: document === null && error == null,
77
- schemaFileExists: schemaFileExists !== null ? schemaFileExists : true,
97
+ loading: document == null && error == null,
98
+ schemaFileExists,
78
99
  };
79
100
  }
80
- export function useDocumentChanged({ document, onChanged }) {
101
+ export function useDocumentChanged({ document, onChanged, }) {
102
+ const onChangedRef = useRef(onChanged);
81
103
  useEffect(() => {
82
- if (document) {
83
- const s = document.listen(() => onChanged(document));
84
- onChanged(document);
85
- return () => s.unsubscribe();
86
- }
87
- }, [document]);
88
- }
89
- export function useRoomParticipants(room) {
90
- const [participants, setParticipants] = useState(() => []);
104
+ onChangedRef.current = onChanged;
105
+ }, [onChanged]);
91
106
  useEffect(() => {
92
- if (!room || !room.messaging) {
107
+ if (document == null) {
93
108
  return;
94
109
  }
95
- const updateParticipants = () => setParticipants(room.messaging.remoteParticipants);
96
- room.messaging.on('participant_added', updateParticipants);
97
- room.messaging.on('participant_removed', updateParticipants);
98
- room.messaging.on('messaging_enabled', updateParticipants);
99
- updateParticipants();
100
- return () => {
101
- room.messaging.off('participant_added', updateParticipants);
102
- room.messaging.off('participant_removed', updateParticipants);
103
- room.messaging.on('messaging_enabled', updateParticipants);
104
- };
105
- }, [room]);
106
- return participants;
110
+ const subscription = document.listen(() => onChangedRef.current(document));
111
+ onChangedRef.current(document);
112
+ return () => subscription.unsubscribe();
113
+ }, [document]);
107
114
  }
@@ -1,6 +1,7 @@
1
- export * from './chat';
2
1
  export * from './client-toolkits';
3
2
  export * from './document-connection-scope';
4
- export * from './file-upload';
3
+ export * from './livekit-client';
4
+ export * from './livekit-protocol';
5
5
  export * from './room-connection-scope';
6
+ export * from './room-participants';
6
7
  export * from './subscribe-async-gen';
package/dist/esm/index.js CHANGED
@@ -1,6 +1,7 @@
1
- export * from './chat';
2
1
  export * from './client-toolkits';
3
2
  export * from './document-connection-scope';
4
- export * from './file-upload';
3
+ export * from './livekit-client';
4
+ export * from './livekit-protocol';
5
5
  export * from './room-connection-scope';
6
+ export * from './room-participants';
6
7
  export * from './subscribe-async-gen';
@@ -0,0 +1,23 @@
1
+ import { RoomClient } from '@meshagent/meshagent';
2
+ export declare class LivekitConnectionInfo {
3
+ readonly url: string;
4
+ readonly token: string;
5
+ constructor({ url, token }: {
6
+ url: string;
7
+ token: string;
8
+ });
9
+ }
10
+ export declare class LivekitClient {
11
+ readonly room: RoomClient;
12
+ constructor({ room }: {
13
+ room: RoomClient;
14
+ });
15
+ getConnectionInfo({ breakoutRoom, }?: {
16
+ breakoutRoom?: string;
17
+ }): Promise<LivekitConnectionInfo>;
18
+ }
19
+ declare module '@meshagent/meshagent' {
20
+ interface RoomClient {
21
+ readonly livekit: LivekitClient;
22
+ }
23
+ }
@@ -0,0 +1,61 @@
1
+ import { JsonContent, RoomClient, RoomServerException, } from '@meshagent/meshagent';
2
+ export class LivekitConnectionInfo {
3
+ constructor({ url, token }) {
4
+ Object.defineProperty(this, "url", {
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true,
8
+ value: void 0
9
+ });
10
+ Object.defineProperty(this, "token", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: void 0
15
+ });
16
+ this.url = url;
17
+ this.token = token;
18
+ }
19
+ }
20
+ export class LivekitClient {
21
+ constructor({ room }) {
22
+ Object.defineProperty(this, "room", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ this.room = room;
29
+ }
30
+ async getConnectionInfo({ breakoutRoom, } = {}) {
31
+ const response = await this.room.invoke({
32
+ toolkit: 'livekit',
33
+ tool: 'connect',
34
+ input: { breakout_room: breakoutRoom ?? null },
35
+ });
36
+ if (!(response instanceof JsonContent)) {
37
+ throw new RoomServerException('unexpected return type from livekit.connect');
38
+ }
39
+ const responseJson = response.json;
40
+ if (typeof responseJson !== 'object'
41
+ || responseJson == null
42
+ || Array.isArray(responseJson)) {
43
+ throw new RoomServerException('unexpected return type from livekit.connect');
44
+ }
45
+ const token = responseJson.token;
46
+ const url = responseJson.url;
47
+ if (typeof token !== 'string' || typeof url !== 'string') {
48
+ throw new RoomServerException('unexpected return type from livekit.connect');
49
+ }
50
+ return new LivekitConnectionInfo({ token, url });
51
+ }
52
+ }
53
+ if (!Object.getOwnPropertyDescriptor(RoomClient.prototype, 'livekit')) {
54
+ Object.defineProperty(RoomClient.prototype, 'livekit', {
55
+ configurable: true,
56
+ enumerable: false,
57
+ get() {
58
+ return new LivekitClient({ room: this });
59
+ },
60
+ });
61
+ }
@@ -0,0 +1,21 @@
1
+ import type { ProtocolChannel } from '@meshagent/meshagent';
2
+ import * as livekit from 'livekit-client';
3
+ export declare class LivekitProtocolChannel implements ProtocolChannel {
4
+ private readonly room;
5
+ private readonly remote;
6
+ private readonly topic;
7
+ private onDataReceived?;
8
+ private readonly handleDataReceivedBound;
9
+ constructor({ room, remote, topic, }: {
10
+ room: livekit.Room;
11
+ remote: livekit.RemoteParticipant;
12
+ topic: string;
13
+ });
14
+ start(onDataReceived: (data: Uint8Array) => void, _params: {
15
+ onDone?: () => void;
16
+ onError?: (error: unknown) => void;
17
+ }): void;
18
+ sendData(data: Uint8Array): Promise<void>;
19
+ dispose(): void;
20
+ private handleDataReceived;
21
+ }
@@ -0,0 +1,60 @@
1
+ import * as livekit from 'livekit-client';
2
+ export class LivekitProtocolChannel {
3
+ constructor({ room, remote, topic, }) {
4
+ Object.defineProperty(this, "room", {
5
+ enumerable: true,
6
+ configurable: true,
7
+ writable: true,
8
+ value: void 0
9
+ });
10
+ Object.defineProperty(this, "remote", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: void 0
15
+ });
16
+ Object.defineProperty(this, "topic", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: void 0
21
+ });
22
+ Object.defineProperty(this, "onDataReceived", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "handleDataReceivedBound", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ this.room = room;
35
+ this.remote = remote;
36
+ this.topic = topic;
37
+ this.handleDataReceivedBound = this.handleDataReceived.bind(this);
38
+ }
39
+ start(onDataReceived, _params) {
40
+ this.onDataReceived = onDataReceived;
41
+ this.room.on(livekit.RoomEvent.DataReceived, this.handleDataReceivedBound);
42
+ }
43
+ async sendData(data) {
44
+ await this.room.localParticipant.publishData(data, {
45
+ reliable: true,
46
+ topic: this.topic,
47
+ destinationIdentities: [this.remote.identity],
48
+ });
49
+ }
50
+ dispose() {
51
+ this.room.off(livekit.RoomEvent.DataReceived, this.handleDataReceivedBound);
52
+ this.onDataReceived = undefined;
53
+ }
54
+ handleDataReceived(payload, participant, _kind, topic, _encryptionType) {
55
+ const identityMatches = participant?.identity === this.remote.identity;
56
+ if (identityMatches && topic === this.topic) {
57
+ this.onDataReceived?.(payload);
58
+ }
59
+ }
60
+ }
@@ -1,8 +1,5 @@
1
- import { RoomClient } from '@meshagent/meshagent';
2
- export interface RoomConnectionInfo {
3
- url: string;
4
- jwt: string;
5
- }
1
+ import { type OAuthTokenRequest, RoomClient, type SecretRequest } from '@meshagent/meshagent';
2
+ import type { RoomConnectionInfo } from '@meshagent/meshagent';
6
3
  export declare const developmentAuthorization: ({ url, projectId, apiKeyId, participantName, roomName, secret, }: {
7
4
  url: string;
8
5
  projectId: string;
@@ -11,27 +8,30 @@ export declare const developmentAuthorization: ({ url, projectId, apiKeyId, part
11
8
  roomName: string;
12
9
  secret: string;
13
10
  }) => (() => Promise<RoomConnectionInfo>);
11
+ export declare const staticAuthorization: ({ projectId, roomName, url, jwt, }: {
12
+ projectId: string;
13
+ roomName: string;
14
+ url: string;
15
+ jwt: string;
16
+ }) => (() => Promise<RoomConnectionInfo>);
14
17
  export interface UseRoomConnectionOptions {
15
- /** Async function that returns `{ url, jwt }` for the room. */
16
- authorization: () => Promise<{
17
- url: string;
18
- jwt: string;
19
- }>;
20
- /** Enable the optional messaging layer (default = `true`). */
18
+ reconnectKey?: string;
19
+ authorization: () => Promise<RoomConnectionInfo>;
21
20
  enableMessaging?: boolean;
21
+ onReady?: (room: RoomClient) => void;
22
+ oauthTokenRequestHandler?: (room: RoomClient, request: OAuthTokenRequest) => Promise<void> | void;
23
+ secretRequestHandler?: (room: RoomClient, request: SecretRequest) => Promise<void> | void;
24
+ roomClientFactory?: (connectionInfo: RoomConnectionInfo) => RoomClient;
22
25
  }
23
- /**
24
- * Shape of the object returned by the hook.
25
- */
26
26
  export interface UseRoomConnectionResult {
27
27
  client: RoomClient | null;
28
- state: 'authorizing' | 'connecting' | 'ready' | 'done';
28
+ state: 'authorizing' | 'connecting' | 'retrying' | 'ready' | 'done';
29
29
  ready: boolean;
30
30
  done: boolean;
31
31
  error: unknown;
32
32
  dispose: () => void;
33
33
  }
34
- export declare function useRoomConnection(props: UseRoomConnectionOptions): UseRoomConnectionResult;
34
+ export declare function useRoomConnection({ reconnectKey, authorization, enableMessaging, onReady, oauthTokenRequestHandler, secretRequestHandler, roomClientFactory, }: UseRoomConnectionOptions): UseRoomConnectionResult;
35
35
  export interface UseRoomIndicatorsResult {
36
36
  typing: boolean;
37
37
  thinking: boolean;