@payloadcms/ui 4.0.0-canary.20 → 4.0.0-canary.21

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 (86) hide show
  1. package/dist/elements/CopyToClipboard/index.d.ts +1 -0
  2. package/dist/elements/CopyToClipboard/index.d.ts.map +1 -1
  3. package/dist/elements/CopyToClipboard/index.js +10 -8
  4. package/dist/elements/CopyToClipboard/index.js.map +1 -1
  5. package/dist/elements/FileManager/FileToolbar/index.d.ts.map +1 -1
  6. package/dist/elements/FileManager/FileToolbar/index.js +3 -0
  7. package/dist/elements/FileManager/FileToolbar/index.js.map +1 -1
  8. package/dist/exports/client/index.d.ts +2 -1
  9. package/dist/exports/client/index.d.ts.map +1 -1
  10. package/dist/exports/client/index.js +1 -1
  11. package/dist/exports/client/index.js.map +3 -3
  12. package/dist/forms/Form/index.d.ts.map +1 -1
  13. package/dist/forms/Form/index.js +4 -1
  14. package/dist/forms/Form/index.js.map +1 -1
  15. package/dist/providers/Auth/AuthSessionDebug/index.css +48 -0
  16. package/dist/providers/Auth/AuthSessionDebug/index.d.ts +13 -0
  17. package/dist/providers/Auth/AuthSessionDebug/index.d.ts.map +1 -0
  18. package/dist/providers/Auth/AuthSessionDebug/index.js +93 -0
  19. package/dist/providers/Auth/AuthSessionDebug/index.js.map +1 -0
  20. package/dist/providers/Auth/AuthSessionDebug/utilities.d.ts +21 -0
  21. package/dist/providers/Auth/AuthSessionDebug/utilities.d.ts.map +1 -0
  22. package/dist/providers/Auth/AuthSessionDebug/utilities.js +53 -0
  23. package/dist/providers/Auth/AuthSessionDebug/utilities.js.map +1 -0
  24. package/dist/providers/Auth/authSessionRequests.d.ts +27 -0
  25. package/dist/providers/Auth/authSessionRequests.d.ts.map +1 -0
  26. package/dist/providers/Auth/authSessionRequests.js +119 -0
  27. package/dist/providers/Auth/authSessionRequests.js.map +1 -0
  28. package/dist/providers/Auth/authSessionRequests.spec.js +121 -0
  29. package/dist/providers/Auth/authSessionRequests.spec.js.map +1 -0
  30. package/dist/providers/Auth/index.d.ts +2 -56
  31. package/dist/providers/Auth/index.d.ts.map +1 -1
  32. package/dist/providers/Auth/index.js +283 -135
  33. package/dist/providers/Auth/index.js.map +1 -1
  34. package/dist/providers/Auth/sessionActivity.d.ts +23 -0
  35. package/dist/providers/Auth/sessionActivity.d.ts.map +1 -0
  36. package/dist/providers/Auth/sessionActivity.js +49 -0
  37. package/dist/providers/Auth/sessionActivity.js.map +1 -0
  38. package/dist/providers/Auth/sessionActivity.spec.js +44 -0
  39. package/dist/providers/Auth/sessionActivity.spec.js.map +1 -0
  40. package/dist/providers/Auth/sessionTiming.d.ts +11 -0
  41. package/dist/providers/Auth/sessionTiming.d.ts.map +1 -0
  42. package/dist/providers/Auth/sessionTiming.js +18 -0
  43. package/dist/providers/Auth/sessionTiming.js.map +1 -0
  44. package/dist/providers/Auth/tabSessionSync/index.d.ts +17 -0
  45. package/dist/providers/Auth/tabSessionSync/index.d.ts.map +1 -0
  46. package/dist/providers/Auth/tabSessionSync/index.js +263 -0
  47. package/dist/providers/Auth/tabSessionSync/index.js.map +1 -0
  48. package/dist/providers/Auth/tabSessionSync/index.spec.js +463 -0
  49. package/dist/providers/Auth/tabSessionSync/index.spec.js.map +1 -0
  50. package/dist/providers/Auth/tabSessionSync/types.d.ts +107 -0
  51. package/dist/providers/Auth/tabSessionSync/types.d.ts.map +1 -0
  52. package/dist/providers/Auth/tabSessionSync/types.js +6 -0
  53. package/dist/providers/Auth/tabSessionSync/types.js.map +1 -0
  54. package/dist/providers/Auth/tabSessionSync/useTabSessionSync.d.ts +11 -0
  55. package/dist/providers/Auth/tabSessionSync/useTabSessionSync.d.ts.map +1 -0
  56. package/dist/providers/Auth/tabSessionSync/useTabSessionSync.js +90 -0
  57. package/dist/providers/Auth/tabSessionSync/useTabSessionSync.js.map +1 -0
  58. package/dist/providers/Auth/tabSessionSync/utilities.d.ts +26 -0
  59. package/dist/providers/Auth/tabSessionSync/utilities.d.ts.map +1 -0
  60. package/dist/providers/Auth/tabSessionSync/utilities.js +159 -0
  61. package/dist/providers/Auth/tabSessionSync/utilities.js.map +1 -0
  62. package/dist/providers/Auth/types.d.ts +66 -0
  63. package/dist/providers/Auth/types.d.ts.map +1 -0
  64. package/dist/providers/Auth/types.js +2 -0
  65. package/dist/providers/Auth/types.js.map +1 -0
  66. package/dist/providers/Auth/useAuthSessionTimers.d.ts +26 -0
  67. package/dist/providers/Auth/useAuthSessionTimers.d.ts.map +1 -0
  68. package/dist/providers/Auth/useAuthSessionTimers.js +203 -0
  69. package/dist/providers/Auth/useAuthSessionTimers.js.map +1 -0
  70. package/dist/providers/Auth/useAuthSessionTimers.spec.js +311 -0
  71. package/dist/providers/Auth/useAuthSessionTimers.spec.js.map +1 -0
  72. package/dist/providers/FormErrorHandler/index.d.ts +5 -1
  73. package/dist/providers/FormErrorHandler/index.d.ts.map +1 -1
  74. package/dist/providers/FormErrorHandler/index.js.map +1 -1
  75. package/dist/providers/Root/index.js +4 -4
  76. package/dist/providers/Root/index.js.map +1 -1
  77. package/dist/providers/RouteTransition/ProgressBar/index.js +4 -1
  78. package/dist/providers/RouteTransition/ProgressBar/index.js.map +1 -1
  79. package/dist/providers/RouteTransition/ProgressBar/index.spec.js +44 -0
  80. package/dist/providers/RouteTransition/ProgressBar/index.spec.js.map +1 -0
  81. package/dist/providers/RouteTransition/index.d.ts +2 -0
  82. package/dist/providers/RouteTransition/index.d.ts.map +1 -1
  83. package/dist/providers/RouteTransition/index.js +42 -14
  84. package/dist/providers/RouteTransition/index.js.map +1 -1
  85. package/dist/styles.css +1 -1
  86. package/package.json +5 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTabSessionSync.d.ts","sourceRoot":"","sources":["../../../../src/providers/Auth/tabSessionSync/useTabSessionSync.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,eAAe,EACf,2BAA2B,EAC3B,qBAAqB,EACtB,MAAM,YAAY,CAAA;AAEnB,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEjD,MAAM,MAAM,cAAc,GAAG;IAC3B,sEAAsE;IACtE,SAAS,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,qBAAqB,GAAG,SAAS,CAAA;IACxE,mFAAmF;IACnF,yBAAyB,EAAE,CAAC,WAAW,EAAE,2BAA2B,KAAK,IAAI,CAAA;CAC9E,CAAA;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,GACvE,cAAc,CA4ChB"}
