@0xkey-io/react-native-wallet-kit 0.1.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.
Files changed (61) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +93 -0
  3. package/dist/hooks/use-0xkey.d.ts +3 -0
  4. package/dist/hooks/use-0xkey.d.ts.map +1 -0
  5. package/dist/hooks/use-0xkey.js +15 -0
  6. package/dist/hooks/use-0xkey.js.map +1 -0
  7. package/dist/hooks/use-0xkey.mjs +13 -0
  8. package/dist/hooks/use-0xkey.mjs.map +1 -0
  9. package/dist/index.d.ts +21 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +55 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/index.mjs +6 -0
  14. package/dist/index.mjs.map +1 -0
  15. package/dist/providers/Types.d.ts +275 -0
  16. package/dist/providers/Types.d.ts.map +1 -0
  17. package/dist/providers/Types.js +9 -0
  18. package/dist/providers/Types.js.map +1 -0
  19. package/dist/providers/Types.mjs +7 -0
  20. package/dist/providers/Types.mjs.map +1 -0
  21. package/dist/providers/ZeroXKeyProvider.d.ts +39 -0
  22. package/dist/providers/ZeroXKeyProvider.d.ts.map +1 -0
  23. package/dist/providers/ZeroXKeyProvider.js +1846 -0
  24. package/dist/providers/ZeroXKeyProvider.js.map +1 -0
  25. package/dist/providers/ZeroXKeyProvider.mjs +1844 -0
  26. package/dist/providers/ZeroXKeyProvider.mjs.map +1 -0
  27. package/dist/providers/index.d.ts +4 -0
  28. package/dist/providers/index.d.ts.map +1 -0
  29. package/dist/tests/oauth-test.d.ts +2 -0
  30. package/dist/tests/oauth-test.d.ts.map +1 -0
  31. package/dist/typedoc-entry/index.d.ts +5 -0
  32. package/dist/typedoc-entry/index.d.ts.map +1 -0
  33. package/dist/types/base.d.ts +137 -0
  34. package/dist/types/base.d.ts.map +1 -0
  35. package/dist/types/base.js +48 -0
  36. package/dist/types/base.js.map +1 -0
  37. package/dist/types/base.mjs +48 -0
  38. package/dist/types/base.mjs.map +1 -0
  39. package/dist/types/method-types.d.ts +102 -0
  40. package/dist/types/method-types.d.ts.map +1 -0
  41. package/dist/utils/index.d.ts +4 -0
  42. package/dist/utils/index.d.ts.map +1 -0
  43. package/dist/utils/oauth.d.ts +240 -0
  44. package/dist/utils/oauth.d.ts.map +1 -0
  45. package/dist/utils/oauth.js +340 -0
  46. package/dist/utils/oauth.js.map +1 -0
  47. package/dist/utils/oauth.mjs +319 -0
  48. package/dist/utils/oauth.mjs.map +1 -0
  49. package/dist/utils/timers.d.ts +73 -0
  50. package/dist/utils/timers.d.ts.map +1 -0
  51. package/dist/utils/timers.js +132 -0
  52. package/dist/utils/timers.js.map +1 -0
  53. package/dist/utils/timers.mjs +122 -0
  54. package/dist/utils/timers.mjs.map +1 -0
  55. package/dist/utils/utils.d.ts +27 -0
  56. package/dist/utils/utils.d.ts.map +1 -0
  57. package/dist/utils/utils.js +37 -0
  58. package/dist/utils/utils.js.map +1 -0
  59. package/dist/utils/utils.mjs +33 -0
  60. package/dist/utils/utils.mjs.map +1 -0
  61. package/package.json +80 -0
