auth-vir 2.3.5 → 2.3.7

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.
@@ -99,7 +99,7 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
99
99
  * How long before a user's session times out when we should start trying to refresh their
100
100
  * session.
101
101
  *
102
- * @default {minutes: 5}
102
+ * @default {minutes: 10}
103
103
  */
104
104
  sessionRefreshThreshold: Readonly<AnyDuration>;
105
105
  overrides: PartialWithUndefined<{
@@ -7,6 +7,9 @@ import { parseJwtKeys } from '../jwt/jwt-keys.js';
7
7
  const defaultSessionIdleTimeout = {
8
8
  minutes: 20,
9
9
  };
10
+ const defaultSessionRefreshThreshold = {
11
+ minutes: 10,
12
+ };
10
13
  /**
11
14
  * An auth client for creating and validating JWTs embedded in cookies. This should only be used in
12
15
  * a backend environment as it accesses native Node packages.
@@ -72,9 +75,7 @@ export class BackendAuthClient {
72
75
  * - Z = JWT expiration outside the refresh threshold: {@link isRefreshReady} = false.
73
76
  */
74
77
  const isRefreshReady = isDateAfter({
75
- fullDate: calculateRelativeDate(now, this.config.sessionRefreshThreshold || {
76
- minutes: 5,
77
- }),
78
+ fullDate: calculateRelativeDate(now, this.config.sessionRefreshThreshold || defaultSessionRefreshThreshold),
78
79
  relativeTo: userIdResult.jwtExpiration,
79
80
  });
80
81
  if (isRefreshReady) {
@@ -1,4 +1,4 @@
1
- import { createBlockingInterval, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
1
+ import { type createBlockingInterval, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
3
  import { type EmptyObject } from 'type-fest';
4
4
  /**
@@ -26,12 +26,19 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
26
26
  *
27
27
  * If the user is not currently authorized, this should return `undefined` to prevent
28
28
  * unnecessary network traffic.
29
+ *
30
+ * This will be called any time the user interacts with the page, debounced by the adjacent
31
+ * `debounce` property.
29
32
  */
30
33
  performCheck: () => MaybePromise<SelectFrom<Response, {
31
34
  status: true;
32
35
  }> | undefined>;
33
- /** @default {minutes: 1} */
34
- interval?: AnyDuration | undefined;
36
+ /**
37
+ * Debounce for firing `performCheck`.
38
+ *
39
+ * @default {minutes: 1}
40
+ */
41
+ debounce?: AnyDuration | undefined;
35
42
  };
36
43
  overrides: PartialWithUndefined<{
37
44
  localStorage: Pick<Storage, 'setItem' | 'removeItem' | 'getItem'>;
@@ -1,4 +1,5 @@
1
- import { createBlockingInterval, HttpStatus, } from '@augment-vir/common';
1
+ import { HttpStatus, } from '@augment-vir/common';
2
+ import { listenToActivity } from 'detect-activity';
2
3
  import { CsrfTokenFailureReason, extractCsrfTokenHeader, getCurrentCsrfToken, storeCsrfToken, wipeCurrentCsrfToken, } from '../csrf-token.js';
3
4
  import { AuthHeaderName } from '../headers.js';
4
5
  /**
@@ -14,14 +15,18 @@ export class FrontendAuthClient {
14
15
  constructor(config = {}) {
15
16
  this.config = config;
16
17
  if (config.checkUser) {
17
- this.userCheckInterval = createBlockingInterval(async () => {
18
- const response = await config.checkUser?.performCheck();
19
- if (response) {
20
- await this.verifyResponseAuth({
21
- status: response.status,
22
- });
23
- }
24
- }, config.checkUser.interval || { minutes: 1 });
18
+ listenToActivity({
19
+ listener: async () => {
20
+ const response = await config.checkUser?.performCheck();
21
+ if (response) {
22
+ await this.verifyResponseAuth({
23
+ status: response.status,
24
+ });
25
+ }
26
+ },
27
+ debounce: config.checkUser.debounce || { minutes: 5 },
28
+ fireImmediately: false,
29
+ });
25
30
  }
26
31
  }
27
32
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-vir",
3
- "version": "2.3.5",
3
+ "version": "2.3.7",
4
4
  "description": "Auth made easy and secure via JWT cookies, CSRF tokens, and password hashing helpers.",
5
5
  "keywords": [
6
6
  "auth",
@@ -45,6 +45,7 @@
45
45
  "@augment-vir/assert": "^31.47.0",
46
46
  "@augment-vir/common": "^31.47.0",
47
47
  "date-vir": "^8.0.0",
48
+ "detect-activity": "^0.0.1",
48
49
  "hash-wasm": "^4.12.0",
49
50
  "jose": "^6.1.0",
50
51
  "object-shape-tester": "^6.9.3",
@@ -123,7 +123,7 @@ export type BackendAuthClientConfig<
123
123
  * How long before a user's session times out when we should start trying to refresh their
124
124
  * session.
125
125
  *
126
- * @default {minutes: 5}
126
+ * @default {minutes: 10}
127
127
  */
128
128
  sessionRefreshThreshold: Readonly<AnyDuration>;
129
129
  overrides: PartialWithUndefined<{
@@ -137,6 +137,10 @@ const defaultSessionIdleTimeout: Readonly<AnyDuration> = {
137
137
  minutes: 20,
138
138
  };
139
139
 
140
+ const defaultSessionRefreshThreshold: Readonly<AnyDuration> = {
141
+ minutes: 10,
142
+ };
143
+
140
144
  /**
141
145
  * An auth client for creating and validating JWTs embedded in cookies. This should only be used in
142
146
  * a backend environment as it accesses native Node packages.
@@ -245,9 +249,7 @@ export class BackendAuthClient<
245
249
  const isRefreshReady = isDateAfter({
246
250
  fullDate: calculateRelativeDate(
247
251
  now,
248
- this.config.sessionRefreshThreshold || {
249
- minutes: 5,
250
- },
252
+ this.config.sessionRefreshThreshold || defaultSessionRefreshThreshold,
251
253
  ),
252
254
  relativeTo: userIdResult.jwtExpiration,
253
255
  });
@@ -1,5 +1,5 @@
1
1
  import {
2
- createBlockingInterval,
2
+ type createBlockingInterval,
3
3
  HttpStatus,
4
4
  type JsonCompatibleObject,
5
5
  type MaybePromise,
@@ -7,6 +7,7 @@ import {
7
7
  type SelectFrom,
8
8
  } from '@augment-vir/common';
9
9
  import {type AnyDuration} from 'date-vir';
10
+ import {listenToActivity} from 'detect-activity';
10
11
  import {type EmptyObject} from 'type-fest';
11
12
  import {
12
13
  CsrfTokenFailureReason,
@@ -43,6 +44,9 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
43
44
  *
44
45
  * If the user is not currently authorized, this should return `undefined` to prevent
45
46
  * unnecessary network traffic.
47
+ *
48
+ * This will be called any time the user interacts with the page, debounced by the adjacent
49
+ * `debounce` property.
46
50
  */
47
51
  performCheck: () => MaybePromise<
48
52
  | SelectFrom<
@@ -53,8 +57,12 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
53
57
  >
54
58
  | undefined
55
59
  >;
56
- /** @default {minutes: 1} */
57
- interval?: AnyDuration | undefined;
60
+ /**
61
+ * Debounce for firing `performCheck`.
62
+ *
63
+ * @default {minutes: 1}
64
+ */
65
+ debounce?: AnyDuration | undefined;
58
66
  };
59
67
 
60
68
  overrides: PartialWithUndefined<{
@@ -76,8 +84,8 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
76
84
 
77
85
  constructor(protected readonly config: FrontendAuthClientConfig = {}) {
78
86
  if (config.checkUser) {
79
- this.userCheckInterval = createBlockingInterval(
80
- async () => {
87
+ listenToActivity({
88
+ listener: async () => {
81
89
  const response = await config.checkUser?.performCheck();
82
90
 
83
91
  if (response) {
@@ -86,8 +94,9 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
86
94
  });
87
95
  }
88
96
  },
89
- config.checkUser.interval || {minutes: 1},
90
- );
97
+ debounce: config.checkUser.debounce || {minutes: 5},
98
+ fireImmediately: false,
99
+ });
91
100
  }
92
101
  }
93
102