@pooflabs/core 0.0.28 → 0.0.29
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 +160 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +160 -26
- package/dist/index.mjs.map +1 -1
- package/dist/utils/utils.d.ts +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -204,6 +204,11 @@ class WebSessionManager {
|
|
|
204
204
|
}
|
|
205
205
|
WebSessionManager.TAROBASE_SESSION_STORAGE_KEY = "tarobase_session_storage";
|
|
206
206
|
|
|
207
|
+
var webSessionManager = /*#__PURE__*/Object.freeze({
|
|
208
|
+
__proto__: null,
|
|
209
|
+
WebSessionManager: WebSessionManager
|
|
210
|
+
});
|
|
211
|
+
|
|
207
212
|
function getDefaultExportFromCjs (x) {
|
|
208
213
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
209
214
|
}
|
|
@@ -3101,11 +3106,19 @@ class ServerSessionManager {
|
|
|
3101
3106
|
/* The single, shared instance */
|
|
3102
3107
|
ServerSessionManager.instance = new ServerSessionManager();
|
|
3103
3108
|
|
|
3109
|
+
var serverSessionManager = /*#__PURE__*/Object.freeze({
|
|
3110
|
+
__proto__: null,
|
|
3111
|
+
ServerSessionManager: ServerSessionManager
|
|
3112
|
+
});
|
|
3113
|
+
|
|
3104
3114
|
async function createBearerToken(isServer) {
|
|
3105
3115
|
if (isServer) {
|
|
3106
3116
|
const sessionMgr = ServerSessionManager.instance;
|
|
3107
3117
|
const session = await sessionMgr.getSession();
|
|
3108
|
-
|
|
3118
|
+
if (!(session === null || session === void 0 ? void 0 : session.idToken)) {
|
|
3119
|
+
return null;
|
|
3120
|
+
}
|
|
3121
|
+
return `Bearer ${session.idToken}`;
|
|
3109
3122
|
}
|
|
3110
3123
|
const idToken = WebSessionManager.getIdToken();
|
|
3111
3124
|
if (!idToken) {
|
|
@@ -3138,13 +3151,72 @@ async function getRefreshToken(isServer) {
|
|
|
3138
3151
|
}
|
|
3139
3152
|
return WebSessionManager.getRefreshToken();
|
|
3140
3153
|
}
|
|
3141
|
-
function updateIdTokenAndAccessToken(idToken, accessToken) {
|
|
3142
|
-
|
|
3154
|
+
async function updateIdTokenAndAccessToken(idToken, accessToken, isServer = false) {
|
|
3155
|
+
if (isServer) {
|
|
3156
|
+
const sessionMgr = ServerSessionManager.instance;
|
|
3157
|
+
// Ensure we have a session to update; if missing, let lazy creation happen on next request.
|
|
3158
|
+
let session = null;
|
|
3159
|
+
try {
|
|
3160
|
+
session = await sessionMgr.getSession();
|
|
3161
|
+
}
|
|
3162
|
+
catch (_a) {
|
|
3163
|
+
return;
|
|
3164
|
+
}
|
|
3165
|
+
if (!session) {
|
|
3166
|
+
return;
|
|
3167
|
+
}
|
|
3168
|
+
sessionMgr.setSession(Object.assign(Object.assign({}, session), { idToken,
|
|
3169
|
+
accessToken }));
|
|
3170
|
+
return;
|
|
3171
|
+
}
|
|
3172
|
+
await WebSessionManager.updateIdTokenAndAccessToken(idToken, accessToken);
|
|
3143
3173
|
}
|
|
3144
3174
|
|
|
3175
|
+
const refreshInFlight = new Map();
|
|
3176
|
+
async function refreshAuthSessionOnce(appId, isServer) {
|
|
3177
|
+
const key = `${isServer ? "server" : "web"}:${appId}`;
|
|
3178
|
+
const existing = refreshInFlight.get(key);
|
|
3179
|
+
if (existing) {
|
|
3180
|
+
return existing;
|
|
3181
|
+
}
|
|
3182
|
+
const refreshPromise = (async () => {
|
|
3183
|
+
var _a, _b;
|
|
3184
|
+
try {
|
|
3185
|
+
const refreshToken = await getRefreshToken(isServer);
|
|
3186
|
+
if (!refreshToken) {
|
|
3187
|
+
return false;
|
|
3188
|
+
}
|
|
3189
|
+
const refreshData = await refreshSession(refreshToken);
|
|
3190
|
+
if (!(refreshData === null || refreshData === void 0 ? void 0 : refreshData.idToken) || !(refreshData === null || refreshData === void 0 ? void 0 : refreshData.accessToken)) {
|
|
3191
|
+
return false;
|
|
3192
|
+
}
|
|
3193
|
+
await updateIdTokenAndAccessToken(refreshData.idToken, refreshData.accessToken, isServer);
|
|
3194
|
+
return true;
|
|
3195
|
+
}
|
|
3196
|
+
catch (error) {
|
|
3197
|
+
if (!isServer && (((_a = error === null || error === void 0 ? void 0 : error.response) === null || _a === void 0 ? void 0 : _a.status) === 401 || ((_b = error === null || error === void 0 ? void 0 : error.response) === null || _b === void 0 ? void 0 : _b.status) === 403)) {
|
|
3198
|
+
const { WebSessionManager } = await Promise.resolve().then(function () { return webSessionManager; });
|
|
3199
|
+
WebSessionManager.clearSession();
|
|
3200
|
+
}
|
|
3201
|
+
return false;
|
|
3202
|
+
}
|
|
3203
|
+
finally {
|
|
3204
|
+
refreshInFlight.delete(key);
|
|
3205
|
+
}
|
|
3206
|
+
})();
|
|
3207
|
+
refreshInFlight.set(key, refreshPromise);
|
|
3208
|
+
return refreshPromise;
|
|
3209
|
+
}
|
|
3145
3210
|
async function makeApiRequest(method, urlPath, data, _overrides) {
|
|
3146
3211
|
var _a, _b, _c, _d, _e, _f;
|
|
3147
3212
|
const config = await getConfig();
|
|
3213
|
+
let hasRetriedAfterServerSessionReset = false;
|
|
3214
|
+
const clearServerSession = async () => {
|
|
3215
|
+
if (!config.isServer)
|
|
3216
|
+
return;
|
|
3217
|
+
const { ServerSessionManager } = await Promise.resolve().then(function () { return serverSessionManager; });
|
|
3218
|
+
ServerSessionManager.instance.clearSession();
|
|
3219
|
+
};
|
|
3148
3220
|
async function executeRequest() {
|
|
3149
3221
|
const authHeader = await createAuthHeader(config.isServer);
|
|
3150
3222
|
const headers = Object.assign({ "Content-Type": "application/json", "X-Public-App-Id": config.appId, "X-App-Id": config.appId }, authHeader);
|
|
@@ -3176,19 +3248,20 @@ async function makeApiRequest(method, urlPath, data, _overrides) {
|
|
|
3176
3248
|
catch (error) {
|
|
3177
3249
|
if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 401) {
|
|
3178
3250
|
try {
|
|
3179
|
-
const
|
|
3180
|
-
if (!
|
|
3181
|
-
throw new Error("
|
|
3182
|
-
}
|
|
3183
|
-
const refreshData = await refreshSession(refreshToken);
|
|
3184
|
-
if (refreshData &&
|
|
3185
|
-
refreshData.idToken &&
|
|
3186
|
-
refreshData.accessToken) {
|
|
3187
|
-
updateIdTokenAndAccessToken(refreshData.idToken, refreshData.accessToken);
|
|
3251
|
+
const refreshed = await refreshAuthSessionOnce(config.appId, config.isServer);
|
|
3252
|
+
if (!refreshed) {
|
|
3253
|
+
throw new Error("Unable to refresh auth session");
|
|
3188
3254
|
}
|
|
3189
3255
|
return await executeRequest();
|
|
3190
3256
|
}
|
|
3191
|
-
catch (
|
|
3257
|
+
catch (_refreshError) {
|
|
3258
|
+
// Server-side fallback: clear cached session and retry once to force
|
|
3259
|
+
// createSession() with a fresh Cognito session.
|
|
3260
|
+
if (config.isServer && !hasRetriedAfterServerSessionReset) {
|
|
3261
|
+
hasRetriedAfterServerSessionReset = true;
|
|
3262
|
+
await clearServerSession();
|
|
3263
|
+
return await executeRequest();
|
|
3264
|
+
}
|
|
3192
3265
|
throw error;
|
|
3193
3266
|
}
|
|
3194
3267
|
}
|
|
@@ -3720,14 +3793,26 @@ const responseCache = new Map();
|
|
|
3720
3793
|
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
3721
3794
|
const TOKEN_REFRESH_BUFFER = 5 * 60 * 1000; // Refresh token 5 minutes before expiry
|
|
3722
3795
|
// ============ WebSocket Config ============
|
|
3796
|
+
const BASE_MIN_RECONNECT_DELAY_MS = 1000;
|
|
3797
|
+
const MIN_RECONNECT_DELAY_JITTER_MS = 1000;
|
|
3798
|
+
const MAX_RECONNECT_DELAY_MS = 300000;
|
|
3799
|
+
const RECONNECT_DELAY_GROW_FACTOR = 1.8;
|
|
3800
|
+
const MIN_BROWSER_RECONNECT_INTERVAL_MS = 30000;
|
|
3723
3801
|
const WS_CONFIG = {
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3802
|
+
// Keep retrying indefinitely so long outages recover without page refresh.
|
|
3803
|
+
maxRetries: Infinity,
|
|
3804
|
+
// Conservative starting delay with jitter spreads reconnects across clients.
|
|
3805
|
+
minReconnectionDelay: BASE_MIN_RECONNECT_DELAY_MS + Math.floor(Math.random() * MIN_RECONNECT_DELAY_JITTER_MS),
|
|
3806
|
+
// Stretch backoff to 5 minutes during prolonged outages to protect backend pools.
|
|
3807
|
+
maxReconnectionDelay: MAX_RECONNECT_DELAY_MS,
|
|
3808
|
+
// Moderate growth to avoid rapid retry bursts while still converging to max delay.
|
|
3809
|
+
reconnectionDelayGrowFactor: RECONNECT_DELAY_GROW_FACTOR,
|
|
3810
|
+
// Give handshakes more time before considering the attempt failed.
|
|
3811
|
+
connectionTimeout: 10000,
|
|
3729
3812
|
};
|
|
3730
3813
|
const WS_V2_PATH = '/ws/v2';
|
|
3814
|
+
let browserReconnectHooksAttached = false;
|
|
3815
|
+
let lastBrowserTriggeredReconnectAt = 0;
|
|
3731
3816
|
// ============ Helper Functions ============
|
|
3732
3817
|
function generateSubscriptionId() {
|
|
3733
3818
|
return `sub_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
@@ -3797,7 +3882,7 @@ async function getFreshAuthToken(isServer) {
|
|
|
3797
3882
|
}
|
|
3798
3883
|
const refreshData = await refreshSession(refreshToken);
|
|
3799
3884
|
if (refreshData && refreshData.idToken && refreshData.accessToken) {
|
|
3800
|
-
updateIdTokenAndAccessToken(refreshData.idToken, refreshData.accessToken);
|
|
3885
|
+
await updateIdTokenAndAccessToken(refreshData.idToken, refreshData.accessToken, isServer);
|
|
3801
3886
|
return refreshData.idToken;
|
|
3802
3887
|
}
|
|
3803
3888
|
}
|
|
@@ -3806,8 +3891,54 @@ async function getFreshAuthToken(isServer) {
|
|
|
3806
3891
|
}
|
|
3807
3892
|
return currentToken;
|
|
3808
3893
|
}
|
|
3894
|
+
function hasDisconnectedActiveConnections() {
|
|
3895
|
+
for (const connection of connections.values()) {
|
|
3896
|
+
if (!connection.ws) {
|
|
3897
|
+
continue;
|
|
3898
|
+
}
|
|
3899
|
+
// Only nudge reconnection when socket is fully closed.
|
|
3900
|
+
// If ReconnectingWebSocket is already in CONNECTING/backoff state, don't interfere.
|
|
3901
|
+
if (connection.ws.readyState === WS_READY_STATE_CLOSED) {
|
|
3902
|
+
return true;
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
return false;
|
|
3906
|
+
}
|
|
3907
|
+
function maybeReconnectFromBrowserSignal() {
|
|
3908
|
+
const now = Date.now();
|
|
3909
|
+
if (now - lastBrowserTriggeredReconnectAt < MIN_BROWSER_RECONNECT_INTERVAL_MS) {
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
if (!hasDisconnectedActiveConnections()) {
|
|
3913
|
+
return;
|
|
3914
|
+
}
|
|
3915
|
+
lastBrowserTriggeredReconnectAt = now;
|
|
3916
|
+
reconnectWithNewAuthV2().catch((error) => {
|
|
3917
|
+
console.error('[WS v2] Browser-triggered reconnect failed:', error);
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3920
|
+
function attachBrowserReconnectHooksOnce() {
|
|
3921
|
+
if (browserReconnectHooksAttached) {
|
|
3922
|
+
return;
|
|
3923
|
+
}
|
|
3924
|
+
if (typeof window === 'undefined') {
|
|
3925
|
+
return;
|
|
3926
|
+
}
|
|
3927
|
+
browserReconnectHooksAttached = true;
|
|
3928
|
+
window.addEventListener('online', () => {
|
|
3929
|
+
maybeReconnectFromBrowserSignal();
|
|
3930
|
+
});
|
|
3931
|
+
if (typeof document !== 'undefined') {
|
|
3932
|
+
document.addEventListener('visibilitychange', () => {
|
|
3933
|
+
if (document.visibilityState === 'visible') {
|
|
3934
|
+
maybeReconnectFromBrowserSignal();
|
|
3935
|
+
}
|
|
3936
|
+
});
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3809
3939
|
// ============ Connection Management ============
|
|
3810
3940
|
async function getOrCreateConnection(appId, isServer) {
|
|
3941
|
+
attachBrowserReconnectHooksOnce();
|
|
3811
3942
|
let connection = connections.get(appId);
|
|
3812
3943
|
if (connection && connection.ws) {
|
|
3813
3944
|
return connection;
|
|
@@ -3900,13 +4031,15 @@ function handleServerMessage(connection, message) {
|
|
|
3900
4031
|
case 'subscribed': {
|
|
3901
4032
|
const subscription = connection.subscriptions.get(message.subscriptionId);
|
|
3902
4033
|
if (subscription) {
|
|
3903
|
-
//
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
4034
|
+
// A data update can race ahead of subscribed during reconnect.
|
|
4035
|
+
// If we already received data for this subscription, treat subscribed
|
|
4036
|
+
// as an ack only and avoid regressing to an older snapshot.
|
|
4037
|
+
if (subscription.lastData === undefined) {
|
|
4038
|
+
const cacheKey = getCacheKey(subscription.path, subscription.prompt, subscription.shape);
|
|
4039
|
+
responseCache.set(cacheKey, { data: message.data, timestamp: Date.now() });
|
|
4040
|
+
subscription.lastData = message.data;
|
|
4041
|
+
notifyCallbacks(subscription, message.data);
|
|
4042
|
+
}
|
|
3910
4043
|
}
|
|
3911
4044
|
// Resolve pending subscription promise
|
|
3912
4045
|
const pending = connection.pendingSubscriptions.get(message.subscriptionId);
|
|
@@ -3972,6 +4105,7 @@ function notifyCallbacks(subscription, data) {
|
|
|
3972
4105
|
}
|
|
3973
4106
|
// WebSocket readyState constants
|
|
3974
4107
|
const WS_READY_STATE_OPEN = 1;
|
|
4108
|
+
const WS_READY_STATE_CLOSED = 3;
|
|
3975
4109
|
function sendSubscribe(connection, subscription) {
|
|
3976
4110
|
if (!connection.ws || connection.ws.readyState !== WS_READY_STATE_OPEN) {
|
|
3977
4111
|
return;
|