@@ -0,0 +1,319 @@
1
+ import { sha256 } from '@noble/hashes/sha256';
2
+ import { stringToBase64urlString } from '@0xkey-io/encoding';
3
+ import { OAuthProviders } from '@0xkey-io/sdk-types';
4
+ import AsyncStorageModule from '@react-native-async-storage/async-storage';
5
+
6
+ // some bundlers wrap the module as { default: AsyncStorage } instead of
7
+ // returning AsyncStorage directly. This handles both cases
8
+ const AsyncStorage = AsyncStorageModule.default ?? AsyncStorageModule;
9
+ const DISCORD_AUTH_URL = "https://discord.com/oauth2/authorize";
10
+ const X_AUTH_URL = "https://x.com/i/oauth2/authorize";
11
+ const GOOGLE_AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
12
+ const APPLE_AUTH_URL = "https://account.apple.com/auth/authorize";
13
+ const FACEBOOK_AUTH_URL = "https://www.facebook.com/v23.0/dialog/oauth";
14
+ const FACEBOOK_GRAPH_URL = "https://graph.facebook.com/v23.0/oauth/access_token";
15
+ const ZEROXKEY_OAUTH_ORIGIN_URL = "https://oauth-origin.0xkey.com";
16
+ const ZEROXKEY_OAUTH_REDIRECT_URL = "https://oauth-redirect.0xkey.com";
17
+ // ============================================================================
18
+ // OAuth State Building
19
+ // ============================================================================
20
+ /**
21
+ * Builds the OAuth state parameter string
22
+ */
23
+ function buildOAuthState(params) {
24
+ const { provider, flow, publicKey, nonce, additionalState } = params;
25
+ let state = `provider=${provider}&flow=${flow}&publicKey=${encodeURIComponent(publicKey)}`;
26
+ if (nonce) {
27
+ state += `&nonce=${nonce}`;
28
+ }
29
+ if (additionalState) {
30
+ const extra = Object.entries(additionalState)
31
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
32
+ .join("&");
33
+ if (extra) {
34
+ state += `&${extra}`;
35
+ }
36
+ }
37
+ return state;
38
+ }
39
+ /**
40
+ * Pre-configured OAuth provider settings
41
+ */
42
+ const OAUTH_PROVIDER_CONFIGS = {
43
+ [OAuthProviders.GOOGLE]: {
44
+ provider: OAuthProviders.GOOGLE,
45
+ authUrl: GOOGLE_AUTH_URL,
46
+ scopes: "openid email profile",
47
+ usesPKCE: false,
48
+ responseType: "id_token",
49
+ nonceInParams: true,
50
+ },
51
+ [OAuthProviders.APPLE]: {
52
+ provider: OAuthProviders.APPLE,
53
+ authUrl: APPLE_AUTH_URL,
54
+ scopes: "",
55
+ usesPKCE: false,
56
+ responseType: "code id_token",
57
+ responseMode: "fragment",
58
+ nonceInParams: true,
59
+ },
60
+ [OAuthProviders.FACEBOOK]: {
61
+ provider: OAuthProviders.FACEBOOK,
62
+ authUrl: FACEBOOK_AUTH_URL,
63
+ scopes: "openid",
64
+ usesPKCE: true,
65
+ responseType: "code",
66
+ nonceInParams: true,
67
+ },
68
+ [OAuthProviders.DISCORD]: {
69
+ provider: OAuthProviders.DISCORD,
70
+ authUrl: DISCORD_AUTH_URL,
71
+ scopes: "identify email",
72
+ usesPKCE: true,
73
+ responseType: "code",
74
+ nonceInParams: false,
75
+ },
76
+ [OAuthProviders.X]: {
77
+ provider: OAuthProviders.X,
78
+ authUrl: X_AUTH_URL,
79
+ scopes: "tweet.read users.read",
80
+ usesPKCE: true,
81
+ responseType: "code",
82
+ nonceInParams: false,
83
+ },
84
+ };
85
+ // ============================================================================
86
+ // OAuth State Parsing
87
+ // ============================================================================
88
+ /**
89
+ * Parses the OAuth state parameter string into an object
90
+ */
91
+ function parseStateParam(stateParam) {
92
+ if (!stateParam)
93
+ return {};
94
+ const result = {};
95
+ const pairs = stateParam.split("&");
96
+ for (const pair of pairs) {
97
+ const [key, value] = pair.split("=");
98
+ if (key && value !== undefined) {
99
+ result[key] = decodeURIComponent(value);
100
+ }
101
+ }
102
+ return result;
103
+ }
104
+ // Function to generate PKCE challenge pair for Facebook OAuth
105
+ async function generateChallengePair() {
106
+ // Generate verifier from 32 random bytes
107
+ const randomBytes = new Uint8Array(32);
108
+ // eslint-disable-next-line no-undef
109
+ crypto.getRandomValues(randomBytes);
110
+ const randomAsBinary = String.fromCharCode(...randomBytes);
111
+ const verifier = stringToBase64urlString(randomAsBinary);
112
+ // Compute SHA-256 over ASCII(verifier), then base64url encode
113
+ const ascii = new TextEncoder().encode(verifier);
114
+ const digest = sha256(ascii);
115
+ const digestAsBinary = String.fromCharCode(...digest);
116
+ const codeChallenge = stringToBase64urlString(digestAsBinary);
117
+ return { verifier, codeChallenge };
118
+ }
119
+ /**
120
+ * Gets the AsyncStorage key name for a PKCE provider's verifier
121
+ */
122
+ function getPKCEVerifierKey(provider) {
123
+ return `${provider}_verifier`;
124
+ }
125
+ /**
126
+ * Stores the PKCE verifier in AsyncStorage
127
+ * @param provider - The OAuth provider
128
+ * @param verifier - The verifier string to store
129
+ */
130
+ async function storePKCEVerifier(provider, verifier) {
131
+ const key = getPKCEVerifierKey(provider);
132
+ await AsyncStorage.setItem(key, verifier);
133
+ }
134
+ /**
135
+ * Retrieves and removes the PKCE verifier from AsyncStorage
136
+ * @param provider - The OAuth provider
137
+ * @returns The verifier string
138
+ * @throws Error if verifier is not found
139
+ */
140
+ async function consumePKCEVerifier(provider) {
141
+ const key = getPKCEVerifierKey(provider);
142
+ const verifier = await AsyncStorage.getItem(key);
143
+ if (!verifier) {
144
+ throw new Error(`Missing PKCE verifier for ${provider}. OAuth flow may have been interrupted.`);
145
+ }
146
+ await AsyncStorage.removeItem(key);
147
+ return verifier;
148
+ }
149
+ /**
150
+ * Builds the complete OAuth authorization URL for a provider
151
+ * For react-native, can use either:
152
+ * - Direct provider URLs (Discord, X)
153
+ * - ZeroXKey OAuth proxy (Google, Apple, Facebook)
154
+ */
155
+ function buildOAuthUrl(params) {
156
+ const { provider, clientId, redirectUri, publicKey, nonce, codeChallenge, additionalState, useOauthProxyOrigin = false, } = params;
157
+ const config = OAUTH_PROVIDER_CONFIGS[provider];
158
+ // Build state parameter
159
+ const stateParams = {
160
+ provider,
161
+ flow: "redirect",
162
+ publicKey,
163
+ };
164
+ if (!config.nonceInParams && nonce) {
165
+ stateParams.nonce = nonce;
166
+ }
167
+ if (additionalState) {
168
+ stateParams.additionalState = additionalState;
169
+ }
170
+ const state = buildOAuthState(stateParams);
171
+ // If using ZeroXKey Oauth proxy (for Google, Apple, Facebook)
172
+ if (useOauthProxyOrigin) {
173
+ const url = new URL(ZEROXKEY_OAUTH_ORIGIN_URL);
174
+ url.searchParams.set("provider", provider);
175
+ url.searchParams.set("clientId", clientId);
176
+ url.searchParams.set("redirectUri", redirectUri);
177
+ url.searchParams.set("nonce", nonce);
178
+ if (codeChallenge) {
179
+ url.searchParams.set("codeChallenge", codeChallenge);
180
+ }
181
+ url.searchParams.set("state", state);
182
+ return url.toString();
183
+ }
184
+ // Direct provider URLs (for Discord, X)
185
+ const authUrl = new URL(config.authUrl);
186
+ authUrl.searchParams.set("client_id", clientId);
187
+ authUrl.searchParams.set("redirect_uri", redirectUri);
188
+ authUrl.searchParams.set("response_type", config.responseType);
189
+ if (config.scopes) {
190
+ authUrl.searchParams.set("scope", config.scopes);
191
+ }
192
+ if (config.usesPKCE && codeChallenge) {
193
+ authUrl.searchParams.set("code_challenge", codeChallenge);
194
+ authUrl.searchParams.set("code_challenge_method", "S256");
195
+ }
196
+ authUrl.searchParams.set("state", state);
197
+ return authUrl.toString();
198
+ }
199
+ /**
200
+ * Parses the deep link URL returned from InAppBrowser after OAuth redirect
201
+ * @param deepLinkUrl - The URL from InAppBrowser result (e.g., "myapp://?id_token=...&state=...")
202
+ * @returns Parsed OAuth response data
203
+ */
204
+ function parseInAppBrowserResult(deepLinkUrl) {
205
+ const qsIndex = deepLinkUrl.indexOf("?");
206
+ const queryString = qsIndex >= 0 ? deepLinkUrl.substring(qsIndex + 1) : "";
207
+ const urlParams = new URLSearchParams(queryString);
208
+ const idToken = urlParams.get("id_token");
209
+ const authCode = urlParams.get("code");
210
+ const stateParam = urlParams.get("state");
211
+ // Parse state parameter
212
+ const stateData = parseStateParam(stateParam);
213
+ return {
214
+ idToken: idToken ?? null,
215
+ authCode: authCode ?? null,
216
+ sessionKey: stateData.sessionKey,
217
+ provider: stateData.provider ?? null,
218
+ publicKey: stateData.publicKey ?? null,
219
+ nonce: stateData.nonce ?? null,
220
+ };
221
+ }
222
+ /**
223
+ * Unified OAuth completion handler.
224
+ * Routes to the appropriate completion handler based on params:
225
+ * Priority: callbacks.onOauthSuccess > callbacks.onOauthRedirect > completeOauth
226
+ *
227
+ * This is the core completion logic used by InAppBrowser flows.
228
+ */
229
+ async function completeOAuthFlow(params) {
230
+ const { provider, publicKey, oidcToken, sessionKey, callbacks, completeOauth, } = params;
231
+ const completionParams = {
232
+ oidcToken,
233
+ providerName: provider,
234
+ publicKey,
235
+ ...(sessionKey && { sessionKey }),
236
+ };
237
+ if (callbacks?.onOauthSuccess) {
238
+ callbacks.onOauthSuccess(completionParams);
239
+ return;
240
+ }
241
+ if (callbacks?.onOauthRedirect) {
242
+ callbacks.onOauthRedirect({
243
+ idToken: oidcToken,
244
+ publicKey,
245
+ ...(sessionKey && { sessionKey }),
246
+ });
247
+ return;
248
+ }
249
+ await completeOauth(completionParams);
250
+ }
251
+ /**
252
+ * Unified PKCE flow handler for all PKCE-based OAuth providers.
253
+ * Handles the complete PKCE flow: verifier retrieval, token exchange, and completion routing.
254
+ *
255
+ * @param params - The PKCE flow parameters
256
+ * @returns A promise that resolves when the flow is complete
257
+ */
258
+ async function handlePKCEFlow(params) {
259
+ const { provider, publicKey, authCode, sessionKey, callbacks, completeOauth, exchangeCodeForToken, } = params;
260
+ if (!authCode) {
261
+ throw new Error(`Missing authorization code from ${provider} OAuth`);
262
+ }
263
+ // Get and consume the stored verifier
264
+ const verifier = await consumePKCEVerifier(provider);
265
+ try {
266
+ // Exchange code for token
267
+ const oidcToken = await exchangeCodeForToken(verifier);
268
+ if (!oidcToken) {
269
+ throw new Error(`Missing oidcToken from ${provider} OAuth exchange`);
270
+ }
271
+ // Complete the OAuth flow
272
+ const completionParams = {
273
+ provider,
274
+ publicKey,
275
+ oidcToken,
276
+ completeOauth,
277
+ };
278
+ if (sessionKey) {
279
+ completionParams.sessionKey = sessionKey;
280
+ }
281
+ if (callbacks) {
282
+ completionParams.callbacks = callbacks;
283
+ }
284
+ await completeOAuthFlow(completionParams);
285
+ }
286
+ catch (error) {
287
+ // Ensure cleanup even on error
288
+ const key = getPKCEVerifierKey(provider);
289
+ await AsyncStorage.removeItem(key).catch(() => {
290
+ /* ignore cleanup errors */
291
+ });
292
+ throw error;
293
+ }
294
+ }
295
+ // Function to exchange Facebook authorization code for token
296
+ async function exchangeCodeForToken(clientId, redirectUri, code, codeVerifier) {
297
+ const params = new URLSearchParams({
298
+ client_id: clientId,
299
+ redirect_uri: redirectUri,
300
+ code_verifier: codeVerifier,
301
+ code: code,
302
+ grant_type: "authorization_code",
303
+ });
304
+ const response = await fetch(FACEBOOK_GRAPH_URL, {
305
+ method: "POST",
306
+ headers: {
307
+ "Content-Type": "application/x-www-form-urlencoded",
308
+ },
309
+ body: params.toString(),
310
+ });
311
+ if (!response.ok) {
312
+ const errorData = await response.json();
313
+ throw new Error(`Facebook token exchange failed: ${JSON.stringify(errorData)}`);
314
+ }
315
+ return await response.json();
316
+ }
317
+
318
+ export { APPLE_AUTH_URL, DISCORD_AUTH_URL, FACEBOOK_AUTH_URL, FACEBOOK_GRAPH_URL, GOOGLE_AUTH_URL, OAUTH_PROVIDER_CONFIGS, X_AUTH_URL, ZEROXKEY_OAUTH_ORIGIN_URL, ZEROXKEY_OAUTH_REDIRECT_URL, buildOAuthState, buildOAuthUrl, completeOAuthFlow, consumePKCEVerifier, exchangeCodeForToken, generateChallengePair, getPKCEVerifierKey, handlePKCEFlow, parseInAppBrowserResult, parseStateParam, storePKCEVerifier };
319
+ //# sourceMappingURL=oauth.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.mjs","sources":["../../src/utils/oauth.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ export type TimerController = {
2
+ clear: () => void;
3
+ };
4
+ export type TimerMap = Record<string, TimerController>;
5
+ export declare const MAX_DELAY_MS = 2147483647;
6
+ /**
7
+ * @internal A drop-in replacement for `setTimeout` that supports arbitrarily long delays.
8
+ *
9
+ * ### Why?
10
+ * Browsers clamp `setTimeout` delays to a 32-bit signed integer,
11
+ * i.e. a maximum of ~24.8 days (`2_147_483_647ms`). Any larger value
12
+ * will fire almost immediately. This helper safely schedules timeouts
13
+ * that can be months or years into the future.
14
+ *
15
+ * ### How it works
16
+ * - On call, we record a fixed **target timestamp** (`now + delayMs`).
17
+ * - We schedule a single "leg" of at most ~24.8 days into the future,
18
+ * with an internal `tick` function as the callback.
19
+ * - When a leg expires, `tick` checks how much time is left:
20
+ * - If `remaining > 0`, it schedules the next leg (`min(MAX_DELAY_MS, remaining)`).
21
+ * - If `remaining <= 0`, the full delay has passed and we finally call your `cb()`.
22
+ * - At any time, only **one** leg is active. Calling `.clear()` cancels
23
+ * the current leg and prevents further hops.
24
+ *
25
+ * ### Benefits
26
+ * - Works seamlessly for both short and very long delays.
27
+ * - Survives tab sleep / system suspend: when the tab wakes,
28
+ * `tick` re-checks the target timestamp and fires immediately if overdue.
29
+ * - No drift accumulation: each hop recalculates based on the fixed target,
30
+ * so you always land as close as possible to the intended deadline.
31
+ *
32
+ * ### Example
33
+ * ```ts
34
+ * const controller = setCappedTimeout(() => {
35
+ * console.log("A whole year later!");
36
+ * }, 1000 * 60 * 60 * 24 * 365);
37
+ *
38
+ * // Cancel if needed
39
+ * controller.clear();
40
+ * ```
41
+ *
42
+ * @param cb - Function to run once the full delay has elapsed.
43
+ * @param delayMs - Delay in milliseconds (can exceed 2_147_483_647).
44
+ * @returns A controller with a `.clear()` method to cancel the timeout.
45
+ */
46
+ export declare function setCappedTimeout(cb: () => void, delayMs: number): TimerController;
47
+ /** @internal Simple one-shot timeout that still returns a controller for uniformity. */
48
+ export declare function setTimeoutController(cb: () => void, delayMs: number): TimerController;
49
+ /** @internal Replace any existing timer for `key` with `controller`. */
50
+ export declare function putTimer(map: TimerMap, key: string, controller: TimerController): void;
51
+ /** @internal Clear a specific key (noop if missing). */
52
+ export declare function clearKey(map: TimerMap, key: string): void;
53
+ /** @internal Clear several keys at once (noop on missing). */
54
+ export declare function clearKeys(map: TimerMap, keys: string[]): void;
55
+ /** @internal Clear all timers in the map. */
56
+ export declare function clearAll(map: TimerMap): void;
57
+ /**
58
+ * @internal Convenience: set a capped timeout directly into the map for `key`.
59
+ * @param map The map to store the timer in (pass in the ref to the timer map)
60
+ * @param key The key to associate with the timer
61
+ * @param cb The callback to invoke when the timer expires
62
+ * @param delayMs The delay in milliseconds before the timer expires
63
+ * */
64
+ export declare function setCappedTimeoutInMap(map: TimerMap, key: string, cb: () => void, delayMs: number): void;
65
+ /**
66
+ * @internal Convenience: set a regular (short) timeout into the map for `key`.
67
+ * @param map The map to store the timer in (pass in the ref to the timer map)
68
+ * @param key The key to associate with the timer
69
+ * @param cb The callback to invoke when the timer expires
70
+ * @param delayMs The delay in milliseconds before the timer expires
71
+ */
72
+ export declare function setTimeoutInMap(map: TimerMap, key: string, cb: () => void, delayMs: number): void;
73
+ //# sourceMappingURL=timers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.d.ts","sourceRoot":"","sources":["../../src/utils/timers.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC;AACpD,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;AAEvD,eAAO,MAAM,YAAY,aAAgB,CAAC;AAO1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,MAAM,IAAI,EACd,OAAO,EAAE,MAAM,GACd,eAAe,CAuBjB;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,MAAM,IAAI,EACd,OAAO,EAAE,MAAM,GACd,eAAe,CAIjB;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CACtB,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,eAAe,QAI5B;AAED,wDAAwD;AACxD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,QAGlD;AAED,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAEtD;AAED,6CAA6C;AAC7C,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,QAKrC;AAED;;;;;;KAMK;AACL,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,IAAI,EACd,OAAO,EAAE,MAAM,QAGhB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,QAAQ,EACb,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,IAAI,EACd,OAAO,EAAE,MAAM,QAGhB"}
@@ -0,0 +1,132 @@
1
+ 'use strict';
2
+
3
+ // This file contains utility functions for managing timers and timeouts for session management.
4
+ // Unfortunately, the delay param in Node Timeouts is a 32-bit signed integer, meaning it can only represent delays up to ~24.8 days.
5
+ // This file provides functions to handle long delays by breaking them into smaller chunks.
6
+ // These functions are separate from the normal utils function to reduce clutter and improve visibility.
7
+ // Use `setTimeoutInMap` for short, frequent nudges (10s), and `setCappedTimeoutInMap` for anything that could exceed ~24.8 days.
8
+ const MAX_DELAY_MS = 2_147_483_647; // ~24.8 days
9
+ /** @internal */
10
+ function toIntMs(x) {
11
+ return Math.max(0, Math.floor(Number.isFinite(x) ? x : 0));
12
+ }
13
+ /**
14
+ * @internal A drop-in replacement for `setTimeout` that supports arbitrarily long delays.
15
+ *
16
+ * ### Why?
17
+ * Browsers clamp `setTimeout` delays to a 32-bit signed integer,
18
+ * i.e. a maximum of ~24.8 days (`2_147_483_647ms`). Any larger value
19
+ * will fire almost immediately. This helper safely schedules timeouts
20
+ * that can be months or years into the future.
21
+ *
22
+ * ### How it works
23
+ * - On call, we record a fixed **target timestamp** (`now + delayMs`).
24
+ * - We schedule a single "leg" of at most ~24.8 days into the future,
25
+ * with an internal `tick` function as the callback.
26
+ * - When a leg expires, `tick` checks how much time is left:
27
+ * - If `remaining > 0`, it schedules the next leg (`min(MAX_DELAY_MS, remaining)`).
28
+ * - If `remaining <= 0`, the full delay has passed and we finally call your `cb()`.
29
+ * - At any time, only **one** leg is active. Calling `.clear()` cancels
30
+ * the current leg and prevents further hops.
31
+ *
32
+ * ### Benefits
33
+ * - Works seamlessly for both short and very long delays.
34
+ * - Survives tab sleep / system suspend: when the tab wakes,
35
+ * `tick` re-checks the target timestamp and fires immediately if overdue.
36
+ * - No drift accumulation: each hop recalculates based on the fixed target,
37
+ * so you always land as close as possible to the intended deadline.
38
+ *
39
+ * ### Example
40
+ * ```ts
41
+ * const controller = setCappedTimeout(() => {
42
+ * console.log("A whole year later!");
43
+ * }, 1000 * 60 * 60 * 24 * 365);
44
+ *
45
+ * // Cancel if needed
46
+ * controller.clear();
47
+ * ```
48
+ *
49
+ * @param cb - Function to run once the full delay has elapsed.
50
+ * @param delayMs - Delay in milliseconds (can exceed 2_147_483_647).
51
+ * @returns A controller with a `.clear()` method to cancel the timeout.
52
+ */
53
+ function setCappedTimeout(cb, delayMs) {
54
+ const target = Date.now() + toIntMs(delayMs);
55
+ let handle;
56
+ const tick = () => {
57
+ const remaining = target - Date.now();
58
+ if (remaining <= 0) {
59
+ cb();
60
+ return;
61
+ }
62
+ handle = setTimeout(tick, Math.min(MAX_DELAY_MS, remaining));
63
+ };
64
+ tick();
65
+ return {
66
+ clear() {
67
+ if (handle !== undefined) {
68
+ clearTimeout(handle);
69
+ handle = undefined;
70
+ }
71
+ },
72
+ };
73
+ }
74
+ /** @internal Simple one-shot timeout that still returns a controller for uniformity. */
75
+ function setTimeoutController(cb, delayMs) {
76
+ const ms = toIntMs(delayMs);
77
+ const id = setTimeout(cb, ms);
78
+ return { clear: () => clearTimeout(id) };
79
+ }
80
+ /** @internal Replace any existing timer for `key` with `controller`. */
81
+ function putTimer(map, key, controller) {
82
+ map[key]?.clear?.();
83
+ map[key] = controller;
84
+ }
85
+ /** @internal Clear a specific key (noop if missing). */
86
+ function clearKey(map, key) {
87
+ map[key]?.clear?.();
88
+ delete map[key];
89
+ }
90
+ /** @internal Clear several keys at once (noop on missing). */
91
+ function clearKeys(map, keys) {
92
+ for (const k of keys)
93
+ clearKey(map, k);
94
+ }
95
+ /** @internal Clear all timers in the map. */
96
+ function clearAll(map) {
97
+ for (const k of Object.keys(map)) {
98
+ map[k]?.clear?.();
99
+ delete map[k];
100
+ }
101
+ }
102
+ /**
103
+ * @internal Convenience: set a capped timeout directly into the map for `key`.
104
+ * @param map The map to store the timer in (pass in the ref to the timer map)
105
+ * @param key The key to associate with the timer
106
+ * @param cb The callback to invoke when the timer expires
107
+ * @param delayMs The delay in milliseconds before the timer expires
108
+ * */
109
+ function setCappedTimeoutInMap(map, key, cb, delayMs) {
110
+ putTimer(map, key, setCappedTimeout(cb, delayMs));
111
+ }
112
+ /**
113
+ * @internal Convenience: set a regular (short) timeout into the map for `key`.
114
+ * @param map The map to store the timer in (pass in the ref to the timer map)
115
+ * @param key The key to associate with the timer
116
+ * @param cb The callback to invoke when the timer expires
117
+ * @param delayMs The delay in milliseconds before the timer expires
118
+ */
119
+ function setTimeoutInMap(map, key, cb, delayMs) {
120
+ putTimer(map, key, setTimeoutController(cb, delayMs));
121
+ }
122
+
123
+ exports.MAX_DELAY_MS = MAX_DELAY_MS;
124
+ exports.clearAll = clearAll;
125
+ exports.clearKey = clearKey;
126
+ exports.clearKeys = clearKeys;
127
+ exports.putTimer = putTimer;
128
+ exports.setCappedTimeout = setCappedTimeout;
129
+ exports.setCappedTimeoutInMap = setCappedTimeoutInMap;
130
+ exports.setTimeoutController = setTimeoutController;
131
+ exports.setTimeoutInMap = setTimeoutInMap;
132
+ //# sourceMappingURL=timers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timers.js","sources":["../../src/utils/timers.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AAMO,MAAM,YAAY,GAAG,cAAc;AAE1C;AACA,SAAS,OAAO,CAAC,CAAS,EAAA;IACxB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAC5D;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;AACG,SAAU,gBAAgB,CAC9B,EAAc,EACd,OAAe,EAAA;IAEf,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;AAC5C,IAAA,IAAI,MAAiD;IAErD,MAAM,IAAI,GAAG,MAAK;QAChB,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE;AACrC,QAAA,IAAI,SAAS,IAAI,CAAC,EAAE;AAClB,YAAA,EAAE,EAAE;YACJ;QACF;AACA,QAAA,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;AAC9D,IAAA,CAAC;AAED,IAAA,IAAI,EAAE;IAEN,OAAO;QACL,KAAK,GAAA;AACH,YAAA,IAAI,MAAM,KAAK,SAAS,EAAE;gBACxB,YAAY,CAAC,MAAM,CAAC;gBACpB,MAAM,GAAG,SAAS;YACpB;QACF,CAAC;KACF;AACH;AAEA;AACM,SAAU,oBAAoB,CAClC,EAAc,EACd,OAAe,EAAA;AAEf,IAAA,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAC3B,MAAM,EAAE,GAAG,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC;IAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC,EAAE,CAAC,EAAE;AAC1C;AAEA;SACgB,QAAQ,CACtB,GAAa,EACb,GAAW,EACX,UAA2B,EAAA;AAE3B,IAAA,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI;AACnB,IAAA,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU;AACvB;AAEA;AACM,SAAU,QAAQ,CAAC,GAAa,EAAE,GAAW,EAAA;AACjD,IAAA,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,IAAI;AACnB,IAAA,OAAO,GAAG,CAAC,GAAG,CAAC;AACjB;AAEA;AACM,SAAU,SAAS,CAAC,GAAa,EAAE,IAAc,EAAA;IACrD,KAAK,MAAM,CAAC,IAAI,IAAI;AAAE,QAAA,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;AACxC;AAEA;AACM,SAAU,QAAQ,CAAC,GAAa,EAAA;IACpC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;AAChC,QAAA,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI;AACjB,QAAA,OAAO,GAAG,CAAC,CAAC,CAAC;IACf;AACF;AAEA;;;;;;AAMK;AACC,SAAU,qBAAqB,CACnC,GAAa,EACb,GAAW,EACX,EAAc,EACd,OAAe,EAAA;AAEf,IAAA,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,gBAAgB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;AACnD;AAEA;;;;;;AAMG;AACG,SAAU,eAAe,CAC7B,GAAa,EACb,GAAW,EACX,EAAc,EACd,OAAe,EAAA;AAEf,IAAA,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;AACvD;;;;;;;;;;;;"}
@@ -0,0 +1,122 @@
1
+ // This file contains utility functions for managing timers and timeouts for session management.
2
+ // Unfortunately, the delay param in Node Timeouts is a 32-bit signed integer, meaning it can only represent delays up to ~24.8 days.
3
+ // This file provides functions to handle long delays by breaking them into smaller chunks.
4
+ // These functions are separate from the normal utils function to reduce clutter and improve visibility.
5
+ // Use `setTimeoutInMap` for short, frequent nudges (10s), and `setCappedTimeoutInMap` for anything that could exceed ~24.8 days.
6
+ const MAX_DELAY_MS = 2_147_483_647; // ~24.8 days
7
+ /** @internal */
8
+ function toIntMs(x) {
9
+ return Math.max(0, Math.floor(Number.isFinite(x) ? x : 0));
10
+ }
11
+ /**
12
+ * @internal A drop-in replacement for `setTimeout` that supports arbitrarily long delays.
13
+ *
14
+ * ### Why?
15
+ * Browsers clamp `setTimeout` delays to a 32-bit signed integer,
16
+ * i.e. a maximum of ~24.8 days (`2_147_483_647ms`). Any larger value
17
+ * will fire almost immediately. This helper safely schedules timeouts
18
+ * that can be months or years into the future.
19
+ *
20
+ * ### How it works
21
+ * - On call, we record a fixed **target timestamp** (`now + delayMs`).
22
+ * - We schedule a single "leg" of at most ~24.8 days into the future,
23
+ * with an internal `tick` function as the callback.
24
+ * - When a leg expires, `tick` checks how much time is left:
25
+ * - If `remaining > 0`, it schedules the next leg (`min(MAX_DELAY_MS, remaining)`).
26
+ * - If `remaining <= 0`, the full delay has passed and we finally call your `cb()`.
27
+ * - At any time, only **one** leg is active. Calling `.clear()` cancels
28
+ * the current leg and prevents further hops.
29
+ *
30
+ * ### Benefits
31
+ * - Works seamlessly for both short and very long delays.
32
+ * - Survives tab sleep / system suspend: when the tab wakes,
33
+ * `tick` re-checks the target timestamp and fires immediately if overdue.
34
+ * - No drift accumulation: each hop recalculates based on the fixed target,
35
+ * so you always land as close as possible to the intended deadline.
36
+ *
37
+ * ### Example
38
+ * ```ts
39
+ * const controller = setCappedTimeout(() => {
40
+ * console.log("A whole year later!");
41
+ * }, 1000 * 60 * 60 * 24 * 365);
42
+ *
43
+ * // Cancel if needed
44
+ * controller.clear();
45
+ * ```
46
+ *
47
+ * @param cb - Function to run once the full delay has elapsed.
48
+ * @param delayMs - Delay in milliseconds (can exceed 2_147_483_647).
49
+ * @returns A controller with a `.clear()` method to cancel the timeout.
50
+ */
51
+ function setCappedTimeout(cb, delayMs) {
52
+ const target = Date.now() + toIntMs(delayMs);
53
+ let handle;
54
+ const tick = () => {
55
+ const remaining = target - Date.now();
56
+ if (remaining <= 0) {
57
+ cb();
58
+ return;
59
+ }
60
+ handle = setTimeout(tick, Math.min(MAX_DELAY_MS, remaining));
61
+ };
62
+ tick();
63
+ return {
64
+ clear() {
65
+ if (handle !== undefined) {
66
+ clearTimeout(handle);
67
+ handle = undefined;
68
+ }
69
+ },
70
+ };
71
+ }
72
+ /** @internal Simple one-shot timeout that still returns a controller for uniformity. */
73
+ function setTimeoutController(cb, delayMs) {
74
+ const ms = toIntMs(delayMs);
75
+ const id = setTimeout(cb, ms);
76
+ return { clear: () => clearTimeout(id) };
77
+ }
78
+ /** @internal Replace any existing timer for `key` with `controller`. */
79
+ function putTimer(map, key, controller) {
80
+ map[key]?.clear?.();
81
+ map[key] = controller;
82
+ }
83
+ /** @internal Clear a specific key (noop if missing). */
84
+ function clearKey(map, key) {
85
+ map[key]?.clear?.();
86
+ delete map[key];
87
+ }
88
+ /** @internal Clear several keys at once (noop on missing). */
89
+ function clearKeys(map, keys) {
90
+ for (const k of keys)
91
+ clearKey(map, k);
92
+ }
93
+ /** @internal Clear all timers in the map. */
94
+ function clearAll(map) {
95
+ for (const k of Object.keys(map)) {
96
+ map[k]?.clear?.();
97
+ delete map[k];
98
+ }
99
+ }
100
+ /**
101
+ * @internal Convenience: set a capped timeout directly into the map for `key`.
102
+ * @param map The map to store the timer in (pass in the ref to the timer map)
103
+ * @param key The key to associate with the timer
104
+ * @param cb The callback to invoke when the timer expires
105
+ * @param delayMs The delay in milliseconds before the timer expires
106
+ * */
107
+ function setCappedTimeoutInMap(map, key, cb, delayMs) {
108
+ putTimer(map, key, setCappedTimeout(cb, delayMs));
109
+ }
110
+ /**
111
+ * @internal Convenience: set a regular (short) timeout into the map for `key`.
112
+ * @param map The map to store the timer in (pass in the ref to the timer map)
113
+ * @param key The key to associate with the timer
114
+ * @param cb The callback to invoke when the timer expires
115
+ * @param delayMs The delay in milliseconds before the timer expires
116
+ */
117
+ function setTimeoutInMap(map, key, cb, delayMs) {
118
+ putTimer(map, key, setTimeoutController(cb, delayMs));
119
+ }
120
+
121
+ export { MAX_DELAY_MS, clearAll, clearKey, clearKeys, putTimer, setCappedTimeout, setCappedTimeoutInMap, setTimeoutController, setTimeoutInMap };
122
+ //# sourceMappingURL=timers.mjs.map