@bounded-sh/core 0.0.23 → 0.0.24
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.js
CHANGED
|
@@ -2943,6 +2943,7 @@ class WebSessionManager {
|
|
|
2943
2943
|
/* STORE */
|
|
2944
2944
|
/* ------------------------------------------------------------------ */
|
|
2945
2945
|
static async storeSession(address, accessToken, idToken, refreshToken, issuer) {
|
|
2946
|
+
var _a;
|
|
2946
2947
|
if (typeof window === "undefined")
|
|
2947
2948
|
return;
|
|
2948
2949
|
// JWT-wallet binding: refuse to store a session whose idToken is bound
|
|
@@ -2965,7 +2966,7 @@ class WebSessionManager {
|
|
|
2965
2966
|
if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
|
|
2966
2967
|
throw err;
|
|
2967
2968
|
}
|
|
2968
|
-
console.warn("[WebSessionManager] storeSession: failed to decode idToken for validation:", err);
|
|
2969
|
+
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");
|
|
2969
2970
|
}
|
|
2970
2971
|
const config = await getConfig();
|
|
2971
2972
|
const currentAppId = config.appId;
|
|
@@ -2996,8 +2997,12 @@ class WebSessionManager {
|
|
|
2996
2997
|
}
|
|
2997
2998
|
/* ---------- check JWT expiration ---------- */
|
|
2998
2999
|
try {
|
|
2999
|
-
|
|
3000
|
-
|
|
3000
|
+
// Check expiry on the ID TOKEN — it is ALWAYS a JWT. The OIDC access_token for
|
|
3001
|
+
// email/social (hosted) logins is an OPAQUE string (not a JWT), so decoding IT
|
|
3002
|
+
// here threw and the catch below wiped a perfectly valid session — breaking
|
|
3003
|
+
// hosted login. The idToken carries the canonical identity (@user.id) + exp.
|
|
3004
|
+
const { idToken } = sessionObj;
|
|
3005
|
+
const { exp } = JSON.parse(this.decodeBase64Url(idToken.split(".")[1]));
|
|
3001
3006
|
if (Date.now() > exp * 1000) {
|
|
3002
3007
|
const { refreshToken } = sessionObj;
|
|
3003
3008
|
if (!refreshToken)
|
|
@@ -3157,6 +3162,7 @@ class ReactNativeSessionManager {
|
|
|
3157
3162
|
/* STORE */
|
|
3158
3163
|
/* ------------------------------------------------------------------ */
|
|
3159
3164
|
static async storeSession(address, accessToken, idToken, refreshToken, issuer) {
|
|
3165
|
+
var _a;
|
|
3160
3166
|
// JWT-wallet binding: refuse to store a session whose idToken is bound
|
|
3161
3167
|
// to a different wallet than `address`. Prevents races that would otherwise
|
|
3162
3168
|
// leave storage with mismatched address/token state.
|
|
@@ -3177,7 +3183,7 @@ class ReactNativeSessionManager {
|
|
|
3177
3183
|
if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("Refusing to store session")) {
|
|
3178
3184
|
throw err;
|
|
3179
3185
|
}
|
|
3180
|
-
console.warn("[ReactNativeSessionManager] storeSession: failed to decode idToken for validation:", err);
|
|
3186
|
+
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");
|
|
3181
3187
|
}
|
|
3182
3188
|
const config = await getConfig();
|
|
3183
3189
|
const currentAppId = config.appId;
|
|
@@ -3205,8 +3211,10 @@ class ReactNativeSessionManager {
|
|
|
3205
3211
|
}
|
|
3206
3212
|
/* ---------- check JWT expiration ---------- */
|
|
3207
3213
|
try {
|
|
3208
|
-
|
|
3209
|
-
|
|
3214
|
+
// Expiry on the ID TOKEN (always a JWT). The OIDC access_token for email/social
|
|
3215
|
+
// logins is opaque, so decoding it threw → the catch wiped a valid session.
|
|
3216
|
+
const { idToken } = sessionObj;
|
|
3217
|
+
const { exp } = JSON.parse(this.decodeBase64Url(idToken.split(".")[1]));
|
|
3210
3218
|
if (Date.now() > exp * 1000) {
|
|
3211
3219
|
const { refreshToken } = sessionObj;
|
|
3212
3220
|
if (!refreshToken)
|
|
@@ -5508,6 +5516,7 @@ function bearerFromAuthHeaders(headers) {
|
|
|
5508
5516
|
// Monotonic counter for unique-ish fallback identity keys (no Date.now in some envs).
|
|
5509
5517
|
let connectionEpoch = 0;
|
|
5510
5518
|
function isTokenExpired(token) {
|
|
5519
|
+
var _a;
|
|
5511
5520
|
try {
|
|
5512
5521
|
const payload = JSON.parse(decodeBase64Url(token.split('.')[1]));
|
|
5513
5522
|
const expirationTime = payload.exp * 1000;
|
|
@@ -5515,7 +5524,7 @@ function isTokenExpired(token) {
|
|
|
5515
5524
|
return currentTime > (expirationTime - 60000); // 60 second buffer
|
|
5516
5525
|
}
|
|
5517
5526
|
catch (error) {
|
|
5518
|
-
console.error('[WS v2] Error checking token expiration:', error);
|
|
5527
|
+
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');
|
|
5519
5528
|
return true;
|
|
5520
5529
|
}
|
|
5521
5530
|
}
|
|
@@ -6949,6 +6958,13 @@ function withoutAuthorization(headers) {
|
|
|
6949
6958
|
}
|
|
6950
6959
|
return Object.keys(clean).length > 0 ? clean : undefined;
|
|
6951
6960
|
}
|
|
6961
|
+
function hasAuthorization(headers) {
|
|
6962
|
+
if (!headers)
|
|
6963
|
+
return false;
|
|
6964
|
+
return Object.entries(headers).some(([key, value]) => key.toLowerCase() === 'authorization' &&
|
|
6965
|
+
typeof value === 'string' &&
|
|
6966
|
+
/^Bearer\s+\S+$/i.test(value.trim()));
|
|
6967
|
+
}
|
|
6952
6968
|
async function liveAuthHeader(configIsServer, overrides) {
|
|
6953
6969
|
if (overrides === null || overrides === void 0 ? void 0 : overrides._getAuthHeaders) {
|
|
6954
6970
|
return overrides._getAuthHeaders();
|
|
@@ -6974,6 +6990,12 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
6974
6990
|
throw new LiveIntentError('A room path is required');
|
|
6975
6991
|
}
|
|
6976
6992
|
const config = await getConfig();
|
|
6993
|
+
const initialAuthHeader = await liveAuthHeader(config.isServer, opts._overrides);
|
|
6994
|
+
if (!hasAuthorization(initialAuthHeader)) {
|
|
6995
|
+
if (opts.fireAndForget)
|
|
6996
|
+
return { ok: true };
|
|
6997
|
+
throw new LiveIntentError('Authentication required to send a live intent. Call init() and sign in before sending live room intents.', 401);
|
|
6998
|
+
}
|
|
6977
6999
|
// Ride the already-open per-room socket instead of a fresh HTTP POST per
|
|
6978
7000
|
// intent. That is what makes high-frequency input (~20-30Hz) cheap — one
|
|
6979
7001
|
// persistent connection, no per-intent TCP/TLS or connection-pool contention
|
|
@@ -7007,6 +7029,9 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
7007
7029
|
const overrideHeaders = withoutAuthorization((_b = opts._overrides) === null || _b === void 0 ? void 0 : _b.headers);
|
|
7008
7030
|
const buildHeaders = async () => {
|
|
7009
7031
|
const authHeader = await liveAuthHeader(config.isServer, opts._overrides);
|
|
7032
|
+
if (!hasAuthorization(authHeader)) {
|
|
7033
|
+
throw new LiveIntentError('Authentication required to send a live intent. Call init() and sign in before sending live room intents.', 401);
|
|
7034
|
+
}
|
|
7010
7035
|
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 : {}));
|
|
7011
7036
|
};
|
|
7012
7037
|
const controller = new AbortController();
|
|
@@ -7028,6 +7053,8 @@ async function intent(roomPath, intent, opts = {}) {
|
|
|
7028
7053
|
}
|
|
7029
7054
|
catch (err) {
|
|
7030
7055
|
clearTimeout(timer);
|
|
7056
|
+
if (err instanceof LiveIntentError)
|
|
7057
|
+
throw err;
|
|
7031
7058
|
if ((err === null || err === void 0 ? void 0 : err.name) === 'AbortError') {
|
|
7032
7059
|
throw new LiveIntentError(`Live intent to "${roomPath}" timed out after ${timeoutMs}ms`);
|
|
7033
7060
|
}
|