sabha-meetings-react 0.1.3 → 0.1.5
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/dist/index.d.mts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +87 -25
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +84 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -19,8 +19,13 @@ type SabhaConfig = {
|
|
|
19
19
|
/** Optional bearer access token */
|
|
20
20
|
accessToken?: string;
|
|
21
21
|
refreshToken?: string;
|
|
22
|
-
/** Persist/reuse `vm_session`
|
|
22
|
+
/** Persist/reuse `vm_session` (also sent as x-sabha-session for proxies). */
|
|
23
23
|
sessionCookie?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Persist `vm_session` in localStorage after login and restore on configure.
|
|
26
|
+
* Default true in browsers.
|
|
27
|
+
*/
|
|
28
|
+
persistSession?: boolean;
|
|
24
29
|
/** Send cookies (`credentials: "include"`). Default true. */
|
|
25
30
|
withCredentials?: boolean;
|
|
26
31
|
socketPath?: string;
|
|
@@ -342,6 +347,7 @@ declare class SabhaClient {
|
|
|
342
347
|
getConnection(): MeetingConnection | null;
|
|
343
348
|
leaveMeeting(): Promise<void>;
|
|
344
349
|
private applySession;
|
|
350
|
+
private persistSessionCookie;
|
|
345
351
|
private tryRefresh;
|
|
346
352
|
private getOrigin;
|
|
347
353
|
private ensureConfigured;
|
|
@@ -427,5 +433,11 @@ declare function toSabhaError(error: unknown, fallback?: string): SabhaError;
|
|
|
427
433
|
|
|
428
434
|
declare function normalizeMeeting(raw: unknown): Meeting;
|
|
429
435
|
|
|
430
|
-
|
|
436
|
+
/** Readable session bridge header (browsers cannot set the Cookie request header). */
|
|
437
|
+
declare const SABHA_SESSION_HEADER = "x-sabha-session";
|
|
438
|
+
declare const SABHA_SESSION_STORAGE_KEY = "sabha_vm_session";
|
|
439
|
+
declare function readStoredSessionCookie(): string | null;
|
|
440
|
+
declare function writeStoredSessionCookie(value: string | null): void;
|
|
441
|
+
|
|
442
|
+
export { ContentProtection, DEFAULT_BASE_URL, DEFAULT_MEDIA_POLICY, MediaController, MeetingConnection, SABHA_SESSION_HEADER, SABHA_SESSION_STORAGE_KEY, SabhaClient, SabhaError, SabhaProvider, createSabhaClient, normalizeMeeting, readStoredSessionCookie, toSabhaError, useSabha, useSabhaMeetings, writeStoredSessionCookie };
|
|
431
443
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -19,8 +19,13 @@ type SabhaConfig = {
|
|
|
19
19
|
/** Optional bearer access token */
|
|
20
20
|
accessToken?: string;
|
|
21
21
|
refreshToken?: string;
|
|
22
|
-
/** Persist/reuse `vm_session`
|
|
22
|
+
/** Persist/reuse `vm_session` (also sent as x-sabha-session for proxies). */
|
|
23
23
|
sessionCookie?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Persist `vm_session` in localStorage after login and restore on configure.
|
|
26
|
+
* Default true in browsers.
|
|
27
|
+
*/
|
|
28
|
+
persistSession?: boolean;
|
|
24
29
|
/** Send cookies (`credentials: "include"`). Default true. */
|
|
25
30
|
withCredentials?: boolean;
|
|
26
31
|
socketPath?: string;
|
|
@@ -342,6 +347,7 @@ declare class SabhaClient {
|
|
|
342
347
|
getConnection(): MeetingConnection | null;
|
|
343
348
|
leaveMeeting(): Promise<void>;
|
|
344
349
|
private applySession;
|
|
350
|
+
private persistSessionCookie;
|
|
345
351
|
private tryRefresh;
|
|
346
352
|
private getOrigin;
|
|
347
353
|
private ensureConfigured;
|
|
@@ -427,5 +433,11 @@ declare function toSabhaError(error: unknown, fallback?: string): SabhaError;
|
|
|
427
433
|
|
|
428
434
|
declare function normalizeMeeting(raw: unknown): Meeting;
|
|
429
435
|
|
|
430
|
-
|
|
436
|
+
/** Readable session bridge header (browsers cannot set the Cookie request header). */
|
|
437
|
+
declare const SABHA_SESSION_HEADER = "x-sabha-session";
|
|
438
|
+
declare const SABHA_SESSION_STORAGE_KEY = "sabha_vm_session";
|
|
439
|
+
declare function readStoredSessionCookie(): string | null;
|
|
440
|
+
declare function writeStoredSessionCookie(value: string | null): void;
|
|
441
|
+
|
|
442
|
+
export { ContentProtection, DEFAULT_BASE_URL, DEFAULT_MEDIA_POLICY, MediaController, MeetingConnection, SABHA_SESSION_HEADER, SABHA_SESSION_STORAGE_KEY, SabhaClient, SabhaError, SabhaProvider, createSabhaClient, normalizeMeeting, readStoredSessionCookie, toSabhaError, useSabha, useSabhaMeetings, writeStoredSessionCookie };
|
|
431
443
|
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 };
|
package/dist/index.js
CHANGED
|
@@ -163,6 +163,30 @@ function toSabhaError(error, fallback = "Sabha request failed") {
|
|
|
163
163
|
return new SabhaError(fallback, { details: error });
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
// src/session.ts
|
|
167
|
+
var SABHA_SESSION_HEADER = "x-sabha-session";
|
|
168
|
+
var SABHA_SESSION_STORAGE_KEY = "sabha_vm_session";
|
|
169
|
+
function readStoredSessionCookie() {
|
|
170
|
+
try {
|
|
171
|
+
if (typeof localStorage === "undefined") return null;
|
|
172
|
+
return localStorage.getItem(SABHA_SESSION_STORAGE_KEY);
|
|
173
|
+
} catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function writeStoredSessionCookie(value) {
|
|
178
|
+
try {
|
|
179
|
+
if (typeof localStorage === "undefined") return;
|
|
180
|
+
if (!value) localStorage.removeItem(SABHA_SESSION_STORAGE_KEY);
|
|
181
|
+
else localStorage.setItem(SABHA_SESSION_STORAGE_KEY, value);
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function parseVmSession(cookieHeader) {
|
|
186
|
+
const match = /(?:^|,\s*)vm_session=([^;]+)/i.exec(cookieHeader);
|
|
187
|
+
return match?.[1] ? decodeURIComponent(match[1].trim()) : null;
|
|
188
|
+
}
|
|
189
|
+
|
|
166
190
|
// src/http/client.ts
|
|
167
191
|
function joinUrl(baseUrl, path) {
|
|
168
192
|
const base = baseUrl.replace(/\/+$/, "");
|
|
@@ -196,15 +220,21 @@ function messageFromBody(body, fallback) {
|
|
|
196
220
|
if (typeof record.error === "string") return record.error;
|
|
197
221
|
return fallback;
|
|
198
222
|
}
|
|
199
|
-
function
|
|
223
|
+
function isBrowser() {
|
|
224
|
+
const runtime = globalThis;
|
|
225
|
+
return typeof runtime.window !== "undefined" && typeof runtime.document !== "undefined";
|
|
226
|
+
}
|
|
227
|
+
function readSessionFromResponse(response) {
|
|
228
|
+
const bridged = response.headers.get(SABHA_SESSION_HEADER);
|
|
229
|
+
if (bridged?.trim()) return bridged.trim();
|
|
200
230
|
const anyHeaders = response.headers;
|
|
201
231
|
const list = typeof anyHeaders.getSetCookie === "function" ? anyHeaders.getSetCookie() : (() => {
|
|
202
232
|
const single = response.headers.get("set-cookie");
|
|
203
233
|
return single ? [single] : [];
|
|
204
234
|
})();
|
|
205
235
|
for (const entry of list) {
|
|
206
|
-
const
|
|
207
|
-
if (
|
|
236
|
+
const value = parseVmSession(entry);
|
|
237
|
+
if (value) return value;
|
|
208
238
|
}
|
|
209
239
|
return null;
|
|
210
240
|
}
|
|
@@ -218,10 +248,8 @@ var HttpClient = class {
|
|
|
218
248
|
Accept: "application/json",
|
|
219
249
|
...options.headers
|
|
220
250
|
};
|
|
221
|
-
const runtime = globalThis;
|
|
222
|
-
const isBrowser = typeof runtime.window !== "undefined" && typeof runtime.document !== "undefined";
|
|
223
251
|
const origin = this.options.getOrigin();
|
|
224
|
-
if (!isBrowser && origin) headers.Origin = origin;
|
|
252
|
+
if (!isBrowser() && origin) headers.Origin = origin;
|
|
225
253
|
const tokens = this.options.getTokens();
|
|
226
254
|
const needsAuth = options.auth !== false;
|
|
227
255
|
if (tokens?.accessToken) {
|
|
@@ -233,7 +261,10 @@ var HttpClient = class {
|
|
|
233
261
|
);
|
|
234
262
|
}
|
|
235
263
|
if (tokens?.sessionCookie) {
|
|
236
|
-
headers
|
|
264
|
+
headers[SABHA_SESSION_HEADER] = tokens.sessionCookie;
|
|
265
|
+
if (!isBrowser()) {
|
|
266
|
+
headers.Cookie = `vm_session=${tokens.sessionCookie}`;
|
|
267
|
+
}
|
|
237
268
|
}
|
|
238
269
|
if (options.body !== void 0) {
|
|
239
270
|
headers["Content-Type"] = "application/json";
|
|
@@ -247,7 +278,7 @@ var HttpClient = class {
|
|
|
247
278
|
credentials: this.options.withCredentials ? "include" : "same-origin"
|
|
248
279
|
}
|
|
249
280
|
);
|
|
250
|
-
const session =
|
|
281
|
+
const session = readSessionFromResponse(response);
|
|
251
282
|
if (session) this.options.onSessionCookie?.(session);
|
|
252
283
|
const body = await parseBody(response);
|
|
253
284
|
if (response.status === 401 && needsAuth && !retried && this.options.onUnauthorized) {
|
|
@@ -832,6 +863,7 @@ var SabhaClient = class {
|
|
|
832
863
|
);
|
|
833
864
|
this.config = {
|
|
834
865
|
withCredentials: true,
|
|
866
|
+
persistSession: true,
|
|
835
867
|
...this.config,
|
|
836
868
|
...config,
|
|
837
869
|
baseUrl
|
|
@@ -840,14 +872,12 @@ var SabhaClient = class {
|
|
|
840
872
|
...DEFAULT_MEDIA_POLICY,
|
|
841
873
|
...this.config.mediaPolicy
|
|
842
874
|
};
|
|
875
|
+
const stored = this.config.persistSession !== false ? readStoredSessionCookie() : null;
|
|
843
876
|
this.tokens = {
|
|
844
877
|
accessToken: config.accessToken ?? this.tokens?.accessToken,
|
|
845
878
|
refreshToken: config.refreshToken ?? this.tokens?.refreshToken,
|
|
846
|
-
sessionCookie: config.sessionCookie ?? this.tokens?.sessionCookie
|
|
879
|
+
sessionCookie: config.sessionCookie ?? this.tokens?.sessionCookie ?? stored ?? void 0
|
|
847
880
|
};
|
|
848
|
-
if (!this.tokens.accessToken && !this.tokens.sessionCookie && !this.tokens.refreshToken) {
|
|
849
|
-
if (!config.accessToken && !config.sessionCookie && !config.refreshToken) ;
|
|
850
|
-
}
|
|
851
881
|
const hasAnyToken = Boolean(
|
|
852
882
|
this.tokens.accessToken || this.tokens.sessionCookie || this.tokens.refreshToken
|
|
853
883
|
);
|
|
@@ -861,10 +891,7 @@ var SabhaClient = class {
|
|
|
861
891
|
this.tokens = tokens;
|
|
862
892
|
},
|
|
863
893
|
onSessionCookie: (cookie) => {
|
|
864
|
-
this.
|
|
865
|
-
...this.tokens ?? {},
|
|
866
|
-
sessionCookie: cookie ?? void 0
|
|
867
|
-
};
|
|
894
|
+
this.persistSessionCookie(cookie);
|
|
868
895
|
},
|
|
869
896
|
onUnauthorized: () => this.tryRefresh()
|
|
870
897
|
});
|
|
@@ -906,28 +933,41 @@ var SabhaClient = class {
|
|
|
906
933
|
clearSession() {
|
|
907
934
|
this.tokens = null;
|
|
908
935
|
this.user = null;
|
|
936
|
+
this.persistSessionCookie(null);
|
|
909
937
|
this.activeConnection?.disconnect();
|
|
910
938
|
this.activeConnection = null;
|
|
911
939
|
}
|
|
912
940
|
async login(input) {
|
|
913
941
|
const session = await this.auth().login(input);
|
|
914
942
|
this.applySession(session);
|
|
943
|
+
if (session.accessToken) {
|
|
944
|
+
this.persistSessionCookie(this.tokens?.sessionCookie ?? null);
|
|
945
|
+
} else if (session.sessionCookie || this.tokens?.sessionCookie) {
|
|
946
|
+
this.persistSessionCookie(session.sessionCookie ?? this.tokens?.sessionCookie ?? null);
|
|
947
|
+
}
|
|
915
948
|
try {
|
|
916
949
|
const me = await this.auth().me();
|
|
917
950
|
this.user = me;
|
|
918
951
|
session.user = me;
|
|
952
|
+
session.sessionCookie = this.tokens?.sessionCookie;
|
|
953
|
+
return session;
|
|
919
954
|
} catch (error) {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
"Login returned a user profile but no Sabha session was established. The API did not set `vm_session` (and no JWT token was returned), so POST /api/meetings will return 401 Sign in first. Fix session cookies on sabha-api (Set-Cookie: vm_session; SameSite=None; Secure for cross-origin) or return a bearer token from /api/auth/login.",
|
|
923
|
-
{
|
|
924
|
-
code: "SESSION_NOT_ESTABLISHED",
|
|
925
|
-
status: 401,
|
|
926
|
-
cause: error
|
|
927
|
-
}
|
|
955
|
+
const hasCredential = Boolean(
|
|
956
|
+
this.tokens?.accessToken || this.tokens?.sessionCookie
|
|
928
957
|
);
|
|
958
|
+
if (!hasCredential) {
|
|
959
|
+
this.clearSession();
|
|
960
|
+
throw new SabhaError(
|
|
961
|
+
"Login returned a user profile but no auth credential. Need JWT `token` from /api/auth/login (Postman) or Set-Cookie vm_session (exposed to the app as x-sabha-session via /sabha proxy). Without that, POST /api/meetings returns 401 Sign in first.",
|
|
962
|
+
{
|
|
963
|
+
code: "SESSION_NOT_ESTABLISHED",
|
|
964
|
+
status: 401,
|
|
965
|
+
cause: error
|
|
966
|
+
}
|
|
967
|
+
);
|
|
968
|
+
}
|
|
969
|
+
throw error;
|
|
929
970
|
}
|
|
930
|
-
return session;
|
|
931
971
|
}
|
|
932
972
|
/** Throws if /api/auth/me fails — call before create/start meeting. */
|
|
933
973
|
async ensureAuthenticated() {
|
|
@@ -1057,6 +1097,23 @@ var SabhaClient = class {
|
|
|
1057
1097
|
refreshToken: session.refreshToken ?? this.tokens?.refreshToken,
|
|
1058
1098
|
sessionCookie: session.sessionCookie ?? this.tokens?.sessionCookie
|
|
1059
1099
|
};
|
|
1100
|
+
if (this.tokens.sessionCookie) {
|
|
1101
|
+
this.persistSessionCookie(this.tokens.sessionCookie);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
persistSessionCookie(cookie) {
|
|
1105
|
+
if (cookie) {
|
|
1106
|
+
this.tokens = {
|
|
1107
|
+
...this.tokens ?? {},
|
|
1108
|
+
sessionCookie: cookie
|
|
1109
|
+
};
|
|
1110
|
+
} else if (this.tokens) {
|
|
1111
|
+
const { sessionCookie: _removed, ...rest } = this.tokens;
|
|
1112
|
+
this.tokens = Object.keys(rest).length ? rest : null;
|
|
1113
|
+
}
|
|
1114
|
+
if (this.config.persistSession !== false) {
|
|
1115
|
+
writeStoredSessionCookie(cookie ?? null);
|
|
1116
|
+
}
|
|
1060
1117
|
}
|
|
1061
1118
|
async tryRefresh() {
|
|
1062
1119
|
if (!this.tokens?.refreshToken) return false;
|
|
@@ -1119,6 +1176,7 @@ function SabhaProvider({
|
|
|
1119
1176
|
const resolvedConfig = {
|
|
1120
1177
|
baseUrl: DEFAULT_BASE_URL,
|
|
1121
1178
|
withCredentials: true,
|
|
1179
|
+
persistSession: true,
|
|
1122
1180
|
...config
|
|
1123
1181
|
};
|
|
1124
1182
|
const client = react.useMemo(
|
|
@@ -1456,13 +1514,17 @@ exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
|
|
|
1456
1514
|
exports.DEFAULT_MEDIA_POLICY = DEFAULT_MEDIA_POLICY;
|
|
1457
1515
|
exports.MediaController = MediaController;
|
|
1458
1516
|
exports.MeetingConnection = MeetingConnection;
|
|
1517
|
+
exports.SABHA_SESSION_HEADER = SABHA_SESSION_HEADER;
|
|
1518
|
+
exports.SABHA_SESSION_STORAGE_KEY = SABHA_SESSION_STORAGE_KEY;
|
|
1459
1519
|
exports.SabhaClient = SabhaClient;
|
|
1460
1520
|
exports.SabhaError = SabhaError;
|
|
1461
1521
|
exports.SabhaProvider = SabhaProvider;
|
|
1462
1522
|
exports.createSabhaClient = createSabhaClient;
|
|
1463
1523
|
exports.normalizeMeeting = normalizeMeeting;
|
|
1524
|
+
exports.readStoredSessionCookie = readStoredSessionCookie;
|
|
1464
1525
|
exports.toSabhaError = toSabhaError;
|
|
1465
1526
|
exports.useSabha = useSabha;
|
|
1466
1527
|
exports.useSabhaMeetings = useSabhaMeetings;
|
|
1528
|
+
exports.writeStoredSessionCookie = writeStoredSessionCookie;
|
|
1467
1529
|
//# sourceMappingURL=index.js.map
|
|
1468
1530
|
//# sourceMappingURL=index.js.map
|