oidc-spa 4.2.1 → 4.3.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/src/oidc.ts CHANGED
@@ -7,6 +7,9 @@ import { fnv1aHashToHex } from "./tools/fnv1aHashToHex";
7
7
  import { Deferred } from "./tools/Deferred";
8
8
  import { decodeJwt } from "./tools/decodeJwt";
9
9
  import { getDownlinkAndRtt } from "./tools/getDownlinkAndRtt";
10
+ import { createIsUserActive } from "./tools/createIsUserActive";
11
+ import { createStartCountdown } from "./tools/startCountdown";
12
+ import type { StatefulObservable } from "./tools/StatefulObservable";
10
13
 
11
14
  export declare type Oidc<DecodedIdToken extends Record<string, unknown> = Record<string, unknown>> =
12
15
  | Oidc.LoggedIn<DecodedIdToken>
@@ -40,6 +43,9 @@ export declare namespace Oidc {
40
43
  | { redirectTo: "home" | "current page" }
41
44
  | { redirectTo: "specific url"; url: string }
42
45
  ) => Promise<never>;
46
+ subscribeToAutoLogoutCountdown: (
47
+ tickCallback: (params: { secondsLeft: number | undefined }) => void
48
+ ) => { unsubscribeFromAutoLogoutCountdown: () => void };
43
49
  };
44
50
 
45
51
  export type Tokens<DecodedIdToken extends Record<string, unknown> = Record<string, unknown>> =
@@ -120,8 +126,20 @@ export type ParamsOfCreateOidc<
120
126
  */
121
127
  publicUrl?: string;
122
128
  decodedIdTokenSchema?: { parse: (data: unknown) => DecodedIdToken };
129
+ /**
130
+ * This parameter defines after how many seconds of inactivity the user should be
131
+ * logged out automatically.
132
+ *
133
+ * WARNING: It should be configured on the identity server side
134
+ * as it's the authoritative source for security policies and not the client.
135
+ * If you don't provide this parameter it will be inferred from the refresh token expiration time.
136
+ * */
137
+ __unsafe_ssoSessionIdleSeconds?: number;
123
138
  };
124
139
 
140
+ let $isUserActive: StatefulObservable<boolean> | undefined = undefined;
141
+ const hotReloadCleanups = new Map<string, Set<() => void>>();
142
+
125
143
  /** @see: https://github.com/garronej/oidc-spa#option-1-usage-without-involving-the-ui-framework */
126
144
  export async function createOidc<
127
145
  DecodedIdToken extends Record<string, unknown> = Record<string, unknown>
@@ -133,7 +151,8 @@ export async function createOidc<
133
151
  transformUrlBeforeRedirect = url => url,
134
152
  extraQueryParams: extraQueryParamsOrGetter,
135
153
  publicUrl: publicUrl_params,
136
- decodedIdTokenSchema
154
+ decodedIdTokenSchema,
155
+ __unsafe_ssoSessionIdleSeconds
137
156
  } = params;
138
157
 
139
158
  const getExtraQueryParams = (() => {
@@ -161,6 +180,12 @@ export async function createOidc<
161
180
  })();
162
181
 
163
182
  const configHash = fnv1aHashToHex(`${issuerUri} ${clientId}`);
183
+
184
+ {
185
+ hotReloadCleanups.get(configHash)?.forEach(cleanup => cleanup());
186
+ hotReloadCleanups.set(configHash, new Set());
187
+ }
188
+
164
189
  const configHashKey = "configHash";
165
190
 
166
191
  const oidcClientTsUserManager = new OidcClientTsUserManager({
@@ -174,15 +199,17 @@ export async function createOidc<
174
199
  "silent_redirect_uri": `${publicUrl}/silent-sso.html?${configHashKey}=${configHash}`
175
200
  });
176
201
 
202
+ // NOTE: Only useful for Firefox, see note bellow.
177
203
  let lastPublicRoute: string | undefined = undefined;
178
204
 
179
- {
205
+ // NOTE: To call only if not logged in.
206
+ const startTrackingLastPublicRoute = () => {
180
207
  const realPushState = history.pushState.bind(history);
181
208
  history.pushState = function pushState(...args) {
182
209
  lastPublicRoute = window.location.href;
183
210
  return realPushState(...args);
184
211
  };
185
- }
212
+ };
186
213
 
