@icp-sdk/auth 5.0.0-beta.2 → 6.0.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/client/db.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type IDBPDatabase, openDB } from 'idb';
2
- import { DB_VERSION, KEY_STORAGE_DELEGATION, KEY_STORAGE_KEY } from './storage.ts';
2
+ import { DB_VERSION, KEY_STORAGE_DELEGATION, KEY_STORAGE_KEY } from './storage.js';
3
3
 
4
4
  type Database = IDBPDatabase<unknown>;
5
5
  type IDBValidKey = string | number | Date | BufferSource | IDBValidKey[];
@@ -27,15 +27,23 @@ const events = ['mousedown', 'mousemove', 'keydown', 'touchstart', 'wheel'];
27
27
  /**
28
28
  * Detects if the user has been idle for a duration of `idleTimeout` ms, and calls `onIdle` and registered callbacks.
29
29
  * By default, the IdleManager will log a user out after 10 minutes of inactivity.
30
- * To override these defaults, you can pass an `onIdle` callback, or configure a custom `idleTimeout` in milliseconds
30
+ * To override these defaults, you can pass an `onIdle` callback, or configure a custom `idleTimeout` in milliseconds.
31
+ *
32
+ * IdleManager is a singleton: multiple calls to `create()` return the same instance,
33
+ * registering any new `onIdle` callback. Call `exit()` to tear down the singleton.
31
34
  */
32
35
  export class IdleManager {
33
- callbacks: IdleCB[] = [];
34
- idleTimeout: IdleManagerOptions['idleTimeout'] = 10 * 60 * 1000;
35
- timeoutID?: number = undefined;
36
+ static #instance: IdleManager | undefined;
37
+
38
+ #callbacks: IdleCB[] = [];
39
+ #idleTimeout: number;
40
+ #timeoutID?: number = undefined;
41
+ #resetTimer: () => void;
36
42
 
37
43
  /**
38
- * Creates an {@link IdleManager}
44
+ * Creates or returns the singleton {@link IdleManager}.
45
+ * If the instance already exists, any provided `onIdle` callback is registered
46
+ * on the existing instance.
39
47
  * @param {IdleManagerOptions} options Optional configuration
40
48
  * @see {@link IdleManagerOptions}
41
49
  * @param options.onIdle Callback once user has been idle. Use to prompt for fresh login, and use `Actor.agentOf(your_actor).invalidateIdentity()` to protect the user
@@ -67,25 +75,34 @@ export class IdleManager {
67
75
  scrollDebounce?: number;
68
76
  } = {},
69
77
  ): IdleManager {
70
- return new IdleManager(options);
78
+ if (IdleManager.#instance) {
79
+ if (options.onIdle) {
80
+ IdleManager.#instance.registerCallback(options.onIdle);
81
+ }
82
+ return IdleManager.#instance;
83
+ }
84
+ const instance = new IdleManager(options);
85
+ IdleManager.#instance = instance;
86
+ return instance;
71
87
  }
72
88
 
73
89
  /**
74
- * @protected
75
90
  * @param options {@link IdleManagerOptions}
76
91
  */
77
- protected constructor(options: IdleManagerOptions = {}) {
92
+ private constructor(options: IdleManagerOptions = {}) {
78
93
  const { onIdle, idleTimeout = 10 * 60 * 1000 } = options || {};
79
94
 
80
- this.callbacks = onIdle ? [onIdle] : [];
81
- this.idleTimeout = idleTimeout;
95
+ this.#callbacks = onIdle ? [onIdle] : [];
96
+ this.#idleTimeout = idleTimeout;
82
97
 
83
- const _resetTimer = this._resetTimer.bind(this);
98
+ // Store the bound function once so the same reference is used
99
+ // for both addEventListener and removeEventListener.
100
+ this.#resetTimer = this._resetTimer.bind(this);
84
101
 
85
- window.addEventListener('load', _resetTimer, true);
102
+ window.addEventListener('load', this.#resetTimer, true);
86
103
 
87
104
  events.forEach((name) => {
88
- document.addEventListener(name, _resetTimer, true);
105
+ document.addEventListener(name, this.#resetTimer, true);
89
106
  });
90
107
 
91
108
  const debounce = (func: (...args: unknown[]) => void, wait: number) => {
@@ -103,42 +120,43 @@ export class IdleManager {
103
120
 
104
121
  if (options?.captureScroll) {
105
122
  // debounce scroll events
106
- const scroll = debounce(_resetTimer, options?.scrollDebounce ?? 100);
123
+ const scroll = debounce(this.#resetTimer, options?.scrollDebounce ?? 100);
107
124
  window.addEventListener('scroll', scroll, true);
108
125
  }
109
126
 
110
- _resetTimer();
127
+ this.#resetTimer();
111
128
  }
112
129
 
113
130
  /**
114
131
  * @param {IdleCB} callback function to be called when user goes idle
115
132
  */
116
133
  public registerCallback(callback: IdleCB): void {
117
- this.callbacks.push(callback);
134
+ this.#callbacks.push(callback);
118
135
  }
119
136
 
120
137
  /**
121
- * Cleans up the idle manager and its listeners
138
+ * Tears down listeners, fires all callbacks, and clears the singleton.
122
139
  */
123
140
  public exit(): void {
124
- clearTimeout(this.timeoutID);
125
- window.removeEventListener('load', this._resetTimer, true);
141
+ clearTimeout(this.#timeoutID);
142
+ window.removeEventListener('load', this.#resetTimer, true);
126
143
 
127
- const _resetTimer = this._resetTimer.bind(this);
128
144
  events.forEach((name) => {
129
- document.removeEventListener(name, _resetTimer, true);
145
+ document.removeEventListener(name, this.#resetTimer, true);
130
146
  });
131
- this.callbacks.forEach((cb) => {
147
+ this.#callbacks.forEach((cb) => {
132
148
  cb();
133
149
  });
150
+
151
+ IdleManager.#instance = undefined;
134
152
  }
135
153
 
136
154
  /**
137
155
  * Resets the timeouts during cleanup
138
156
  */
139
- _resetTimer(): void {
157
+ private _resetTimer(): void {
140
158
  const exit = this.exit.bind(this);
141
- window.clearTimeout(this.timeoutID);
142
- this.timeoutID = window.setTimeout(exit, this.idleTimeout);
159
+ window.clearTimeout(this.#timeoutID);
160
+ this.#timeoutID = window.setTimeout(exit, this.#idleTimeout);
143
161
  }
144
162
  }
@@ -2,13 +2,13 @@
2
2
  * @module api/client
3
3
  */
4
4
 
5
- export * from './auth-client.ts';
6
- export { type DBCreateOptions, IdbKeyVal } from './db.ts';
7
- export * from './idle-manager.ts';
5
+ export * from './auth-client.js';
6
+ export { type DBCreateOptions, IdbKeyVal } from './db.js';
7
+ export * from './idle-manager.js';
8
8
  export {
9
9
  type AuthClientStorage,
10
10
  IdbStorage,
11
11
  KEY_STORAGE_DELEGATION,
12
12
  KEY_STORAGE_KEY,
13
13
  LocalStorage,
14
- } from './storage.ts';
14
+ } from './storage.js';
@@ -1,4 +1,4 @@
1
- import { type DBCreateOptions, IdbKeyVal } from './db.ts';
1
+ import { type DBCreateOptions, IdbKeyVal } from './db.js';
2
2
 
3
3
  export const KEY_STORAGE_KEY = 'identity';
4
4
  export const KEY_STORAGE_DELEGATION = 'delegation';