@@ -0,0 +1,90 @@
1
+ 'use client';
2
+
3
+ import { c as _c } from "react/compiler-runtime";
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { createTabSessionSync } from './index.js';
6
+ /** Connects the Auth provider to one cross-tab session coordinator for the current browser tab. */
7
+ export function useTabSessionSync(options) {
8
+ const $ = _c(9);
9
+ const [sourceTabID] = useState(createTabID);
10
+ const optionsRef = useRef(options);
11
+ const tabSessionSyncRef = useRef(undefined);
12
+ let t0;
13
+ let t1;
14
+ if ($[0] !== options) {
15
+ t0 = () => {
16
+ optionsRef.current = options;
17
+ };
18
+ t1 = [options];
19
+ $[0] = options;
20
+ $[1] = t0;
21
+ $[2] = t1;
22
+ } else {
23
+ t0 = $[1];
24
+ t1 = $[2];
25
+ }
26
+ useEffect(t0, t1);
27
+ let t2;
28
+ let t3;
29
+ if ($[3] !== sourceTabID) {
30
+ t2 = () => {
31
+ const tabSessionSync = createTabSessionSync({
32
+ getTokenExpirationMs: () => optionsRef.current.getTokenExpirationMs(),
33
+ onSessionExpired: expiredTokenAt => optionsRef.current.onSessionExpired(expiredTokenAt),
34
+ onSessionLoggedOut: () => optionsRef.current.onSessionLoggedOut(),
35
+ onSessionRefreshed: session => optionsRef.current.onSessionRefreshed(session),
36
+ onTabSessionUnauthenticated: () => optionsRef.current.onTabSessionUnauthenticated(),
37
+ reconcileSession: reconciliationOptions => optionsRef.current.reconcileSession(reconciliationOptions),
38
+ sourceTabID
39
+ });
40
+ tabSessionSyncRef.current = tabSessionSync;
41
+ return () => {
42
+ if (tabSessionSyncRef.current === tabSessionSync) {
43
+ tabSessionSyncRef.current = undefined;
44
+ }
45
+ tabSessionSync.cleanup();
46
+ };
47
+ };
48
+ t3 = [sourceTabID];
49
+ $[3] = sourceTabID;
50
+ $[4] = t2;
51
+ $[5] = t3;
52
+ } else {
53
+ t2 = $[4];
54
+ t3 = $[5];
55
+ }
56
+ useEffect(t2, t3);
57
+ let t4;
58
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
59
+ t4 = event => tabSessionSyncRef.current?.broadcast(event);
60
+ $[6] = t4;
61
+ } else {
62
+ t4 = $[6];
63
+ }
64
+ const broadcast = t4;
65
+ let t5;
66
+ if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
67
+ t5 = publication => {
68
+ tabSessionSyncRef.current?.broadcastLogoutSettlement(publication);
69
+ };
70
+ $[7] = t5;
71
+ } else {
72
+ t5 = $[7];
73
+ }
74
+ const broadcastLogoutSettlement = t5;
75
+ let t6;
76
+ if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
77
+ t6 = {
78
+ broadcast,
79
+ broadcastLogoutSettlement
80
+ };
81
+ $[8] = t6;
82
+ } else {
83
+ t6 = $[8];
84
+ }
85
+ return t6;
86
+ }
87
+ function createTabID() {
88
+ return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`;
89
+ }
90
+ //# sourceMappingURL=useTabSessionSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTabSessionSync.js","names":["c","_c","useCallback","useEffect","useMemo","useRef","useState","createTabSessionSync","useTabSessionSync","options","$","sourceTabID","createTabID","optionsRef","tabSessionSyncRef","undefined","t0","t1","current","t2","t3","tabSessionSync","getTokenExpirationMs","onSessionExpired","expiredTokenAt","onSessionLoggedOut","onSessionRefreshed","session","onTabSessionUnauthenticated","reconcileSession","reconciliationOptions","cleanup","t4","Symbol","for","event","broadcast","t5","publication","broadcastLogoutSettlement","t6","globalThis","crypto","randomUUID","Date","now","Math","random"],"sources":["../../../../src/providers/Auth/tabSessionSync/useTabSessionSync.ts"],"sourcesContent":["'use client'\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type {\n TabSessionEvent,\n TabSessionLogoutPublication,\n TabSessionPublication,\n} from './index.js'\n\nimport { createTabSessionSync } from './index.js'\n\nexport type TabSessionSync = {\n /** Broadcasts a session lifecycle event to the other browser tabs. */\n broadcast: (event: TabSessionEvent) => TabSessionPublication | undefined\n /** Notifies storage-fallback tabs after the server-side logout request settles. */\n broadcastLogoutSettlement: (publication: TabSessionLogoutPublication) => void\n}\n\n/** Connects the Auth provider to one cross-tab session coordinator for the current browser tab. */\nexport function useTabSessionSync(\n options: Omit<Parameters<typeof createTabSessionSync>[0], 'sourceTabID'>,\n): TabSessionSync {\n const [sourceTabID] = useState(createTabID)\n const optionsRef = useRef(options)\n const tabSessionSyncRef = useRef<ReturnType<typeof createTabSessionSync>>(undefined)\n\n useEffect(() => {\n optionsRef.current = options\n }, [options])\n\n useEffect(() => {\n const tabSessionSync = createTabSessionSync({\n getTokenExpirationMs: () => optionsRef.current.getTokenExpirationMs(),\n onSessionExpired: (expiredTokenAt) => optionsRef.current.onSessionExpired(expiredTokenAt),\n onSessionLoggedOut: () => optionsRef.current.onSessionLoggedOut(),\n onSessionRefreshed: (session) => optionsRef.current.onSessionRefreshed(session),\n onTabSessionUnauthenticated: () => optionsRef.current.onTabSessionUnauthenticated(),\n reconcileSession: (reconciliationOptions) =>\n optionsRef.current.reconcileSession(reconciliationOptions),\n sourceTabID,\n })\n\n tabSessionSyncRef.current = tabSessionSync\n\n return () => {\n if (tabSessionSyncRef.current === tabSessionSync) {\n tabSessionSyncRef.current = undefined\n }\n\n tabSessionSync.cleanup()\n }\n }, [sourceTabID])\n\n const broadcast = useCallback(\n (event: TabSessionEvent) => tabSessionSyncRef.current?.broadcast(event),\n [],\n )\n const broadcastLogoutSettlement = useCallback((publication: TabSessionLogoutPublication) => {\n tabSessionSyncRef.current?.broadcastLogoutSettlement(publication)\n }, [])\n\n return useMemo(\n () => ({ broadcast, broadcastLogoutSettlement }),\n [broadcast, broadcastLogoutSettlement],\n )\n}\n\nfunction createTabID(): string {\n return globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,26 @@
1
+ import type { TabSessionEvent, TabSessionLifecycleOrder, TabSessionMessage, TabSessionStorageNotification } from './types.js';
2
+ export declare const tabSessionSyncStorageKey = "payload:auth-session:tab-sync";
3
+ export declare const tabSessionSyncChannelName = "payload-auth-session-tab-sync";
4
+ export declare function isTabSessionMessage(value: unknown): value is TabSessionMessage;
5
+ export declare function isTabSessionStorageNotification(value: unknown): value is TabSessionStorageNotification;
6
+ export declare function parseTabSessionStorageNotification(event: StorageEvent): null | TabSessionStorageNotification;
7
+ /**
8
+ * Orders two lifecycle events from oldest to newest.
9
+ *
10
+ * A refresh is ordered from when it started rather than when its response was published. This
11
+ * prevents a refresh that began before a logout or expiration from restoring that older session.
12
+ */
13
+ export declare function compareLifecycleOrders({ first, second, }: {
14
+ first: TabSessionLifecycleOrder;
15
+ second: TabSessionLifecycleOrder;
16
+ }): number;
17
+ export declare function getLifecycleOrder(event: {
18
+ sentAt: number;
19
+ sourceTabID: string;
20
+ } & TabSessionEvent): TabSessionLifecycleOrder;
21
+ export declare function createTabSessionMessage({ event, sentAt, sourceTabID, }: {
22
+ event: TabSessionEvent;
23
+ sentAt: number;
24
+ sourceTabID: string;
25
+ }): TabSessionMessage;
26
+ //# sourceMappingURL=utilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../../../../src/providers/Auth/tabSessionSync/utilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,wBAAwB,EACxB,iBAAiB,EACjB,6BAA6B,EAC9B,MAAM,YAAY,CAAA;AAInB,eAAO,MAAM,wBAAwB,kCAAkC,CAAA;AACvE,eAAO,MAAM,yBAAyB,kCAAkC,CAAA;AAExE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CA0C9E;AAED,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,6BAA6B,CAsCxC;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE,YAAY,GAClB,IAAI,GAAG,6BAA6B,CActC;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,KAAK,EACL,MAAM,GACP,EAAE;IACD,KAAK,EAAE,wBAAwB,CAAA;IAC/B,MAAM,EAAE,wBAAwB,CAAA;CACjC,GAAG,MAAM,CAoCT;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,GAC/D,wBAAwB,CAwB1B;AAED,wBAAgB,uBAAuB,CAAC,EACtC,KAAK,EACL,MAAM,EACN,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,iBAAiB,CAgBpB"}
@@ -0,0 +1,159 @@
1
+ import { TAB_SESSION_EVENT_TYPES } from './types.js';
2
+ export const tabSessionSyncStorageKey = 'payload:auth-session:tab-sync';
3
+ export const tabSessionSyncChannelName = 'payload-auth-session-tab-sync';
4
+ export function isTabSessionMessage(value) {
5
+ if (!value || typeof value !== 'object' || !('sourceTabID' in value) || typeof value.sourceTabID !== 'string' || !('sentAt' in value) || typeof value.sentAt !== 'number' || !Number.isFinite(value.sentAt) || !('type' in value)) {
6
+ return false;
7
+ }
8
+ if (value.type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT) {
9
+ return true;
10
+ }
11
+ if (value.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {
12
+ return 'expiredTokenAt' in value && typeof value.expiredTokenAt === 'number' && Number.isFinite(value.expiredTokenAt);
13
+ }
14
+ if (value.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {
15
+ return 'refreshStartedAt' in value && typeof value.refreshStartedAt === 'number' && Number.isFinite(value.refreshStartedAt) && 'session' in value && Boolean(value.session) && typeof value.session === 'object' && 'exp' in value.session && typeof value.session.exp === 'number' && Number.isFinite(value.session.exp) && 'user' in value.session;
16
+ }
17
+ return false;
18
+ }
19
+ export function isTabSessionStorageNotification(value) {
20
+ if (!value || typeof value !== 'object' || !('affectedExpirationMs' in value) || typeof value.affectedExpirationMs !== 'number' || !Number.isFinite(value.affectedExpirationMs) || !('sentAt' in value) || typeof value.sentAt !== 'number' || !Number.isFinite(value.sentAt) || !('sourceTabID' in value) || typeof value.sourceTabID !== 'string' || !('type' in value) || !isTabSessionEventType(value.type) || 'isBroadcastChannelFallback' in value && value.isBroadcastChannelFallback !== true) {
21
+ return false;
22
+ }
23
+ if (value.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {
24
+ return !('settlesSentAt' in value);
25
+ }
26
+ if (value.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {
27
+ return !('settlesSentAt' in value) && 'refreshStartedAt' in value && typeof value.refreshStartedAt === 'number' && Number.isFinite(value.refreshStartedAt);
28
+ }
29
+ return value.affectedExpirationMs === 0 && 'settlesSentAt' in value && typeof value.settlesSentAt === 'number' && Number.isFinite(value.settlesSentAt);
30
+ }
31
+ export function parseTabSessionStorageNotification(event) {
32
+ if (event.key !== tabSessionSyncStorageKey || !event.newValue) {
33
+ return null;
34
+ }
35
+ try {
36
+ const notification = JSON.parse(event.newValue);
37
+ return isTabSessionStorageNotification(notification) ? notification : null;
38
+ } catch {
39
+ // Ignore storage writes that do not belong to cross-tab session synchronization.
40
+ }
41
+ return null;
42
+ }
43
+ /**
44
+ * Orders two lifecycle events from oldest to newest.
45
+ *
46
+ * A refresh is ordered from when it started rather than when its response was published. This
47
+ * prevents a refresh that began before a logout or expiration from restoring that older session.
48
+ */
49
+ export function compareLifecycleOrders({
50
+ first,
51
+ second
52
+ }) {
53
+ const isFirstRefresh = first.type === TAB_SESSION_EVENT_TYPES.REFRESHED;
54
+ const isSecondRefresh = second.type === TAB_SESSION_EVENT_TYPES.REFRESHED;
55
+ if (isFirstRefresh !== isSecondRefresh) {
56
+ const firstOrderingFence = getLifecycleOrderingFence(first);
57
+ const secondOrderingFence = getLifecycleOrderingFence(second);
58
+ if (firstOrderingFence !== secondOrderingFence) {
59
+ return firstOrderingFence - secondOrderingFence;
60
+ }
61
+ }
62
+ const isFirstLogout = first.type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT;
63
+ const isSecondLogout = second.type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT;
64
+ if (isFirstLogout !== isSecondLogout) {
65
+ return isFirstLogout ? 1 : -1;
66
+ }
67
+ if (first.sentAt !== second.sentAt) {
68
+ return first.sentAt - second.sentAt;
69
+ }
70
+ if (first.affectedExpirationMs !== second.affectedExpirationMs) {
71
+ return first.affectedExpirationMs - second.affectedExpirationMs;
72
+ }
73
+ const firstPrecedence = getLifecyclePrecedence(first.type);
74
+ const secondPrecedence = getLifecyclePrecedence(second.type);
75
+ if (firstPrecedence !== secondPrecedence) {
76
+ return firstPrecedence - secondPrecedence;
77
+ }
78
+ return compareSourceTabIDs({
79
+ first: first.sourceTabID,
80
+ second: second.sourceTabID
81
+ });
82
+ }
83
+ export function getLifecycleOrder(event) {
84
+ const lifecycleMetadata = {
85
+ sentAt: event.sentAt,
86
+ sourceTabID: event.sourceTabID
87
+ };
88
+ if (event.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {
89
+ return {
90
+ type: event.type,
91
+ affectedExpirationMs: event.session.exp * 1000,
92
+ refreshStartedAt: event.refreshStartedAt,
93
+ ...lifecycleMetadata
94
+ };
95
+ }
96
+ if (event.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {
97
+ return {
98
+ type: event.type,
99
+ affectedExpirationMs: event.expiredTokenAt,
100
+ ...lifecycleMetadata
101
+ };
102
+ }
103
+ return {
104
+ type: event.type,
105
+ affectedExpirationMs: 0,
106
+ ...lifecycleMetadata
107
+ };
108
+ }
109
+ export function createTabSessionMessage({
110
+ event,
111
+ sentAt,
112
+ sourceTabID
113
+ }) {
114
+ if (event.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {
115
+ return {
116
+ type: event.type,
117
+ refreshStartedAt: event.refreshStartedAt,
118
+ sentAt,
119
+ session: event.session,
120
+ sourceTabID
121
+ };
122
+ }
123
+ if (event.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {
124
+ return {
125
+ type: event.type,
126
+ expiredTokenAt: event.expiredTokenAt,
127
+ sentAt,
128
+ sourceTabID
129
+ };
130
+ }
131
+ return {
132
+ type: event.type,
133
+ sentAt,
134
+ sourceTabID
135
+ };
136
+ }
137
+ function compareSourceTabIDs({
138
+ first,
139
+ second
140
+ }) {
141
+ if (first === second) {
142
+ return 0;
143
+ }
144
+ return first > second ? 1 : -1;
145
+ }
146
+ /** Returns the point in time when a lifecycle event began affecting the session. */
147
+ function getLifecycleOrderingFence(order) {
148
+ return order.type === TAB_SESSION_EVENT_TYPES.REFRESHED ? order.refreshStartedAt : order.sentAt;
149
+ }
150
+ function getLifecyclePrecedence(type) {
151
+ if (type === TAB_SESSION_EVENT_TYPES.EXPIRED) {
152
+ return 1;
153
+ }
154
+ return type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT ? 2 : 0;
155
+ }
156
+ function isTabSessionEventType(value) {
157
+ return Object.values(TAB_SESSION_EVENT_TYPES).some(eventType => eventType === value);
158
+ }
159
+ //# sourceMappingURL=utilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utilities.js","names":["TAB_SESSION_EVENT_TYPES","tabSessionSyncStorageKey","tabSessionSyncChannelName","isTabSessionMessage","value","sourceTabID","sentAt","Number","isFinite","type","LOGGED_OUT","EXPIRED","expiredTokenAt","REFRESHED","refreshStartedAt","Boolean","session","exp","isTabSessionStorageNotification","affectedExpirationMs","isTabSessionEventType","isBroadcastChannelFallback","settlesSentAt","parseTabSessionStorageNotification","event","key","newValue","notification","JSON","parse","compareLifecycleOrders","first","second","isFirstRefresh","isSecondRefresh","firstOrderingFence","getLifecycleOrderingFence","secondOrderingFence","isFirstLogout","isSecondLogout","firstPrecedence","getLifecyclePrecedence","secondPrecedence","compareSourceTabIDs","getLifecycleOrder","lifecycleMetadata","createTabSessionMessage","order","Object","values","some","eventType"],"sources":["../../../../src/providers/Auth/tabSessionSync/utilities.ts"],"sourcesContent":["import type {\n TabSessionEvent,\n TabSessionEventType,\n TabSessionLifecycleOrder,\n TabSessionMessage,\n TabSessionStorageNotification,\n} from './types.js'\n\nimport { TAB_SESSION_EVENT_TYPES } from './types.js'\n\nexport const tabSessionSyncStorageKey = 'payload:auth-session:tab-sync'\nexport const tabSessionSyncChannelName = 'payload-auth-session-tab-sync'\n\nexport function isTabSessionMessage(value: unknown): value is TabSessionMessage {\n if (\n !value ||\n typeof value !== 'object' ||\n !('sourceTabID' in value) ||\n typeof value.sourceTabID !== 'string' ||\n !('sentAt' in value) ||\n typeof value.sentAt !== 'number' ||\n !Number.isFinite(value.sentAt) ||\n !('type' in value)\n ) {\n return false\n }\n\n if (value.type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT) {\n return true\n }\n\n if (value.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {\n return (\n 'expiredTokenAt' in value &&\n typeof value.expiredTokenAt === 'number' &&\n Number.isFinite(value.expiredTokenAt)\n )\n }\n\n if (value.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {\n return (\n 'refreshStartedAt' in value &&\n typeof value.refreshStartedAt === 'number' &&\n Number.isFinite(value.refreshStartedAt) &&\n 'session' in value &&\n Boolean(value.session) &&\n typeof value.session === 'object' &&\n 'exp' in value.session &&\n typeof value.session.exp === 'number' &&\n Number.isFinite(value.session.exp) &&\n 'user' in value.session\n )\n }\n\n return false\n}\n\nexport function isTabSessionStorageNotification(\n value: unknown,\n): value is TabSessionStorageNotification {\n if (\n !value ||\n typeof value !== 'object' ||\n !('affectedExpirationMs' in value) ||\n typeof value.affectedExpirationMs !== 'number' ||\n !Number.isFinite(value.affectedExpirationMs) ||\n !('sentAt' in value) ||\n typeof value.sentAt !== 'number' ||\n !Number.isFinite(value.sentAt) ||\n !('sourceTabID' in value) ||\n typeof value.sourceTabID !== 'string' ||\n !('type' in value) ||\n !isTabSessionEventType(value.type) ||\n ('isBroadcastChannelFallback' in value && value.isBroadcastChannelFallback !== true)\n ) {\n return false\n }\n\n if (value.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {\n return !('settlesSentAt' in value)\n }\n\n if (value.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {\n return (\n !('settlesSentAt' in value) &&\n 'refreshStartedAt' in value &&\n typeof value.refreshStartedAt === 'number' &&\n Number.isFinite(value.refreshStartedAt)\n )\n }\n\n return (\n value.affectedExpirationMs === 0 &&\n 'settlesSentAt' in value &&\n typeof value.settlesSentAt === 'number' &&\n Number.isFinite(value.settlesSentAt)\n )\n}\n\nexport function parseTabSessionStorageNotification(\n event: StorageEvent,\n): null | TabSessionStorageNotification {\n if (event.key !== tabSessionSyncStorageKey || !event.newValue) {\n return null\n }\n\n try {\n const notification: unknown = JSON.parse(event.newValue)\n\n return isTabSessionStorageNotification(notification) ? notification : null\n } catch {\n // Ignore storage writes that do not belong to cross-tab session synchronization.\n }\n\n return null\n}\n\n/**\n * Orders two lifecycle events from oldest to newest.\n *\n * A refresh is ordered from when it started rather than when its response was published. This\n * prevents a refresh that began before a logout or expiration from restoring that older session.\n */\nexport function compareLifecycleOrders({\n first,\n second,\n}: {\n first: TabSessionLifecycleOrder\n second: TabSessionLifecycleOrder\n}): number {\n const isFirstRefresh = first.type === TAB_SESSION_EVENT_TYPES.REFRESHED\n const isSecondRefresh = second.type === TAB_SESSION_EVENT_TYPES.REFRESHED\n\n if (isFirstRefresh !== isSecondRefresh) {\n const firstOrderingFence = getLifecycleOrderingFence(first)\n const secondOrderingFence = getLifecycleOrderingFence(second)\n\n if (firstOrderingFence !== secondOrderingFence) {\n return firstOrderingFence - secondOrderingFence\n }\n }\n\n const isFirstLogout = first.type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT\n const isSecondLogout = second.type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT\n\n if (isFirstLogout !== isSecondLogout) {\n return isFirstLogout ? 1 : -1\n }\n\n if (first.sentAt !== second.sentAt) {\n return first.sentAt - second.sentAt\n }\n\n if (first.affectedExpirationMs !== second.affectedExpirationMs) {\n return first.affectedExpirationMs - second.affectedExpirationMs\n }\n\n const firstPrecedence = getLifecyclePrecedence(first.type)\n const secondPrecedence = getLifecyclePrecedence(second.type)\n\n if (firstPrecedence !== secondPrecedence) {\n return firstPrecedence - secondPrecedence\n }\n\n return compareSourceTabIDs({ first: first.sourceTabID, second: second.sourceTabID })\n}\n\nexport function getLifecycleOrder(\n event: { sentAt: number; sourceTabID: string } & TabSessionEvent,\n): TabSessionLifecycleOrder {\n const lifecycleMetadata = {\n sentAt: event.sentAt,\n sourceTabID: event.sourceTabID,\n }\n\n if (event.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {\n return {\n type: event.type,\n affectedExpirationMs: event.session.exp * 1000,\n refreshStartedAt: event.refreshStartedAt,\n ...lifecycleMetadata,\n }\n }\n\n if (event.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {\n return {\n type: event.type,\n affectedExpirationMs: event.expiredTokenAt,\n ...lifecycleMetadata,\n }\n }\n\n return { type: event.type, affectedExpirationMs: 0, ...lifecycleMetadata }\n}\n\nexport function createTabSessionMessage({\n event,\n sentAt,\n sourceTabID,\n}: {\n event: TabSessionEvent\n sentAt: number\n sourceTabID: string\n}): TabSessionMessage {\n if (event.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {\n return {\n type: event.type,\n refreshStartedAt: event.refreshStartedAt,\n sentAt,\n session: event.session,\n sourceTabID,\n }\n }\n\n if (event.type === TAB_SESSION_EVENT_TYPES.EXPIRED) {\n return { type: event.type, expiredTokenAt: event.expiredTokenAt, sentAt, sourceTabID }\n }\n\n return { type: event.type, sentAt, sourceTabID }\n}\n\nfunction compareSourceTabIDs({ first, second }: { first: string; second: string }): number {\n if (first === second) {\n return 0\n }\n\n return first > second ? 1 : -1\n}\n\n/** Returns the point in time when a lifecycle event began affecting the session. */\nfunction getLifecycleOrderingFence(order: TabSessionLifecycleOrder): number {\n return order.type === TAB_SESSION_EVENT_TYPES.REFRESHED ? order.refreshStartedAt : order.sentAt\n}\n\nfunction getLifecyclePrecedence(type: TabSessionEventType): number {\n if (type === TAB_SESSION_EVENT_TYPES.EXPIRED) {\n return 1\n }\n\n return type === TAB_SESSION_EVENT_TYPES.LOGGED_OUT ? 2 : 0\n}\n\nfunction isTabSessionEventType(value: unknown): value is TabSessionEventType {\n return Object.values(TAB_SESSION_EVENT_TYPES).some((eventType) => eventType === value)\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,66 @@
1
+ import type { AuthenticatedUser, SanitizedPermissions } from 'payload';
2
+ export type AuthSession = {
3
+ /** Whether qualifying activity has been recorded for the current token. */
4
+ readonly activityRecorded: boolean;
5
+ readonly activityTrackingStartsAt: number;
6
+ readonly expiresAt: number;
7
+ readonly refreshStartsAt: number;
8
+ readonly reminderStartsAt: number;
9
+ };
10
+ export type UserWithToken<T = AuthenticatedUser> = {
11
+ /** seconds until expiration */
12
+ exp: number;
13
+ refreshedToken?: string;
14
+ token?: string;
15
+ user: T;
16
+ };
17
+ export type AuthContext<T = AuthenticatedUser> = {
18
+ /** Lifecycle state for the current auth session. */
19
+ authSession?: AuthSession;
20
+ fetchFullUser: () => Promise<null | T>;
21
+ logOut: () => Promise<boolean>;
22
+ /**
23
+ * These are the permissions for the current user from a global scope.
24
+ *
25
+ * When checking for permissions on document specific level, use the `useDocumentInfo` hook instead.
26
+ *
27
+ * @example
28
+ *
29
+ * ```tsx
30
+ * import { useAuth } from 'payload/ui'
31
+ *
32
+ * const MyComponent: React.FC = () => {
33
+ * const { permissions } = useAuth()
34
+ *
35
+ * if (permissions?.collections?.myCollection?.create) {
36
+ * // user can create documents in 'myCollection'
37
+ * }
38
+ *
39
+ * return null
40
+ * }
41
+ * ```
42
+ *
43
+ * with useDocumentInfo:
44
+ *
45
+ * ```tsx
46
+ * import { useDocumentInfo } from 'payload/ui'
47
+ *
48
+ * const MyComponent: React.FC = () => {
49
+ * const { docPermissions } = useDocumentInfo()
50
+ * if (docPermissions?.create) {
51
+ * // user can create this document
52
+ * }
53
+ * return null
54
+ * } ```
55
+ */
56
+ permissions?: SanitizedPermissions;
57
+ refreshCookie: (forceRefresh?: boolean) => void;
58
+ refreshCookieAsync: () => Promise<null | T>;
59
+ refreshPermissions: () => Promise<void>;
60
+ setPermissions: (permissions: SanitizedPermissions) => void;
61
+ setUser: (user: null | UserWithToken<T>) => void;
62
+ strategy?: string;
63
+ token?: string;
64
+ user?: null | T;
65
+ };
66
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/Auth/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAA;IACzC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,iBAAiB,IAAI;IACjD,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,CAAC,CAAA;CACR,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,iBAAiB,IAAI;IAC/C,oDAAoD;IACpD,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;IACtC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,WAAW,CAAC,EAAE,oBAAoB,CAAA;IAClC,aAAa,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAC/C,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;IAC3C,kBAAkB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,cAAc,EAAE,CAAC,WAAW,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAC3D,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,CAAA;CAChB,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/providers/Auth/types.ts"],"sourcesContent":["import type { AuthenticatedUser, SanitizedPermissions } from 'payload'\n\nexport type AuthSession = {\n /** Whether qualifying activity has been recorded for the current token. */\n readonly activityRecorded: boolean\n readonly activityTrackingStartsAt: number\n readonly expiresAt: number\n readonly refreshStartsAt: number\n readonly reminderStartsAt: number\n}\n\nexport type UserWithToken<T = AuthenticatedUser> = {\n /** seconds until expiration */\n exp: number\n refreshedToken?: string\n token?: string\n user: T\n}\n\nexport type AuthContext<T = AuthenticatedUser> = {\n /** Lifecycle state for the current auth session. */\n authSession?: AuthSession\n fetchFullUser: () => Promise<null | T>\n logOut: () => Promise<boolean>\n /**\n * These are the permissions for the current user from a global scope.\n *\n * When checking for permissions on document specific level, use the `useDocumentInfo` hook instead.\n *\n * @example\n *\n * ```tsx\n * import { useAuth } from 'payload/ui'\n *\n * const MyComponent: React.FC = () => {\n * const { permissions } = useAuth()\n *\n * if (permissions?.collections?.myCollection?.create) {\n * // user can create documents in 'myCollection'\n * }\n *\n * return null\n * }\n * ```\n *\n * with useDocumentInfo:\n *\n * ```tsx\n * import { useDocumentInfo } from 'payload/ui'\n *\n * const MyComponent: React.FC = () => {\n * const { docPermissions } = useDocumentInfo()\n * if (docPermissions?.create) {\n * // user can create this document\n * }\n * return null\n * } ```\n */\n permissions?: SanitizedPermissions\n refreshCookie: (forceRefresh?: boolean) => void\n refreshCookieAsync: () => Promise<null | T>\n refreshPermissions: () => Promise<void>\n setPermissions: (permissions: SanitizedPermissions) => void\n setUser: (user: null | UserWithToken<T>) => void\n strategy?: string\n token?: string\n user?: null | T\n}\n"],"mappings":"AAmBA","ignoreList":[]}
@@ -0,0 +1,26 @@
1
+ import type { SessionActivitySource } from './sessionActivity.js';
2
+ import type { AuthSessionTiming } from './sessionTiming.js';
3
+ export type AuthSessionTimers = {
4
+ clear: () => void;
5
+ getCurrentExpirationMs: () => number | undefined;
6
+ /** Records activity only while the activity tracking window is open. */
7
+ recordActivity: (source: SessionActivitySource) => boolean;
8
+ scheduleRefresh: (forceRefresh?: boolean) => void;
9
+ setExpiration: (expirationMs: number) => AuthSessionTiming | undefined;
10
+ };
11
+ export type UseAuthSessionTimersArgs = {
12
+ isAuthenticated: boolean;
13
+ onActivity: () => void;
14
+ onActivityRefresh: () => void;
15
+ onExpire: (expirationMs: number) => void;
16
+ onReminder: () => void;
17
+ };
18
+ /**
19
+ * Manages activity-aware refresh, expiration reminders, and logout timing for the current session.
20
+ *
21
+ * Activity inside the refresh window schedules a refresh. Earlier activity is remembered until the
22
+ * refresh-window checkpoint so the session can still be extended without requiring another
23
+ * activity event.
24
+ */
25
+ export declare function useAuthSessionTimers({ isAuthenticated, onActivity, onActivityRefresh, onExpire, onReminder, }: UseAuthSessionTimersArgs): AuthSessionTimers;
26
+ //# sourceMappingURL=useAuthSessionTimers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAuthSessionTimers.d.ts","sourceRoot":"","sources":["../../../src/providers/Auth/useAuthSessionTimers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAU3D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,IAAI,CAAA;IACjB,sBAAsB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;IAChD,wEAAwE;IACxE,cAAc,EAAE,CAAC,MAAM,EAAE,qBAAqB,KAAK,OAAO,CAAA;IAC1D,eAAe,EAAE,CAAC,YAAY,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IACjD,aAAa,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,iBAAiB,GAAG,SAAS,CAAA;CACvE,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,eAAe,EAAE,OAAO,CAAA;IACxB,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,iBAAiB,EAAE,MAAM,IAAI,CAAA;IAC7B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC,UAAU,EAAE,MAAM,IAAI,CAAA;CACvB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,UAAU,GACX,EAAE,wBAAwB,GAAG,iBAAiB,CAqP9C"}
@@ -0,0 +1,203 @@
1
+ 'use client';
2
+
3
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
4
+ import { createSessionActivityTracker, registerSessionActivityListeners } from './sessionActivity.js';
5
+ import { getAuthSessionTiming } from './sessionTiming.js';
6
+ const maxTimeoutMs = 2_147_483_647 // ~24.8 days
7
+ ;
8
+ /**
9
+ * Manages activity-aware refresh, expiration reminders, and logout timing for the current session.
10
+ *
11
+ * Activity inside the refresh window schedules a refresh. Earlier activity is remembered until the
12
+ * refresh-window checkpoint so the session can still be extended without requiring another
13
+ * activity event.
14
+ */
15
+ export function useAuthSessionTimers({
16
+ isAuthenticated,
17
+ onActivity,
18
+ onActivityRefresh,
19
+ onExpire,
20
+ onReminder
21
+ }) {
22
+ const activityListenerCleanupRef = useRef(undefined);
23
+ const activityCheckpointTimeoutRef = useRef(null);
24
+ const forceLogOutTimeoutRef = useRef(null);
25
+ const hasActiveSessionRef = useRef(isAuthenticated);
26
+ const lastSessionActivityAtRef = useRef(undefined);
27
+ const scheduledRefreshTimeoutRef = useRef(null);
28
+ const reminderTimeoutRef = useRef(null);
29
+ const sessionTimingRef = useRef(undefined);
30
+ const tokenExpirationMsRef = useRef(undefined);
31
+ const callbacksRef = useRef({
32
+ onActivity,
33
+ onActivityRefresh,
34
+ onExpire,
35
+ onReminder
36
+ });
37
+ const scheduleRefresh = useCallback(forceRefresh => {
38
+ if (!hasActiveSessionRef.current) {
39
+ return;
40
+ }
41
+ const sessionTiming = sessionTimingRef.current;
42
+ if (forceRefresh || sessionTiming && Date.now() >= sessionTiming.refreshStartsAt) {
43
+ clearTimeout(scheduledRefreshTimeoutRef.current);
44
+ scheduledRefreshTimeoutRef.current = setTimeout(() => {
45
+ callbacksRef.current.onActivityRefresh();
46
+ }, 1000);
47
+ }
48
+ }, []);
49
+ const activityTracker = useMemo(() => createSessionActivityTracker({
50
+ onActivity: (_source, occurredAt) => {
51
+ const isFirstActivity = lastSessionActivityAtRef.current === undefined;
52
+ lastSessionActivityAtRef.current = occurredAt;
53
+ if (isFirstActivity) {
54
+ callbacksRef.current.onActivity();
55
+ }
56
+ scheduleRefresh();
57
+ }
58
+ }), [scheduleRefresh]);
59
+ const recordActivity = useCallback(source => {
60
+ const occurredAt_0 = Date.now();
61
+ const sessionTiming_0 = sessionTimingRef.current;
62
+ const isActivityWindowOpen = sessionTiming_0 && occurredAt_0 >= sessionTiming_0.activityTrackingStartsAt && occurredAt_0 < sessionTiming_0.reminderStartsAt;
63
+ if (!activityListenerCleanupRef.current || !isActivityWindowOpen) {
64
+ return false;
65
+ }
66
+ return activityTracker.record(source);
67
+ }, [activityTracker]);
68
+ const addActivityListeners = useCallback(() => {
69
+ if (activityListenerCleanupRef.current) {
70
+ return;
71
+ }
72
+ activityListenerCleanupRef.current = registerSessionActivityListeners({
73
+ markActivity: recordActivity,
74
+ window
75
+ });
76
+ }, [recordActivity]);
77
+ const removeActivityListeners = useCallback(() => {
78
+ const cleanup = activityListenerCleanupRef.current;
79
+ if (!cleanup) {
80
+ return;
81
+ }
82
+ activityListenerCleanupRef.current = undefined;
83
+ cleanup();
84
+ }, []);
85
+ const resetSessionLifecycle = useCallback(() => {
86
+ clearTimeout(activityCheckpointTimeoutRef.current);
87
+ clearTimeout(forceLogOutTimeoutRef.current);
88
+ clearTimeout(reminderTimeoutRef.current);
89
+ clearTimeout(scheduledRefreshTimeoutRef.current);
90
+ removeActivityListeners();
91
+ activityTracker.reset();
92
+ lastSessionActivityAtRef.current = undefined;
93
+ }, [activityTracker, removeActivityListeners]);
94
+ const clear = useCallback(() => {
95
+ resetSessionLifecycle();
96
+ hasActiveSessionRef.current = false;
97
+ sessionTimingRef.current = undefined;
98
+ tokenExpirationMsRef.current = undefined;
99
+ }, [resetSessionLifecycle]);
100
+ const setExpiration = useCallback(expirationMs => {
101
+ if (!Number.isFinite(expirationMs)) {
102
+ return;
103
+ }
104
+ resetSessionLifecycle();
105
+ tokenExpirationMsRef.current = expirationMs;
106
+ const sessionTiming_1 = getAuthSessionTiming({
107
+ expirationMs
108
+ });
109
+ sessionTimingRef.current = sessionTiming_1;
110
+ const scheduleReminder = () => {
111
+ if (tokenExpirationMsRef.current !== expirationMs) {
112
+ return;
113
+ }
114
+ const reminderStartsInMs = Math.max(sessionTiming_1.reminderStartsAt - Date.now(), 0);
115
+ reminderTimeoutRef.current = setTimeout(() => {
116
+ if (tokenExpirationMsRef.current !== expirationMs) {
117
+ return;
118
+ }
119
+ if (Date.now() < sessionTiming_1.reminderStartsAt) {
120
+ scheduleReminder();
121
+ return;
122
+ }
123
+ clearTimeout(scheduledRefreshTimeoutRef.current);
124
+ removeActivityListeners();
125
+ if (Date.now() < sessionTiming_1.expiresAt) {
126
+ callbacksRef.current.onReminder();
127
+ }
128
+ }, Math.min(reminderStartsInMs, maxTimeoutMs));
129
+ };
130
+ const scheduleActivityCheckpoint = () => {
131
+ if (tokenExpirationMsRef.current !== expirationMs) {
132
+ return;
133
+ }
134
+ const refreshStartsInMs = Math.max(sessionTiming_1.refreshStartsAt - Date.now(), 0);
135
+ activityCheckpointTimeoutRef.current = setTimeout(() => {
136
+ if (tokenExpirationMsRef.current !== expirationMs) {
137
+ return;
138
+ }
139
+ const checkpointAt = Date.now();
140
+ if (checkpointAt < sessionTiming_1.refreshStartsAt) {
141
+ scheduleActivityCheckpoint();
142
+ return;
143
+ }
144
+ const lastActivityAt = lastSessionActivityAtRef.current;
145
+ const hasRecentActivity = lastActivityAt !== undefined && checkpointAt < sessionTiming_1.reminderStartsAt && lastActivityAt >= sessionTiming_1.activityTrackingStartsAt;
146
+ if (hasRecentActivity) {
147
+ scheduleRefresh(true);
148
+ }
149
+ }, Math.min(refreshStartsInMs, maxTimeoutMs));
150
+ };
151
+ const scheduleExpiration = () => {
152
+ if (tokenExpirationMsRef.current !== expirationMs) {
153
+ return;
154
+ }
155
+ const expiresInMs = Math.max(sessionTiming_1.expiresAt - Date.now(), 0);
156
+ forceLogOutTimeoutRef.current = setTimeout(() => {
157
+ if (tokenExpirationMsRef.current === expirationMs) {
158
+ if (Date.now() < sessionTiming_1.expiresAt) {
159
+ scheduleExpiration();
160
+ return;
161
+ }
162
+ hasActiveSessionRef.current = false;
163
+ removeActivityListeners();
164
+ callbacksRef.current.onExpire(expirationMs);
165
+ }
166
+ }, Math.min(expiresInMs, maxTimeoutMs));
167
+ };
168
+ hasActiveSessionRef.current = expirationMs > Date.now();
169
+ if (hasActiveSessionRef.current) {
170
+ addActivityListeners();
171
+ scheduleReminder();
172
+ scheduleActivityCheckpoint();
173
+ }
174
+ scheduleExpiration();
175
+ return sessionTiming_1;
176
+ }, [addActivityListeners, removeActivityListeners, resetSessionLifecycle, scheduleRefresh]);
177
+ const getCurrentExpirationMs = useCallback(() => tokenExpirationMsRef.current, []);
178
+ useEffect(() => {
179
+ callbacksRef.current = {
180
+ onActivity,
181
+ onActivityRefresh,
182
+ onExpire,
183
+ onReminder
184
+ };
185
+ }, [onActivity, onActivityRefresh, onExpire, onReminder]);
186
+ useEffect(() => {
187
+ hasActiveSessionRef.current = isAuthenticated;
188
+ if (!isAuthenticated) {
189
+ removeActivityListeners();
190
+ }
191
+ }, [isAuthenticated, removeActivityListeners]);
192
+ useEffect(() => {
193
+ return clear;
194
+ }, [clear]);
195
+ return useMemo(() => ({
196
+ clear,
197
+ getCurrentExpirationMs,
198
+ recordActivity,
199
+ scheduleRefresh,
200
+ setExpiration
201
+ }), [clear, getCurrentExpirationMs, recordActivity, scheduleRefresh, setExpiration]);
202
+ }
203
+ //# sourceMappingURL=useAuthSessionTimers.js.map