187
214
  let hasLoginBeenCalled = false;
188
215
 
@@ -243,6 +270,9 @@ export async function createOidc<
243
270
  });
244
271
 
245
272
  if (doesCurrentHrefRequiresAuth) {
273
+ // NOTE: In Firefox, when the user navigate back from the login page
274
+ // the state of the app is restored. We don't want that to happen,
275
+ // we want to redirect the user to the last public page.
246
276
  const callback = () => {
247
277
  if (document.visibilityState === "visible") {
248
278
  document.removeEventListener("visibilitychange", callback);
@@ -259,6 +289,9 @@ export async function createOidc<
259
289
 
260
290
  await oidcClientTsUserManager.signinRedirect({
261
291
  redirect_uri,
292
+ // NOTE: This is for the behavior when the use presses the back button on the login pages.
293
+ // This is what happens when the user gave up the login process.
294
+ // We want to that to redirect to the last public page.
262
295
  "redirectMethod": doesCurrentHrefRequiresAuth ? "replace" : "assign"
263
296
  });
264
297
  return new Promise<never>(() => {});
@@ -507,7 +540,9 @@ export async function createOidc<
507
540
  "cause": error
508
541
  });
509
542
 
510
- console.error(`OIDC initilization error: ${initializationError.message}`);
543
+ console.error(`OIDC initialization error: ${initializationError.message}`);
544
+
545
+ startTrackingLastPublicRoute();
511
546
 
512
547
  return id<Oidc.NotLoggedIn>({
513
548
  ...common,
@@ -521,6 +556,8 @@ export async function createOidc<
521
556
  }
522
557
 
523
558
  if (initialTokens === undefined) {
559
+ startTrackingLastPublicRoute();
560
+
524
561
  return id<Oidc.NotLoggedIn>({
525
562
  ...common,
526
563
  "isUserLoggedIn": false,
@@ -531,6 +568,10 @@ export async function createOidc<
531
568
 
532
569
  let currentTokens = initialTokens;
533
570
 
571
+ const autoLogoutCountdownTickCallback = new Set<
572
+ (params: { secondsLeft: number | undefined }) => void
573
+ >();
574
+
534
575
  const onTokenChanges = new Set<() => void>();
535
576
 
536
577
  const oidc = id<Oidc.LoggedIn<DecodedIdToken>>({
@@ -583,24 +624,105 @@ export async function createOidc<
583
624
  onTokenChanges.delete(onTokenChange);
584
625
  }
585
626
  };
627
+ },
628
+ "subscribeToAutoLogoutCountdown": tickCallback => {
629
+ autoLogoutCountdownTickCallback.add(tickCallback);
630
+
631
+ const unsubscribeFromAutoLogoutCountdown = () => {
632
+ autoLogoutCountdownTickCallback.delete(tickCallback);
633
+ };
634
+
635
+ return { unsubscribeFromAutoLogoutCountdown };
586
636
  }
587
637
  });
588
638
 
589
- (function scheduleAutomaticRenew() {
590
- const msBeforeExpiration =
591
- Math.min(currentTokens.accessTokenExpirationTime, currentTokens.refreshTokenExpirationTime) -
592
- Date.now();
639
+ {
640
+ const getMsBeforeExpiration = () => {
641
+ // NOTE: In general the access token is supposed to have a shorter
642
+ // lifespan than the refresh token but we don't want to make any
643
+ // assumption here.
644
+ const tokenExpirationTime = Math.min(
645
+ currentTokens.accessTokenExpirationTime,
646
+ currentTokens.refreshTokenExpirationTime
647
+ );
593
648
 
594
- setTimeout(async () => {
595
- try {
596
- await oidc.renewTokens();
597
- } catch {
598
- await login({ "doesCurrentHrefRequiresAuth": true });
649
+ return tokenExpirationTime - Date.now();
650
+ };
651
+
652
+ // NOTE: We refresh the token 25 seconds before it expires.
653
+ // If the token expiration time is less than 25 seconds we refresh the token when
654
+ // only 1/10 of the token time is left.
655
+ const renewMsBeforeExpires = Math.min(25_000, getMsBeforeExpiration() * 0.1);
656
+
657
+ (function scheduleRenew() {
658
+ const timer = setTimeout(async () => {
659
+ tokenChangeUnsubscribe();
660
+
661
+ try {
662
+ await oidc.renewTokens();
663
+ } catch {
664
+ // NOTE: Here semantically it's wrong. The user may very well be
665
+ // on a page that require auth.
666
+ // However there's no way to enforce the browser to redirect back to
667
+ // the last public route if the user press back on the login page.
668
+ // This is due to the fact that pushing to history only works if it's
669
+ // triggered by a user interaction.
670
+ await login({ "doesCurrentHrefRequiresAuth": false });
671
+ }
672
+
673
+ scheduleRenew();
674
+ }, getMsBeforeExpiration() - renewMsBeforeExpires);
675
+
676
+ const { unsubscribe: tokenChangeUnsubscribe } = oidc.subscribeToTokensChange(() => {
677
+ clearTimeout(timer);
678
+ tokenChangeUnsubscribe();
679
+ scheduleRenew();
680
+ });
681
+ })();
682
+ }
683
+
684
+ {
685
+ const { startCountdown } = createStartCountdown({
686
+ "getCountdownEndTime": () =>
687
+ __unsafe_ssoSessionIdleSeconds ?? currentTokens.refreshTokenExpirationTime,
688
+ "tickCallback": ({ secondsLeft }) => {
689
+ autoLogoutCountdownTickCallback.forEach(tickCallback => tickCallback({ secondsLeft }));
690
+
691
+ if (secondsLeft === 0) {
692
+ oidc.logout({ "redirectTo": "current page" });
693
+ }
599
694
  }
695
+ });
600
696
 
601
- scheduleAutomaticRenew();
602
- }, msBeforeExpiration - /* min validity in seconds */ 25 * 1000);
603
- })();
697
+ let stopCountdown: (() => void) | undefined = undefined;
698
+
699
+ if ($isUserActive === undefined) {
700
+ $isUserActive = createIsUserActive({
701
+ "theUserIsConsideredInactiveAfterMsOfInactivity": 5_000
702
+ }).$isUserActive;
703
+ }
704
+
705
+ const { unsubscribe: unsubscribeFrom$isUserActive } = $isUserActive.subscribe(isUserActive => {
706
+ if (isUserActive) {
707
+ if (stopCountdown !== undefined) {
708
+ stopCountdown();
709
+ stopCountdown = undefined;
710
+ }
711
+ } else {
712
+ assert(stopCountdown === undefined);
713
+ stopCountdown = startCountdown().stopCountdown;
714
+ }
715
+ });
716
+
717
+ {
718
+ const hotReloadCleanupsForThisConfig = hotReloadCleanups.get(configHash);
719
+ assert(hotReloadCleanupsForThisConfig !== undefined);
720
+ hotReloadCleanupsForThisConfig.add(() => {
721
+ unsubscribeFrom$isUserActive();
722
+ stopCountdown?.();
723
+ });
724
+ }
725
+ }
604
726
 
605
727
  return oidc;
606
728
  }
package/src/react.tsx CHANGED
@@ -14,9 +14,11 @@ export namespace OidcReact {
14
14
  export type NotLoggedIn = Common & {
15
15
  isUserLoggedIn: false;
16
16
  login: Oidc.NotLoggedIn["login"];
17
+ initializationError: OidcInitializationError | undefined;
18
+
17
19
  oidcTokens?: never;
18
20
  logout?: never;
19
- initializationError: OidcInitializationError | undefined;
21
+ subscribeToAutoLogoutCountdown?: never;
20
22
  };
21
23
 
22
24
  export type LoggedIn<DecodedIdToken extends Record<string, unknown>> = Common & {
@@ -24,6 +26,10 @@ export namespace OidcReact {
24
26
  oidcTokens: Oidc.Tokens<DecodedIdToken>;
25
27
  logout: Oidc.LoggedIn["logout"];
26
28
  renewTokens: Oidc.LoggedIn["renewTokens"];
29
+ subscribeToAutoLogoutCountdown: (
30
+ tickCallback: (params: { secondsLeft: number | undefined }) => void
31
+ ) => { unsubscribeFromAutoLogoutCountdown: () => void };
32
+
27
33
  login?: never;
28
34
  initializationError?: never;
29
35
  };
@@ -160,7 +166,8 @@ export function createReactOidc<
160
166
  "isUserLoggedIn": true,
161
167
  oidcTokens,
162
168
  "logout": oidc.logout,
163
- "renewTokens": oidc.renewTokens
169
+ "renewTokens": oidc.renewTokens,
170
+ "subscribeToAutoLogoutCountdown": oidc.subscribeToAutoLogoutCountdown
164
171
  })
165
172
  )
166
173
  : id<OidcReact.NotLoggedIn>({
@@ -0,0 +1,52 @@
1
+ export type StatefulObservable<T> = {
2
+ current: T;
3
+ subscribe: (next: (data: T) => void) => Subscription;
4
+ };
5
+
6
+ export type StatefulReadonlyObservable<T> = {
7
+ readonly current: T;
8
+ subscribe: (next: (data: T) => void) => Subscription;
9
+ };
10
+
11
+ export type Subscription = {
12
+ unsubscribe(): void;
13
+ };
14
+
15
+ export function createStatefulObservable<T>(getInitialValue: () => T): StatefulObservable<T> {
16
+ let nextFunctions: ((data: T) => void)[] = [];
17
+
18
+ const { get, set } = (() => {
19
+ let wrappedState: [T] | undefined = undefined;
20
+
21
+ return {
22
+ "get": () => {
23
+ if (wrappedState === undefined) {
24
+ wrappedState = [getInitialValue()];
25
+ }
26
+ return wrappedState[0];
27
+ },
28
+ "set": (data: T) => {
29
+ wrappedState = [data];
30
+
31
+ nextFunctions.forEach(next => next(data));
32
+ }
33
+ };
34
+ })();
35
+
36
+ return Object.defineProperty(
37
+ {
38
+ "current": null as any as T,
39
+ "subscribe": (next: (data: T) => void) => {
40
+ nextFunctions.push(next);
41
+
42
+ return { "unsubscribe": () => nextFunctions.splice(nextFunctions.indexOf(next), 1) };
43
+ }
44
+ },
45
+ "current",
46
+ {
47
+ "enumerable": true,
48
+ get,
49
+ set
50
+ }
51
+ );
52
+ }
@@ -0,0 +1,41 @@
1
+ import { createStatefulObservable } from "./StatefulObservable";
2
+ import { subscribeToUserInteraction } from "./subscribeToUserInteraction";
3
+ import { assert } from "tsafe/assert";
4
+
5
+ export function createIsUserActive(params: { theUserIsConsideredInactiveAfterMsOfInactivity: number }) {
6
+ const { theUserIsConsideredInactiveAfterMsOfInactivity } = params;
7
+
8
+ // this should set itself to false whenever the user had performed no user interaction for a certain amount of time
9
+ const $isUserActive = createStatefulObservable(() => true);
10
+
11
+ const scheduleSetInactive = () => {
12
+ const timer = setTimeout(() => {
13
+ assert($isUserActive.current);
14
+ $isUserActive.current = false;
15
+ }, theUserIsConsideredInactiveAfterMsOfInactivity);
16
+ return () => {
17
+ clearTimeout(timer);
18
+ };
19
+ };
20
+
21
+ let clearScheduledSetInactive = scheduleSetInactive();
22
+
23
+ const { unsubscribeFromUserInteraction } = subscribeToUserInteraction({
24
+ "throttleMs": 1_000,
25
+ "callback": () => {
26
+ clearScheduledSetInactive();
27
+ clearScheduledSetInactive = scheduleSetInactive();
28
+
29
+ if (!$isUserActive.current) {
30
+ $isUserActive.current = true;
31
+ }
32
+ }
33
+ });
34
+
35
+ const disable$isUserActive = () => {
36
+ unsubscribeFromUserInteraction();
37
+ clearScheduledSetInactive();
38
+ };
39
+
40
+ return { $isUserActive, disable$isUserActive };
41
+ }
@@ -0,0 +1,23 @@
1
+ import { Deferred } from "./Deferred";
2
+
3
+ export function getPrUserInteraction() {
4
+ const d = new Deferred<void>();
5
+
6
+ const callback = () => {
7
+ d.resolve();
8
+ cleanup();
9
+ };
10
+
11
+ const cleanup = () => {
12
+ window.document.removeEventListener("mousemove", callback, false);
13
+ window.document.removeEventListener("keydown", callback, false);
14
+ };
15
+
16
+ window.document.addEventListener("mousemove", callback, false);
17
+ window.document.addEventListener("keydown", callback, false);
18
+
19
+ return {
20
+ "prUserInteraction": d.pr,
21
+ "cancelPrUserInteraction": cleanup
22
+ };
23
+ }
@@ -0,0 +1,35 @@
1
+ export function createStartCountdown(params: {
2
+ tickCallback: (params: { secondsLeft: number | undefined }) => void;
3
+ getCountdownEndTime: () => number;
4
+ }) {
5
+ const { getCountdownEndTime, tickCallback } = params;
6
+
7
+ const getCountdownEndInMs = () => getCountdownEndTime() - Date.now();
8
+
9
+ function startCountdown() {
10
+ let timer: ReturnType<typeof setTimeout>;
11
+
12
+ (async () => {
13
+ let secondsLeft = Math.floor(getCountdownEndInMs() / 1000);
14
+
15
+ while (secondsLeft >= 0) {
16
+ tickCallback({ secondsLeft });
17
+
18
+ await new Promise<void>(resolve => {
19
+ timer = setTimeout(resolve, 1_000);
20
+ });
21
+
22
+ secondsLeft--;
23
+ }
24
+ })();
25
+
26
+ const stopCountdown = () => {
27
+ clearTimeout(timer);
28
+ tickCallback({ "secondsLeft": undefined });
29
+ };
30
+
31
+ return { stopCountdown };
32
+ }
33
+
34
+ return { startCountdown };
35
+ }
@@ -0,0 +1,33 @@
1
+ import { getPrUserInteraction } from "./getPrUserInteraction";
2
+
3
+ export function subscribeToUserInteraction(params: { throttleMs: number; callback: () => void }) {
4
+ const { throttleMs } = params;
5
+
6
+ const cleanups = new Set<() => void>();
7
+
8
+ (async function callee() {
9
+ const { cancelPrUserInteraction, prUserInteraction } = getPrUserInteraction();
10
+
11
+ cleanups.add(cancelPrUserInteraction);
12
+
13
+ await prUserInteraction;
14
+
15
+ params.callback();
16
+
17
+ await new Promise<void>(resolve => {
18
+ const timer = setTimeout(resolve, throttleMs);
19
+ cleanups.add(() => {
20
+ clearTimeout(timer);
21
+ });
22
+ });
23
+
24
+ cleanups.clear();
25
+ callee();
26
+ })();
27
+
28
+ const unsubscribeFromUserInteraction = () => {
29
+ cleanups.forEach(cleanup => cleanup());
30
+ };
31
+
32
+ return { unsubscribeFromUserInteraction };
33
+ }
@@ -0,0 +1,12 @@
1
+ export type StatefulObservable<T> = {
2
+ current: T;
3
+ subscribe: (next: (data: T) => void) => Subscription;
4
+ };
5
+ export type StatefulReadonlyObservable<T> = {
6
+ readonly current: T;
7
+ subscribe: (next: (data: T) => void) => Subscription;
8
+ };
9
+ export type Subscription = {
10
+ unsubscribe(): void;
11
+ };
12
+ export declare function createStatefulObservable<T>(getInitialValue: () => T): StatefulObservable<T>;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createStatefulObservable = void 0;
4
+ function createStatefulObservable(getInitialValue) {
5
+ var nextFunctions = [];
6
+ var _a = (function () {
7
+ var wrappedState = undefined;
8
+ return {
9
+ "get": function () {
10
+ if (wrappedState === undefined) {
11
+ wrappedState = [getInitialValue()];
12
+ }
13
+ return wrappedState[0];
14
+ },
15
+ "set": function (data) {
16
+ wrappedState = [data];
17
+ nextFunctions.forEach(function (next) { return next(data); });
18
+ }
19
+ };
20
+ })(), get = _a.get, set = _a.set;
21
+ return Object.defineProperty({
22
+ "current": null,
23
+ "subscribe": function (next) {
24
+ nextFunctions.push(next);
25
+ return { "unsubscribe": function () { return nextFunctions.splice(nextFunctions.indexOf(next), 1); } };
26
+ }
27
+ }, "current", {
28
+ "enumerable": true,
29
+ get: get,
30
+ set: set
31
+ });
32
+ }
33
+ exports.createStatefulObservable = createStatefulObservable;
34
+ //# sourceMappingURL=StatefulObservable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatefulObservable.js","sourceRoot":"","sources":["../src/tools/StatefulObservable.ts"],"names":[],"mappings":";;;AAcA,SAAgB,wBAAwB,CAAI,eAAwB;IAChE,IAAI,aAAa,GAA0B,EAAE,CAAC;IAExC,IAAA,KAAe,CAAC;QAClB,IAAI,YAAY,GAAoB,SAAS,CAAC;QAE9C,OAAO;YACH,KAAK,EAAE;gBACH,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;oBAC7B,YAAY,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC;gBACvC,CAAC;gBACD,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;YAC3B,CAAC;YACD,KAAK,EAAE,UAAC,IAAO;gBACX,YAAY,GAAG,CAAC,IAAI,CAAC,CAAC;gBAEtB,aAAa,CAAC,OAAO,CAAC,UAAA,IAAI,IAAI,OAAA,IAAI,CAAC,IAAI,CAAC,EAAV,CAAU,CAAC,CAAC;YAC9C,CAAC;SACJ,CAAC;IACN,CAAC,CAAC,EAAE,EAhBI,GAAG,SAAA,EAAE,GAAG,SAgBZ,CAAC;IAEL,OAAO,MAAM,CAAC,cAAc,CACxB;QACI,SAAS,EAAE,IAAgB;QAC3B,WAAW,EAAE,UAAC,IAAuB;YACjC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEzB,OAAO,EAAE,aAAa,EAAE,cAAM,OAAA,aAAa,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAApD,CAAoD,EAAE,CAAC;QACzF,CAAC;KACJ,EACD,SAAS,EACT;QACI,YAAY,EAAE,IAAI;QAClB,GAAG,KAAA;QACH,GAAG,KAAA;KACN,CACJ,CAAC;AACN,CAAC;AArCD,4DAqCC"}
@@ -0,0 +1,6 @@
1
+ export declare function createIsUserActive(params: {
2
+ theUserIsConsideredInactiveAfterMsOfInactivity: number;
3
+ }): {
4
+ $isUserActive: import("./StatefulObservable").StatefulObservable<boolean>;
5
+ disable$isUserActive: () => void;
6
+ };
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createIsUserActive = void 0;
4
+ var StatefulObservable_1 = require("./StatefulObservable");
5
+ var subscribeToUserInteraction_1 = require("./subscribeToUserInteraction");
6
+ var assert_1 = require("tsafe/assert");
7
+ function createIsUserActive(params) {
8
+ var theUserIsConsideredInactiveAfterMsOfInactivity = params.theUserIsConsideredInactiveAfterMsOfInactivity;
9
+ // this should set itself to false whenever the user had performed no user interaction for a certain amount of time
10
+ var $isUserActive = (0, StatefulObservable_1.createStatefulObservable)(function () { return true; });
11
+ var scheduleSetInactive = function () {
12
+ var timer = setTimeout(function () {
13
+ (0, assert_1.assert)($isUserActive.current);
14
+ $isUserActive.current = false;
15
+ }, theUserIsConsideredInactiveAfterMsOfInactivity);
16
+ return function () {
17
+ clearTimeout(timer);
18
+ };
19
+ };
20
+ var clearScheduledSetInactive = scheduleSetInactive();
21
+ var unsubscribeFromUserInteraction = (0, subscribeToUserInteraction_1.subscribeToUserInteraction)({
22
+ "throttleMs": 1000,
23
+ "callback": function () {
24
+ clearScheduledSetInactive();
25
+ clearScheduledSetInactive = scheduleSetInactive();
26
+ if (!$isUserActive.current) {
27
+ $isUserActive.current = true;
28
+ }
29
+ }
30
+ }).unsubscribeFromUserInteraction;
31
+ var disable$isUserActive = function () {
32
+ unsubscribeFromUserInteraction();
33
+ clearScheduledSetInactive();
34
+ };
35
+ return { $isUserActive: $isUserActive, disable$isUserActive: disable$isUserActive };
36
+ }
37
+ exports.createIsUserActive = createIsUserActive;
38
+ //# sourceMappingURL=createIsUserActive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createIsUserActive.js","sourceRoot":"","sources":["../src/tools/createIsUserActive.ts"],"names":[],"mappings":";;;AAAA,2DAAgE;AAChE,2EAA0E;AAC1E,uCAAsC;AAEtC,SAAgB,kBAAkB,CAAC,MAAkE;IACzF,IAAA,8CAA8C,GAAK,MAAM,+CAAX,CAAY;IAElE,mHAAmH;IACnH,IAAM,aAAa,GAAG,IAAA,6CAAwB,EAAC,cAAM,OAAA,IAAI,EAAJ,CAAI,CAAC,CAAC;IAE3D,IAAM,mBAAmB,GAAG;QACxB,IAAM,KAAK,GAAG,UAAU,CAAC;YACrB,IAAA,eAAM,EAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC9B,aAAa,CAAC,OAAO,GAAG,KAAK,CAAC;QAClC,CAAC,EAAE,8CAA8C,CAAC,CAAC;QACnD,OAAO;YACH,YAAY,CAAC,KAAK,CAAC,CAAC;QACxB,CAAC,CAAC;IACN,CAAC,CAAC;IAEF,IAAI,yBAAyB,GAAG,mBAAmB,EAAE,CAAC;IAE9C,IAAA,8BAA8B,GAAK,IAAA,uDAA0B,EAAC;QAClE,YAAY,EAAE,IAAK;QACnB,UAAU,EAAE;YACR,yBAAyB,EAAE,CAAC;YAC5B,yBAAyB,GAAG,mBAAmB,EAAE,CAAC;YAElD,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;gBACzB,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;YACjC,CAAC;QACL,CAAC;KACJ,CAAC,+BAVoC,CAUnC;IAEH,IAAM,oBAAoB,GAAG;QACzB,8BAA8B,EAAE,CAAC;QACjC,yBAAyB,EAAE,CAAC;IAChC,CAAC,CAAC;IAEF,OAAO,EAAE,aAAa,eAAA,EAAE,oBAAoB,sBAAA,EAAE,CAAC;AACnD,CAAC;AApCD,gDAoCC"}
@@ -0,0 +1,4 @@
1
+ export declare function getPrUserInteraction(): {
2
+ prUserInteraction: Promise<void>;
3
+ cancelPrUserInteraction: () => void;
4
+ };
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPrUserInteraction = void 0;
4
+ var Deferred_1 = require("./Deferred");
5
+ function getPrUserInteraction() {
6
+ var d = new Deferred_1.Deferred();
7
+ var callback = function () {
8
+ d.resolve();
9
+ cleanup();
10
+ };
11
+ var cleanup = function () {
12
+ window.document.removeEventListener("mousemove", callback, false);
13
+ window.document.removeEventListener("keydown", callback, false);
14
+ };
15
+ window.document.addEventListener("mousemove", callback, false);
16
+ window.document.addEventListener("keydown", callback, false);
17
+ return {
18
+ "prUserInteraction": d.pr,
19
+ "cancelPrUserInteraction": cleanup
20
+ };
21
+ }
22
+ exports.getPrUserInteraction = getPrUserInteraction;
23
+ //# sourceMappingURL=getPrUserInteraction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getPrUserInteraction.js","sourceRoot":"","sources":["../src/tools/getPrUserInteraction.ts"],"names":[],"mappings":";;;AAAA,uCAAsC;AAEtC,SAAgB,oBAAoB;IAChC,IAAM,CAAC,GAAG,IAAI,mBAAQ,EAAQ,CAAC;IAE/B,IAAM,QAAQ,GAAG;QACb,CAAC,CAAC,OAAO,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACd,CAAC,CAAC;IAEF,IAAM,OAAO,GAAG;QACZ,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClE,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACpE,CAAC,CAAC;IAEF,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,WAAW,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/D,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAE7D,OAAO;QACH,mBAAmB,EAAE,CAAC,CAAC,EAAE;QACzB,yBAAyB,EAAE,OAAO;KACrC,CAAC;AACN,CAAC;AApBD,oDAoBC"}
@@ -0,0 +1,10 @@
1
+ export declare function createStartCountdown(params: {
2
+ tickCallback: (params: {
3
+ secondsLeft: number | undefined;
4
+ }) => void;
5
+ getCountdownEndTime: () => number;
6
+ }): {
7
+ startCountdown: () => {
8
+ stopCountdown: () => void;
9
+ };
10
+ };