@iblai/web-utils 1.11.12 → 1.12.0
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/auth/web-utils/src/features/tracking/time-tracker.d.ts +55 -4
- package/dist/index.d.ts +56 -5
- package/dist/index.esm.js +187 -12
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +187 -12
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/web-utils/src/features/tracking/time-tracker.d.ts +55 -4
- package/dist/web-utils/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11914,46 +11914,117 @@ const selectIsReasoning = (state) => state.chatSliceShared.currentStreamingMessa
|
|
|
11914
11914
|
// NEW: Get streaming tool calls
|
|
11915
11915
|
const selectStreamingToolCalls = (state) => state.chatSliceShared.currentStreamingMessage.toolCalls;
|
|
11916
11916
|
|
|
11917
|
+
const DEFAULT_IDLE_TIMEOUT_SECONDS = 120;
|
|
11918
|
+
// Minimum gap between idle-timer resets. Interaction events like mousemove fire
|
|
11919
|
+
// rapidly; there's no need to restart the (minutes-long) idle countdown more
|
|
11920
|
+
// than once per second.
|
|
11921
|
+
const ACTIVITY_THROTTLE_MS = 1000;
|
|
11922
|
+
// User interactions that count as activity and keep the user "present".
|
|
11923
|
+
const ACTIVITY_EVENTS = [
|
|
11924
|
+
"mousemove",
|
|
11925
|
+
"mousedown",
|
|
11926
|
+
"keydown",
|
|
11927
|
+
"wheel",
|
|
11928
|
+
"scroll",
|
|
11929
|
+
"touchstart",
|
|
11930
|
+
"pointerdown",
|
|
11931
|
+
];
|
|
11917
11932
|
class TimeTracker {
|
|
11918
11933
|
constructor(config) {
|
|
11934
|
+
var _a, _b, _c;
|
|
11919
11935
|
this.state = {
|
|
11920
11936
|
currentUrl: "",
|
|
11921
|
-
startTime: 0,
|
|
11922
11937
|
intervalId: null,
|
|
11923
11938
|
routeUnsubscribe: null,
|
|
11939
|
+
accumulatedMs: 0,
|
|
11940
|
+
activeSince: null,
|
|
11941
|
+
isVisible: true,
|
|
11942
|
+
isFocused: true,
|
|
11943
|
+
isIdle: false,
|
|
11944
|
+
idleTimerId: null,
|
|
11924
11945
|
};
|
|
11946
|
+
// Timestamp of the last activity that reset the idle timer (for throttling).
|
|
11947
|
+
this.lastActivityAt = 0;
|
|
11948
|
+
// Bound listeners kept so they can be removed on destroy.
|
|
11949
|
+
this.handleActivity = () => this.onActivity();
|
|
11950
|
+
this.handleVisibilityChange = () => this.onVisibilityChange();
|
|
11951
|
+
this.handleWindowFocus = () => this.onWindowFocus();
|
|
11952
|
+
this.handleWindowBlur = () => this.onWindowBlur();
|
|
11925
11953
|
this.config = config;
|
|
11954
|
+
this.idleTimeoutMs =
|
|
11955
|
+
((_a = config.idleTimeoutSeconds) !== null && _a !== void 0 ? _a : DEFAULT_IDLE_TIMEOUT_SECONDS) * 1000;
|
|
11956
|
+
this.pauseOnHidden = (_b = config.pauseOnHidden) !== null && _b !== void 0 ? _b : true;
|
|
11957
|
+
this.pauseOnBlur = (_c = config.pauseOnBlur) !== null && _c !== void 0 ? _c : true;
|
|
11958
|
+
this.idleDetectionEnabled =
|
|
11959
|
+
this.idleTimeoutMs > 0 &&
|
|
11960
|
+
typeof window !== "undefined" &&
|
|
11961
|
+
typeof document !== "undefined";
|
|
11926
11962
|
this.initialize();
|
|
11927
11963
|
}
|
|
11928
11964
|
initialize() {
|
|
11929
11965
|
this.state.currentUrl = this.config.getCurrentUrl();
|
|
11966
|
+
// Seed activity signals from the current environment.
|
|
11967
|
+
if (this.pauseOnHidden && typeof document !== "undefined") {
|
|
11968
|
+
this.state.isVisible = !document.hidden;
|
|
11969
|
+
}
|
|
11970
|
+
this.state.isFocused = true;
|
|
11971
|
+
this.state.isIdle = false;
|
|
11972
|
+
this.attachActivityListeners();
|
|
11930
11973
|
this.startTracking();
|
|
11974
|
+
this.startIdleTimer();
|
|
11931
11975
|
if (this.config.onRouteChange) {
|
|
11932
11976
|
this.state.routeUnsubscribe = this.config.onRouteChange(() => {
|
|
11933
11977
|
this.handleRouteChange();
|
|
11934
11978
|
});
|
|
11935
11979
|
}
|
|
11936
11980
|
}
|
|
11981
|
+
// --- Active time accounting -------------------------------------------------
|
|
11982
|
+
/** Whether time should currently be counted. */
|
|
11983
|
+
isActive() {
|
|
11984
|
+
return this.state.isVisible && this.state.isFocused && !this.state.isIdle;
|
|
11985
|
+
}
|
|
11986
|
+
/**
|
|
11987
|
+
* Reconcile the active window with the current activity signals: open a new
|
|
11988
|
+
* window when the user becomes active, or bank the elapsed time when they
|
|
11989
|
+
* become inactive.
|
|
11990
|
+
*/
|
|
11991
|
+
syncActiveWindow() {
|
|
11992
|
+
const active = this.isActive();
|
|
11993
|
+
if (active && this.state.activeSince === null) {
|
|
11994
|
+
this.state.activeSince = Date.now();
|
|
11995
|
+
}
|
|
11996
|
+
else if (!active && this.state.activeSince !== null) {
|
|
11997
|
+
this.state.accumulatedMs += Date.now() - this.state.activeSince;
|
|
11998
|
+
this.state.activeSince = null;
|
|
11999
|
+
}
|
|
12000
|
+
}
|
|
12001
|
+
getTimeSpent() {
|
|
12002
|
+
let total = this.state.accumulatedMs;
|
|
12003
|
+
if (this.state.activeSince !== null) {
|
|
12004
|
+
total += Date.now() - this.state.activeSince;
|
|
12005
|
+
}
|
|
12006
|
+
return total;
|
|
12007
|
+
}
|
|
12008
|
+
resetTimer() {
|
|
12009
|
+
this.state.accumulatedMs = 0;
|
|
12010
|
+
this.state.activeSince = this.isActive() ? Date.now() : null;
|
|
12011
|
+
}
|
|
11937
12012
|
startTracking() {
|
|
11938
|
-
this.
|
|
11939
|
-
this.
|
|
12013
|
+
this.clearTrackingInterval();
|
|
12014
|
+
this.resetTimer();
|
|
12015
|
+
if (typeof window === "undefined")
|
|
12016
|
+
return;
|
|
11940
12017
|
this.state.intervalId = window.setInterval(() => {
|
|
11941
12018
|
this.sendTimeUpdate();
|
|
11942
12019
|
this.resetTimer();
|
|
11943
12020
|
}, this.config.intervalSeconds * 1000);
|
|
11944
12021
|
}
|
|
11945
|
-
|
|
12022
|
+
clearTrackingInterval() {
|
|
11946
12023
|
if (this.state.intervalId !== null) {
|
|
11947
12024
|
clearInterval(this.state.intervalId);
|
|
11948
12025
|
this.state.intervalId = null;
|
|
11949
12026
|
}
|
|
11950
12027
|
}
|
|
11951
|
-
resetTimer() {
|
|
11952
|
-
this.state.startTime = Date.now();
|
|
11953
|
-
}
|
|
11954
|
-
getTimeSpent() {
|
|
11955
|
-
return Date.now() - this.state.startTime;
|
|
11956
|
-
}
|
|
11957
12028
|
sendTimeUpdate() {
|
|
11958
12029
|
const timeSpent = this.getTimeSpent();
|
|
11959
12030
|
if (timeSpent > 0) {
|
|
@@ -11968,16 +12039,116 @@ class TimeTracker {
|
|
|
11968
12039
|
this.resetTimer();
|
|
11969
12040
|
}
|
|
11970
12041
|
}
|
|
12042
|
+
// --- Activity / inactivity detection ---------------------------------------
|
|
12043
|
+
attachActivityListeners() {
|
|
12044
|
+
if (typeof window !== "undefined" && window.addEventListener) {
|
|
12045
|
+
if (this.idleDetectionEnabled) {
|
|
12046
|
+
for (const event of ACTIVITY_EVENTS) {
|
|
12047
|
+
window.addEventListener(event, this.handleActivity, {
|
|
12048
|
+
passive: true,
|
|
12049
|
+
});
|
|
12050
|
+
}
|
|
12051
|
+
}
|
|
12052
|
+
if (this.pauseOnBlur) {
|
|
12053
|
+
window.addEventListener("focus", this.handleWindowFocus);
|
|
12054
|
+
window.addEventListener("blur", this.handleWindowBlur);
|
|
12055
|
+
}
|
|
12056
|
+
}
|
|
12057
|
+
if (this.pauseOnHidden &&
|
|
12058
|
+
typeof document !== "undefined" &&
|
|
12059
|
+
document.addEventListener) {
|
|
12060
|
+
document.addEventListener("visibilitychange", this.handleVisibilityChange);
|
|
12061
|
+
}
|
|
12062
|
+
}
|
|
12063
|
+
detachActivityListeners() {
|
|
12064
|
+
if (typeof window !== "undefined" && window.removeEventListener) {
|
|
12065
|
+
for (const event of ACTIVITY_EVENTS) {
|
|
12066
|
+
window.removeEventListener(event, this.handleActivity);
|
|
12067
|
+
}
|
|
12068
|
+
window.removeEventListener("focus", this.handleWindowFocus);
|
|
12069
|
+
window.removeEventListener("blur", this.handleWindowBlur);
|
|
12070
|
+
}
|
|
12071
|
+
if (typeof document !== "undefined" && document.removeEventListener) {
|
|
12072
|
+
document.removeEventListener("visibilitychange", this.handleVisibilityChange);
|
|
12073
|
+
}
|
|
12074
|
+
}
|
|
12075
|
+
startIdleTimer() {
|
|
12076
|
+
if (!this.idleDetectionEnabled)
|
|
12077
|
+
return;
|
|
12078
|
+
this.clearIdleTimer();
|
|
12079
|
+
this.lastActivityAt = Date.now();
|
|
12080
|
+
this.state.idleTimerId = window.setTimeout(() => {
|
|
12081
|
+
this.markIdle();
|
|
12082
|
+
}, this.idleTimeoutMs);
|
|
12083
|
+
}
|
|
12084
|
+
clearIdleTimer() {
|
|
12085
|
+
if (this.state.idleTimerId !== null) {
|
|
12086
|
+
clearTimeout(this.state.idleTimerId);
|
|
12087
|
+
this.state.idleTimerId = null;
|
|
12088
|
+
}
|
|
12089
|
+
}
|
|
12090
|
+
markIdle() {
|
|
12091
|
+
if (this.state.isIdle)
|
|
12092
|
+
return;
|
|
12093
|
+
this.state.isIdle = true;
|
|
12094
|
+
this.syncActiveWindow();
|
|
12095
|
+
}
|
|
12096
|
+
onActivity() {
|
|
12097
|
+
// Returning from idle must always restart the countdown immediately.
|
|
12098
|
+
if (this.state.isIdle) {
|
|
12099
|
+
this.state.isIdle = false;
|
|
12100
|
+
this.syncActiveWindow();
|
|
12101
|
+
this.startIdleTimer();
|
|
12102
|
+
return;
|
|
12103
|
+
}
|
|
12104
|
+
// Otherwise throttle: no need to reset a minutes-long timer on every
|
|
12105
|
+
// mousemove.
|
|
12106
|
+
if (Date.now() - this.lastActivityAt < ACTIVITY_THROTTLE_MS)
|
|
12107
|
+
return;
|
|
12108
|
+
this.startIdleTimer();
|
|
12109
|
+
}
|
|
12110
|
+
onVisibilityChange() {
|
|
12111
|
+
if (typeof document === "undefined")
|
|
12112
|
+
return;
|
|
12113
|
+
this.state.isVisible = !document.hidden;
|
|
12114
|
+
if (this.state.isVisible) {
|
|
12115
|
+
// Returning to the tab counts as being present again.
|
|
12116
|
+
this.state.isIdle = false;
|
|
12117
|
+
this.startIdleTimer();
|
|
12118
|
+
}
|
|
12119
|
+
this.syncActiveWindow();
|
|
12120
|
+
}
|
|
12121
|
+
onWindowFocus() {
|
|
12122
|
+
this.state.isFocused = true;
|
|
12123
|
+
this.state.isIdle = false;
|
|
12124
|
+
this.startIdleTimer();
|
|
12125
|
+
this.syncActiveWindow();
|
|
12126
|
+
}
|
|
12127
|
+
onWindowBlur() {
|
|
12128
|
+
this.state.isFocused = false;
|
|
12129
|
+
this.syncActiveWindow();
|
|
12130
|
+
}
|
|
12131
|
+
// --- Public API -------------------------------------------------------------
|
|
11971
12132
|
pause() {
|
|
11972
12133
|
this.sendTimeUpdate();
|
|
11973
|
-
this.
|
|
12134
|
+
this.clearTrackingInterval();
|
|
12135
|
+
this.clearIdleTimer();
|
|
12136
|
+
// Stop accounting until resumed.
|
|
12137
|
+
this.state.accumulatedMs = 0;
|
|
12138
|
+
this.state.activeSince = null;
|
|
11974
12139
|
}
|
|
11975
12140
|
resume() {
|
|
12141
|
+
// Treat resume as a fresh, present start so a stale idle flag can't keep
|
|
12142
|
+
// the tracker from counting.
|
|
12143
|
+
this.state.isIdle = false;
|
|
11976
12144
|
this.startTracking();
|
|
12145
|
+
this.startIdleTimer();
|
|
11977
12146
|
}
|
|
11978
12147
|
destroy() {
|
|
11979
12148
|
this.sendTimeUpdate();
|
|
11980
|
-
this.
|
|
12149
|
+
this.clearTrackingInterval();
|
|
12150
|
+
this.clearIdleTimer();
|
|
12151
|
+
this.detachActivityListeners();
|
|
11981
12152
|
if (this.state.routeUnsubscribe) {
|
|
11982
12153
|
this.state.routeUnsubscribe();
|
|
11983
12154
|
this.state.routeUnsubscribe = null;
|
|
@@ -11989,6 +12160,10 @@ class TimeTracker {
|
|
|
11989
12160
|
getTimeSpentSinceLastReset() {
|
|
11990
12161
|
return this.getTimeSpent();
|
|
11991
12162
|
}
|
|
12163
|
+
/** Whether the user is currently considered active (present & interacting). */
|
|
12164
|
+
getIsActive() {
|
|
12165
|
+
return this.isActive();
|
|
12166
|
+
}
|
|
11992
12167
|
}
|
|
11993
12168
|
|
|
11994
12169
|
function useTimeTracker(config) {
|