sabha-meetings-react 0.1.0 → 0.1.1
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.
- package/README.md +139 -0
- package/dist/index.d.mts +428 -1
- package/dist/index.d.ts +428 -1
- package/dist/index.js +1432 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1419 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,429 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
1
3
|
|
|
2
|
-
|
|
4
|
+
type SabhaTokens = {
|
|
5
|
+
/** Optional bearer token (Postman-style). Live API primarily uses `vm_session` cookie. */
|
|
6
|
+
accessToken?: string;
|
|
7
|
+
refreshToken?: string;
|
|
8
|
+
/** Session cookie value when running outside the browser (Node / RN). */
|
|
9
|
+
sessionCookie?: string;
|
|
10
|
+
};
|
|
11
|
+
type SabhaConfig = {
|
|
12
|
+
/** Sabha API base URL */
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Origin for auth CORS allow-list (server-side / RN).
|
|
16
|
+
* Browsers set Origin automatically; still useful for documentation.
|
|
17
|
+
*/
|
|
18
|
+
origin?: string;
|
|
19
|
+
/** Optional bearer access token */
|
|
20
|
+
accessToken?: string;
|
|
21
|
+
refreshToken?: string;
|
|
22
|
+
/** Persist/reuse `vm_session` outside the browser */
|
|
23
|
+
sessionCookie?: string;
|
|
24
|
+
/** Send cookies (`credentials: "include"`). Default true. */
|
|
25
|
+
withCredentials?: boolean;
|
|
26
|
+
socketPath?: string;
|
|
27
|
+
socketEvents?: Partial<SabhaSocketEvents>;
|
|
28
|
+
/**
|
|
29
|
+
* Meeting media / capture policy applied when connecting.
|
|
30
|
+
* Defaults enable mic+cam and block screenshots/recordings where possible.
|
|
31
|
+
*/
|
|
32
|
+
mediaPolicy?: Partial<MediaPolicy>;
|
|
33
|
+
};
|
|
34
|
+
declare const DEFAULT_BASE_URL = "https://sabha-api.sthanave.com";
|
|
35
|
+
type SabhaSocketEvents = {
|
|
36
|
+
join: string;
|
|
37
|
+
leave: string;
|
|
38
|
+
participantJoined: string;
|
|
39
|
+
participantLeft: string;
|
|
40
|
+
meetingEnded: string;
|
|
41
|
+
error: string;
|
|
42
|
+
mediaState: string;
|
|
43
|
+
};
|
|
44
|
+
type SabhaOrg = {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
suspended: boolean;
|
|
48
|
+
};
|
|
49
|
+
/** Shape returned by POST /api/auth/login and GET /api/auth/me */
|
|
50
|
+
type AuthUser = {
|
|
51
|
+
ok?: boolean;
|
|
52
|
+
userId: string;
|
|
53
|
+
username: string;
|
|
54
|
+
email: string;
|
|
55
|
+
about?: string;
|
|
56
|
+
photo?: string;
|
|
57
|
+
lat?: number | null;
|
|
58
|
+
lng?: number | null;
|
|
59
|
+
termsAccepted?: boolean;
|
|
60
|
+
role?: string;
|
|
61
|
+
jobTitle?: string;
|
|
62
|
+
permissions?: string[];
|
|
63
|
+
platformRole?: string | null;
|
|
64
|
+
platformAccess?: boolean;
|
|
65
|
+
org?: SabhaOrg | null;
|
|
66
|
+
pendingApproval?: unknown;
|
|
67
|
+
/** Present when API returns JWT-style auth */
|
|
68
|
+
token?: string;
|
|
69
|
+
refreshToken?: string;
|
|
70
|
+
[key: string]: unknown;
|
|
71
|
+
};
|
|
72
|
+
type LoginInput = {
|
|
73
|
+
email: string;
|
|
74
|
+
password: string;
|
|
75
|
+
};
|
|
76
|
+
type RegisterInput = {
|
|
77
|
+
email: string;
|
|
78
|
+
password: string;
|
|
79
|
+
username: string;
|
|
80
|
+
acceptTerms: boolean;
|
|
81
|
+
};
|
|
82
|
+
type VerifyEmailInput = {
|
|
83
|
+
email: string;
|
|
84
|
+
code: string;
|
|
85
|
+
};
|
|
86
|
+
type AuthSession = {
|
|
87
|
+
user: AuthUser;
|
|
88
|
+
accessToken?: string;
|
|
89
|
+
refreshToken?: string;
|
|
90
|
+
sessionCookie?: string;
|
|
91
|
+
};
|
|
92
|
+
type MeetingOrganizer = {
|
|
93
|
+
id: string;
|
|
94
|
+
username: string;
|
|
95
|
+
photo?: string;
|
|
96
|
+
online?: boolean;
|
|
97
|
+
lastActive?: string;
|
|
98
|
+
};
|
|
99
|
+
type MeetingInvitee = {
|
|
100
|
+
id: string;
|
|
101
|
+
username?: string;
|
|
102
|
+
photo?: string;
|
|
103
|
+
[key: string]: unknown;
|
|
104
|
+
};
|
|
105
|
+
/** Shape returned under `meeting` / `meetings[]` from /api/meetings */
|
|
106
|
+
type Meeting = {
|
|
107
|
+
id: string;
|
|
108
|
+
title: string;
|
|
109
|
+
notes?: string;
|
|
110
|
+
/** Join code, e.g. `rxv-scpd-ppe` */
|
|
111
|
+
code?: string;
|
|
112
|
+
startAt: string;
|
|
113
|
+
durationMin: number;
|
|
114
|
+
timeZone?: string;
|
|
115
|
+
groupId?: string;
|
|
116
|
+
owner?: boolean;
|
|
117
|
+
canEdit?: boolean;
|
|
118
|
+
canCancel?: boolean;
|
|
119
|
+
organizer?: MeetingOrganizer;
|
|
120
|
+
invitees?: MeetingInvitee[];
|
|
121
|
+
inviteeIds?: string[];
|
|
122
|
+
[key: string]: unknown;
|
|
123
|
+
};
|
|
124
|
+
type CreateMeetingInput = {
|
|
125
|
+
title: string;
|
|
126
|
+
startAt?: string;
|
|
127
|
+
durationMin?: number;
|
|
128
|
+
timeZone?: string;
|
|
129
|
+
inviteeIds?: string[];
|
|
130
|
+
notes?: string;
|
|
131
|
+
groupId?: string;
|
|
132
|
+
};
|
|
133
|
+
type UpdateMeetingInput = {
|
|
134
|
+
title?: string;
|
|
135
|
+
startAt?: string;
|
|
136
|
+
durationMin?: number;
|
|
137
|
+
timeZone?: string;
|
|
138
|
+
inviteeIds?: string[];
|
|
139
|
+
notes?: string;
|
|
140
|
+
[key: string]: unknown;
|
|
141
|
+
};
|
|
142
|
+
type MeetingConnectionState = "disconnected" | "connecting" | "connected" | "joined" | "error";
|
|
143
|
+
type MeetingParticipant = {
|
|
144
|
+
id: string;
|
|
145
|
+
displayName?: string;
|
|
146
|
+
username?: string;
|
|
147
|
+
audioEnabled?: boolean;
|
|
148
|
+
videoEnabled?: boolean;
|
|
149
|
+
screenSharing?: boolean;
|
|
150
|
+
[key: string]: unknown;
|
|
151
|
+
};
|
|
152
|
+
type MediaTrackKind = "audio" | "video" | "screen";
|
|
153
|
+
type LocalMediaState = {
|
|
154
|
+
audioEnabled: boolean;
|
|
155
|
+
videoEnabled: boolean;
|
|
156
|
+
screenSharing: boolean;
|
|
157
|
+
screenOff: boolean;
|
|
158
|
+
};
|
|
159
|
+
type MediaPolicy = {
|
|
160
|
+
/** Start with microphone enabled */
|
|
161
|
+
audio: boolean;
|
|
162
|
+
/** Start with camera enabled */
|
|
163
|
+
video: boolean;
|
|
164
|
+
/** Allow screen sharing */
|
|
165
|
+
allowScreenShare: boolean;
|
|
166
|
+
/** Soft “screen off” — stop publishing camera/screen locally */
|
|
167
|
+
screenOff: boolean;
|
|
168
|
+
/** Block screenshots / screen recording where the platform allows */
|
|
169
|
+
blockScreenshots: boolean;
|
|
170
|
+
/** Block OS / in-app screen recording where the platform allows */
|
|
171
|
+
blockScreenRecording: boolean;
|
|
172
|
+
};
|
|
173
|
+
declare const DEFAULT_MEDIA_POLICY: MediaPolicy;
|
|
174
|
+
type MeetingRoomEventMap = {
|
|
175
|
+
state: MeetingConnectionState;
|
|
176
|
+
participantJoined: MeetingParticipant;
|
|
177
|
+
participantLeft: {
|
|
178
|
+
id: string;
|
|
179
|
+
};
|
|
180
|
+
meetingEnded: {
|
|
181
|
+
meetingId: string;
|
|
182
|
+
reason?: string;
|
|
183
|
+
};
|
|
184
|
+
mediaState: LocalMediaState;
|
|
185
|
+
captureAttempt: {
|
|
186
|
+
type: "screenshot" | "recording" | "visibility";
|
|
187
|
+
at: string;
|
|
188
|
+
};
|
|
189
|
+
error: Error;
|
|
190
|
+
raw: {
|
|
191
|
+
event: string;
|
|
192
|
+
payload: unknown;
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
type MediaListener = (state: LocalMediaState) => void;
|
|
197
|
+
/**
|
|
198
|
+
* Local A/V + screen-share controller for web meetings.
|
|
199
|
+
* Publishes MediaStreams the host app can attach to <video>/<audio> elements.
|
|
200
|
+
*/
|
|
201
|
+
declare class MediaController {
|
|
202
|
+
private policy;
|
|
203
|
+
private micStream;
|
|
204
|
+
private camStream;
|
|
205
|
+
private screenStream;
|
|
206
|
+
private state;
|
|
207
|
+
private readonly listeners;
|
|
208
|
+
constructor(policy: MediaPolicy);
|
|
209
|
+
getMediaState(): LocalMediaState;
|
|
210
|
+
getMicrophoneStream(): MediaStream | null;
|
|
211
|
+
getCameraStream(): MediaStream | null;
|
|
212
|
+
getScreenStream(): MediaStream | null;
|
|
213
|
+
/** Combined local A/V tracks for attaching to a peer connection / video element. */
|
|
214
|
+
getLocalStream(): MediaStream;
|
|
215
|
+
onChange(listener: MediaListener): () => void;
|
|
216
|
+
start(policy?: Partial<MediaPolicy>): Promise<LocalMediaState>;
|
|
217
|
+
setAudioEnabled(enabled: boolean): Promise<LocalMediaState>;
|
|
218
|
+
setVideoEnabled(enabled: boolean): Promise<LocalMediaState>;
|
|
219
|
+
setScreenOff(off: boolean): Promise<LocalMediaState>;
|
|
220
|
+
startScreenShare(): Promise<LocalMediaState>;
|
|
221
|
+
stopScreenShare(): Promise<LocalMediaState>;
|
|
222
|
+
toggleAudio(): Promise<LocalMediaState>;
|
|
223
|
+
toggleVideo(): Promise<LocalMediaState>;
|
|
224
|
+
stopAll(): void;
|
|
225
|
+
private publish;
|
|
226
|
+
private ensureMediaDevices;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
type CaptureAttemptType = "screenshot" | "recording" | "visibility";
|
|
230
|
+
type CaptureListener = (event: {
|
|
231
|
+
type: CaptureAttemptType;
|
|
232
|
+
at: string;
|
|
233
|
+
}) => void;
|
|
234
|
+
/**
|
|
235
|
+
* Best-effort web protections against screenshots / screen recording.
|
|
236
|
+
* Browsers cannot fully block OS-level capture; this layer deters casual capture
|
|
237
|
+
* and notifies the host app so it can blank the UI or end the meeting.
|
|
238
|
+
*/
|
|
239
|
+
declare class ContentProtection {
|
|
240
|
+
private policy;
|
|
241
|
+
private enabled;
|
|
242
|
+
private readonly listeners;
|
|
243
|
+
private cleanups;
|
|
244
|
+
private styleEl;
|
|
245
|
+
constructor(policy: Pick<MediaPolicy, "blockScreenshots" | "blockScreenRecording">);
|
|
246
|
+
onCaptureAttempt(listener: CaptureListener): () => void;
|
|
247
|
+
setPolicy(policy: Pick<MediaPolicy, "blockScreenshots" | "blockScreenRecording">): void;
|
|
248
|
+
enable(): void;
|
|
249
|
+
disable(): void;
|
|
250
|
+
private injectStyles;
|
|
251
|
+
private bindGuards;
|
|
252
|
+
private obscureBriefly;
|
|
253
|
+
private emit;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
type Listener<T> = (payload: T) => void;
|
|
257
|
+
type MeetingConnectionOptions = {
|
|
258
|
+
baseUrl: string;
|
|
259
|
+
meetingId: string;
|
|
260
|
+
accessToken?: string;
|
|
261
|
+
sessionCookie?: string;
|
|
262
|
+
withCredentials?: boolean;
|
|
263
|
+
socketPath?: string;
|
|
264
|
+
events?: Partial<SabhaSocketEvents>;
|
|
265
|
+
mediaPolicy?: Partial<MediaPolicy>;
|
|
266
|
+
};
|
|
267
|
+
declare class MeetingConnection {
|
|
268
|
+
private readonly options;
|
|
269
|
+
private socket;
|
|
270
|
+
private state;
|
|
271
|
+
private readonly events;
|
|
272
|
+
private readonly mediaPolicy;
|
|
273
|
+
readonly media: MediaController;
|
|
274
|
+
readonly protection: ContentProtection;
|
|
275
|
+
private readonly listeners;
|
|
276
|
+
private mediaUnsub;
|
|
277
|
+
private captureUnsub;
|
|
278
|
+
constructor(options: MeetingConnectionOptions);
|
|
279
|
+
get meetingId(): string;
|
|
280
|
+
get connectionState(): MeetingConnectionState;
|
|
281
|
+
getMediaState(): LocalMediaState;
|
|
282
|
+
on<K extends keyof MeetingRoomEventMap>(event: K, listener: Listener<MeetingRoomEventMap[K]>): () => void;
|
|
283
|
+
connect(): Promise<void>;
|
|
284
|
+
setAudioEnabled(enabled: boolean): Promise<LocalMediaState>;
|
|
285
|
+
setVideoEnabled(enabled: boolean): Promise<LocalMediaState>;
|
|
286
|
+
setScreenOff(off: boolean): Promise<LocalMediaState>;
|
|
287
|
+
startScreenShare(): Promise<LocalMediaState>;
|
|
288
|
+
stopScreenShare(): Promise<LocalMediaState>;
|
|
289
|
+
leave(): Promise<void>;
|
|
290
|
+
disconnect(): void;
|
|
291
|
+
emitRaw(event: string, payload?: unknown): void;
|
|
292
|
+
private teardownMedia;
|
|
293
|
+
private join;
|
|
294
|
+
private bindServerEvents;
|
|
295
|
+
private setState;
|
|
296
|
+
private emit;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
type SabhaClientStatus = {
|
|
300
|
+
configured: boolean;
|
|
301
|
+
authenticated: boolean;
|
|
302
|
+
baseUrl: string;
|
|
303
|
+
};
|
|
304
|
+
declare class SabhaClient {
|
|
305
|
+
private config;
|
|
306
|
+
private tokens;
|
|
307
|
+
private user;
|
|
308
|
+
private http;
|
|
309
|
+
private authApi;
|
|
310
|
+
private meetingsApi;
|
|
311
|
+
private activeConnection;
|
|
312
|
+
private refreshPromise;
|
|
313
|
+
private mediaPolicy;
|
|
314
|
+
configure(config?: SabhaConfig): this;
|
|
315
|
+
getStatus(): SabhaClientStatus;
|
|
316
|
+
getAccessToken(): string | null;
|
|
317
|
+
getSessionCookie(): string | null;
|
|
318
|
+
getUser(): AuthUser | null;
|
|
319
|
+
getMediaPolicy(): MediaPolicy;
|
|
320
|
+
setMediaPolicy(policy: Partial<MediaPolicy>): void;
|
|
321
|
+
setTokens(tokens: SabhaTokens): void;
|
|
322
|
+
clearSession(): void;
|
|
323
|
+
login(input: LoginInput): Promise<AuthSession>;
|
|
324
|
+
register(input: RegisterInput): Promise<unknown>;
|
|
325
|
+
verifyEmail(input: VerifyEmailInput): Promise<AuthSession>;
|
|
326
|
+
refreshSession(): Promise<SabhaTokens>;
|
|
327
|
+
me(): Promise<AuthUser>;
|
|
328
|
+
logout(): Promise<void>;
|
|
329
|
+
listMeetings(): Promise<Meeting[]>;
|
|
330
|
+
createMeeting(input: CreateMeetingInput): Promise<Meeting>;
|
|
331
|
+
updateMeeting(meetingId: string, input: UpdateMeetingInput): Promise<Meeting>;
|
|
332
|
+
cancelMeeting(meetingId: string): Promise<void>;
|
|
333
|
+
startMeeting(input?: CreateMeetingInput & {
|
|
334
|
+
meetingId?: string;
|
|
335
|
+
}): Promise<{
|
|
336
|
+
meeting: Meeting;
|
|
337
|
+
connection: MeetingConnection;
|
|
338
|
+
}>;
|
|
339
|
+
connect(meetingId: string): Promise<MeetingConnection>;
|
|
340
|
+
getConnection(): MeetingConnection | null;
|
|
341
|
+
leaveMeeting(): Promise<void>;
|
|
342
|
+
private applySession;
|
|
343
|
+
private tryRefresh;
|
|
344
|
+
private getOrigin;
|
|
345
|
+
private ensureConfigured;
|
|
346
|
+
private auth;
|
|
347
|
+
private meetings;
|
|
348
|
+
}
|
|
349
|
+
declare function createSabhaClient(config?: SabhaConfig): SabhaClient;
|
|
350
|
+
|
|
351
|
+
type SabhaProviderProps = SabhaConfig & {
|
|
352
|
+
children: ReactNode;
|
|
353
|
+
client?: SabhaClient;
|
|
354
|
+
autoLoadMeetings?: boolean;
|
|
355
|
+
};
|
|
356
|
+
declare function SabhaProvider({ children, client: clientProp, autoLoadMeetings, ...config }: SabhaProviderProps): react.JSX.Element;
|
|
357
|
+
|
|
358
|
+
type SabhaContextValue = {
|
|
359
|
+
client: SabhaClient;
|
|
360
|
+
ready: boolean;
|
|
361
|
+
authenticated: boolean;
|
|
362
|
+
user: AuthUser | null;
|
|
363
|
+
meetings: Meeting[];
|
|
364
|
+
meetingsLoading: boolean;
|
|
365
|
+
connection: MeetingConnection | null;
|
|
366
|
+
connectionState: MeetingConnectionState;
|
|
367
|
+
mediaState: LocalMediaState;
|
|
368
|
+
error: Error | null;
|
|
369
|
+
refreshMeetings: () => Promise<Meeting[]>;
|
|
370
|
+
createMeeting: SabhaClient["createMeeting"];
|
|
371
|
+
updateMeeting: SabhaClient["updateMeeting"];
|
|
372
|
+
cancelMeeting: SabhaClient["cancelMeeting"];
|
|
373
|
+
startMeeting: SabhaClient["startMeeting"];
|
|
374
|
+
connect: SabhaClient["connect"];
|
|
375
|
+
leaveMeeting: SabhaClient["leaveMeeting"];
|
|
376
|
+
login: SabhaClient["login"];
|
|
377
|
+
logout: SabhaClient["logout"];
|
|
378
|
+
setAudioEnabled: (enabled: boolean) => Promise<LocalMediaState>;
|
|
379
|
+
setVideoEnabled: (enabled: boolean) => Promise<LocalMediaState>;
|
|
380
|
+
setScreenOff: (off: boolean) => Promise<LocalMediaState>;
|
|
381
|
+
startScreenShare: () => Promise<LocalMediaState>;
|
|
382
|
+
stopScreenShare: () => Promise<LocalMediaState>;
|
|
383
|
+
clearError: () => void;
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
declare function useSabha(): SabhaContextValue;
|
|
387
|
+
declare function useSabhaMeetings(): {
|
|
388
|
+
meetings: Meeting[];
|
|
389
|
+
meetingsLoading: boolean;
|
|
390
|
+
refreshMeetings: () => Promise<Meeting[]>;
|
|
391
|
+
createMeeting: (input: CreateMeetingInput) => Promise<Meeting>;
|
|
392
|
+
updateMeeting: (meetingId: string, input: UpdateMeetingInput) => Promise<Meeting>;
|
|
393
|
+
cancelMeeting: (meetingId: string) => Promise<void>;
|
|
394
|
+
startMeeting: (input?: CreateMeetingInput & {
|
|
395
|
+
meetingId?: string;
|
|
396
|
+
}) => Promise<{
|
|
397
|
+
meeting: Meeting;
|
|
398
|
+
connection: MeetingConnection;
|
|
399
|
+
}>;
|
|
400
|
+
connect: (meetingId: string) => Promise<MeetingConnection>;
|
|
401
|
+
leaveMeeting: () => Promise<void>;
|
|
402
|
+
connection: MeetingConnection | null;
|
|
403
|
+
connectionState: MeetingConnectionState;
|
|
404
|
+
mediaState: LocalMediaState;
|
|
405
|
+
setAudioEnabled: (enabled: boolean) => Promise<LocalMediaState>;
|
|
406
|
+
setVideoEnabled: (enabled: boolean) => Promise<LocalMediaState>;
|
|
407
|
+
setScreenOff: (off: boolean) => Promise<LocalMediaState>;
|
|
408
|
+
startScreenShare: () => Promise<LocalMediaState>;
|
|
409
|
+
stopScreenShare: () => Promise<LocalMediaState>;
|
|
410
|
+
error: Error | null;
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
declare class SabhaError extends Error {
|
|
414
|
+
readonly status?: number;
|
|
415
|
+
readonly code?: string;
|
|
416
|
+
readonly details?: unknown;
|
|
417
|
+
constructor(message: string, options?: {
|
|
418
|
+
status?: number;
|
|
419
|
+
code?: string;
|
|
420
|
+
details?: unknown;
|
|
421
|
+
cause?: unknown;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
declare function toSabhaError(error: unknown, fallback?: string): SabhaError;
|
|
425
|
+
|
|
426
|
+
declare function normalizeMeeting(raw: unknown): Meeting;
|
|
427
|
+
|
|
428
|
+
export { ContentProtection, DEFAULT_BASE_URL, DEFAULT_MEDIA_POLICY, MediaController, MeetingConnection, SabhaClient, SabhaError, SabhaProvider, createSabhaClient, normalizeMeeting, toSabhaError, useSabha, useSabhaMeetings };
|
|
429
|
+
export type { AuthSession, AuthUser, CaptureAttemptType, CreateMeetingInput, LocalMediaState, LoginInput, MediaPolicy, MediaTrackKind, Meeting, MeetingConnectionOptions, MeetingConnectionState, MeetingInvitee, MeetingOrganizer, MeetingParticipant, MeetingRoomEventMap, RegisterInput, SabhaClientStatus, SabhaConfig, SabhaContextValue, SabhaOrg, SabhaProviderProps, SabhaSocketEvents, SabhaTokens, UpdateMeetingInput, VerifyEmailInput };
|