@bounded-sh/core 0.0.23 → 0.0.25
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.js +34 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -7
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -2923,6 +2923,7 @@ class WebSessionManager {
|
|
|
2923
2923
|
/* STORE */
|
|
2924
2924
|
/* ------------------------------------------------------------------ */
|
|
2925
2925
|
static async storeSession(address, accessToken, idToken, refreshToken, issuer) {
|
|
2926
|
+
var _a;
|
|
2926
2927
|
if (typeof window === "undefined")
|
|
2927
2928
|
return;
|
|
2928
2929
|
// JWT-wallet binding: refuse to store a session whose idToken is bound
|
|
@@ -2945,7 +2946,7 @@ class WebSessionManager {
|
|
|
2945
2946
|
if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
|
|
2946
2947
|
throw err;
|
|
2947
2948
|
}
|
|
2948
|
-
console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation:", err);
|
|
2949
|
+
console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation. reason:", (_a = err === null || err === void 0 ? void 0 : err.name) !== null && _a !== void 0 ? _a : "decode_failed");
|
|
2949
2950
|
}
|
|
2950
2951
|
const config = await getConfig();
|
|
2951
2952
|
const currentAppId = config.appId;
|
|
@@ -2976,8 +2977,12 @@ class WebSessionManager {
|
|
|
2976
2977
|
}
|
|
2977
2978
|
/* ---------- check JWT expiration ---------- */
|
|
2978
2979
|
try {
|
|
2979
|
-
|
|
2980
|
-
|
|
2980
|
+
// Check expiry on the ID TOKEN — it is ALWAYS a JWT. The OIDC access_token for
|
|
2981
|
+
// email/social (hosted) logins is an OPAQUE string (not a JWT), so decoding IT
|
|
2982
|
+
// here threw and the catch below wiped a perfectly valid session — breaking
|
|
2983
|
+
// hosted login. The idToken carries the canonical identity (@user.id) + exp.
|
|
2984
|
+
const { idToken } = sessionObj;
|
|
2985
|
+
const { exp } = JSON.parse(this.decodeBase64Url(idToken.split(".")[1]));
|
|
2981
2986
|
if (Date.now() > exp * 1000) {
|
|
2982
2987
|
const { refreshToken } = sessionObj;
|
|
2983
2988
|
if (!refreshToken)
|
|
@@ -3137,6 +3142,7 @@ class ReactNativeSessionManager {
|
|
|
3137
3142
|
/* STORE */
|
|
3138
3143
|
/* ------------------------------------------------------------------ */
|
|
3139
3144
|
static async storeSession(address, accessToken, idToken, refreshToken, issuer) {
|
|
3145
|
+
var _a;
|
|
3140
3146
|
// JWT-wallet binding: refuse to store a session whose idToken is bound
|
|
3141
3147
|
// to a different wallet than `address`. Prevents races that would otherwise
|
|
3142
3148
|
// leave storage with mismatched address/token state.
|
|
@@ -3157,7 +3163,7 @@ class ReactNativeSessionManager {
|
|
|
3157
3163
|
if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
|
|
3158
3164
|
throw err;
|
|
3159
3165
|
}
|
|
3160
|
-
console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation:", err);
|
|
3166
|
+
console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation. reason:", (_a = err === null || err === void 0 ? void 0 : err.name) !== null && _a !== void 0 ? _a : "decode_failed");
|
|
3161
3167
|
}
|
|
3162
3168
|
const config = await getConfig();
|
|
3163
3169
|
const currentAppId = config.appId;
|
|
@@ -3185,8 +3191,10 @@ class ReactNativeSessionManager {
|
|
|
3185
3191
|
}
|
|
3186
3192
|
/* ---------- check JWT expiration ---------- */
|
|
3187
3193
|
try {
|
|
3188
|
-
|
|
3189
|
-
|
|
3194
|
+
// Expiry on the ID TOKEN (always a JWT). The OIDC access_token for email/social
|
|
3195
|
+
// logins is opaque, so decoding it threw → the catch wiped a valid session.
|
|
3196
|
+
const { idToken } = sessionObj;
|
|
3197
|
+
const { exp } = JSON.parse(this.decodeBase64Url(idToken.split(".")[1]));
|
|
3190
3198
|
if (Date.now() > exp * 1000) {
|
|
3191
3199
|
const { refreshToken } = sessionObj;
|
|
3192
3200
|
if (!refreshToken)
|
|
@@ -5488,6 +5496,7 @@ function bearerFromAuthHeaders(headers) {
|
|
|
5488
5496
|
// Monotonic counter for unique-ish fallback identity keys (no Date.now in some envs).
|
|
5489
5497
|
let connectionEpoch = 0;
|
|
5490
5498
|
function isTokenExpired(token) {
|
|
5499
|
+
var _a;
|
|
5491
5500
|
try {
|
|
5492
5501
|
const payload = JSON.parse(decodeBase64Url(token.split('.')[1]));
|
|
5493
5502
|
const expirationTime = payload.exp * 1000;
|
|
@@ -5495,7 +5504,7 @@ function isTokenExpired(token) {
|
|
|
5495
5504
|
return currentTime > (expirationTime - 60000); // 60 second buffer
|
|
5496
5505
|
}
|
|
5497
5506
|
catch (error) {
|
|
5498
|
-
console.error('[WS v2] Error checking token expiration:', error);
|
|
5507
|
+
console.error('[WS v2] Error checking token expiration. reason:', (_a = error === null || error === void 0 ? void 0 : error.name) !== null && _a !== void 0 ? _a : 'decode_failed');
|
|
5499
5508
|
return true;
|
|
5500
5509
|
}
|
|
5501
5510
|
}
|
|
@@ -6929,6 +6938,13 @@ function withoutAuthorization(headers) {
|
|
|
6929
6938
|
}
|
|
6930
6939
|
return Object.keys(clean).length > 0 ? clean : undefined;
|
|
6931
6940
|
}
|
|
6941
|
+
function hasAuthorization(headers) {
|
|
6942
|
+
if (!headers)
|
|
6943
|
+
return false;
|
|
6944
|
+
return Object.entries(headers).some(([key, value]) => key.toLowerCase() === 'authorization' &&
|
|
6945
|
+
typeof value === 'string' &&
|
|
6946
|
+
/^Bearer\s+\S+$/i.test(value.trim()));
|
|
6947
|
+
}
|
|
6932
6948
|
async function liveAuthHeader(configIsServer, overrides) {
|
|
6933
6949
|
if (overrides === null || overrides === void 0 ? void 0 : overrides._getAuthHeaders) {
|
|
6934
6950
|
return overrides._getAuthHeaders();
|
|
@@ -6954,6 +6970,12 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
6954
6970
|
throw new LiveIntentError('A room path is required');
|
|
6955
6971
|
}
|
|
6956
6972
|
const config = await getConfig();
|
|
6973
|
+
const initialAuthHeader = await liveAuthHeader(config.isServer, opts._overrides);
|
|
6974
|
+
if (!hasAuthorization(initialAuthHeader)) {
|
|
6975
|
+
if (opts.fireAndForget)
|
|
6976
|
+
return { ok: true };
|
|
6977
|
+
throw new LiveIntentError('Authentication required to send a live intent. Call init() and sign in before sending live room intents.', 401);
|
|
6978
|
+
}
|
|
6957
6979
|
// Ride the already-open per-room socket instead of a fresh HTTP POST per
|
|
6958
6980
|
// intent. That is what makes high-frequency input (~20-30Hz) cheap — one
|
|
6959
6981
|
// persistent connection, no per-intent TCP/TLS or connection-pool contention
|
|
@@ -6987,6 +7009,9 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
6987
7009
|
const overrideHeaders = withoutAuthorization((_b = opts._overrides) === null || _b === void 0 ? void 0 : _b.headers);
|
|
6988
7010
|
const buildHeaders = async () => {
|
|
6989
7011
|
const authHeader = await liveAuthHeader(config.isServer, opts._overrides);
|
|
7012
|
+
if (!hasAuthorization(authHeader)) {
|
|
7013
|
+
throw new LiveIntentError('Authentication required to send a live intent. Call init() and sign in before sending live room intents.', 401);
|
|
7014
|
+
}
|
|
6990
7015
|
return Object.assign(Object.assign(Object.assign({ 'Content-Type': 'application/json', 'X-App-Id': config.appId }, (overrideHeaders !== null && overrideHeaders !== void 0 ? overrideHeaders : {})), (extraHeaders !== null && extraHeaders !== void 0 ? extraHeaders : {})), (authHeader !== null && authHeader !== void 0 ? authHeader : {}));
|
|
6991
7016
|
};
|
|
6992
7017
|
const controller = new AbortController();
|
|
@@ -7008,6 +7033,8 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
7008
7033
|
}
|
|
7009
7034
|
catch (err) {
|
|
7010
7035
|
clearTimeout(timer);
|
|
7036
|
+
if (err instanceof LiveIntentError)
|
|
7037
|
+
throw err;
|
|
7011
7038
|
if ((err === null || err === void 0 ? void 0 : err.name) === 'AbortError') {
|
|
7012
7039
|
throw new LiveIntentError(`Live intent to "${roomPath}" timed out after ${timeoutMs}ms`);
|
|
7013
7040
|
}
|