@payloadcms/ui 4.0.0-canary.34 → 4.0.0-canary.36

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 (180) hide show
  1. package/dist/css/app.css +1 -0
  2. package/dist/css/preflight.css +1 -0
  3. package/dist/css/spacing.css +3 -0
  4. package/dist/elements/AppHeader/index.css +3 -0
  5. package/dist/elements/BulkUpload/ActionsBar/index.css +1 -0
  6. package/dist/elements/BulkUpload/AddingFilesView/index.css +2 -4
  7. package/dist/elements/BulkUpload/FileSidebar/index.css +1 -0
  8. package/dist/elements/BulkUpload/FormsManager/index.d.ts.map +1 -1
  9. package/dist/elements/BulkUpload/FormsManager/index.js +12 -7
  10. package/dist/elements/BulkUpload/FormsManager/index.js.map +1 -1
  11. package/dist/elements/BulkUpload/index.css +2 -0
  12. package/dist/elements/Collapsible/index.css +1 -0
  13. package/dist/elements/DatePicker/index.css +2 -0
  14. package/dist/elements/Dialog/index.css +1 -0
  15. package/dist/elements/DocumentControls/index.css +1 -0
  16. package/dist/elements/DocumentFields/index.css +2 -0
  17. package/dist/elements/DocumentHeader/Tabs/index.css +1 -0
  18. package/dist/elements/DocumentHeader/index.css +1 -0
  19. package/dist/elements/EditUpload/index.css +1 -1
  20. package/dist/elements/FieldDiffContainer/index.css +1 -0
  21. package/dist/elements/FieldDiffLabel/index.css +1 -0
  22. package/dist/elements/FileDetails/StaticFileDetails/index.css +2 -0
  23. package/dist/elements/HTMLDiff/index.css +1 -0
  24. package/dist/elements/ItemsDrawer/index.css +3 -0
  25. package/dist/elements/ListControls/index.css +1 -0
  26. package/dist/elements/ListControls/index.d.ts.map +1 -1
  27. package/dist/elements/ListControls/index.js +7 -1
  28. package/dist/elements/ListControls/index.js.map +1 -1
  29. package/dist/elements/ListControls/types.d.ts +3 -1
  30. package/dist/elements/ListControls/types.d.ts.map +1 -1
  31. package/dist/elements/ListControls/types.js.map +1 -1
  32. package/dist/elements/ListControlsBar/index.css +1 -0
  33. package/dist/elements/ListHeader/TitleActions/ListEmptyTrashButton.js +1 -1
  34. package/dist/elements/ListHeader/TitleActions/ListEmptyTrashButton.js.map +1 -1
  35. package/dist/elements/LivePreview/Window/index.css +1 -0
  36. package/dist/elements/Nav/index.css +2 -0
  37. package/dist/elements/PageControls/index.css +1 -0
  38. package/dist/elements/PillSelector/index.css +1 -0
  39. package/dist/elements/PreviewSizes/index.css +2 -0
  40. package/dist/elements/PublishButton/index.css +1 -0
  41. package/dist/elements/QueryPresets/fields/Heading/index.css +1 -0
  42. package/dist/elements/RenderTitle/index.css +1 -0
  43. package/dist/elements/Table/index.css +1 -0
  44. package/dist/elements/TableSection/index.css +1 -0
  45. package/dist/elements/Tabs/index.css +1 -0
  46. package/dist/elements/Thumbnail/index.css +1 -0
  47. package/dist/elements/TimezonePicker/index.css +1 -0
  48. package/dist/elements/Tooltip/index.css +7 -0
  49. package/dist/elements/WhereBuilder/Condition/index.css +1 -0
  50. package/dist/elements/WhereBuilder/index.css +2 -0
  51. package/dist/fields/Array/index.css +1 -0
  52. package/dist/fields/Blocks/index.css +1 -0
  53. package/dist/fields/Group/index.css +1 -0
  54. package/dist/fields/Row/index.css +2 -0
  55. package/dist/fields/Tabs/index.css +1 -0
  56. package/dist/forms/RenderFields/index.css +1 -0
  57. package/dist/hooks/useControllableState.js +3 -3
  58. package/dist/hooks/useControllableState.js.map +1 -1
  59. package/dist/providers/DocumentInfo/index.d.ts.map +1 -1
  60. package/dist/providers/DocumentInfo/index.js +30 -19
  61. package/dist/providers/DocumentInfo/index.js.map +1 -1
  62. package/dist/providers/Locale/index.d.ts.map +1 -1
  63. package/dist/providers/Locale/index.js +6 -7
  64. package/dist/providers/Locale/index.js.map +1 -1
  65. package/dist/styles.css +5 -1
  66. package/dist/templates/Default/Wrapper/index.css +2 -0
  67. package/dist/templates/Default/index.css +1 -0
  68. package/dist/utilities/handleAuthRedirect.d.ts.map +1 -1
  69. package/dist/utilities/handleAuthRedirect.js +4 -1
  70. package/dist/utilities/handleAuthRedirect.js.map +1 -1
  71. package/dist/utilities/isPathMatchingRoute.d.ts.map +1 -1
  72. package/dist/utilities/isPathMatchingRoute.js +7 -5
  73. package/dist/utilities/isPathMatchingRoute.js.map +1 -1
  74. package/dist/views/API/index.css +1 -0
  75. package/dist/views/Dashboard/Default/ModularDashboard/index.css +2 -0
  76. package/dist/views/Edit/index.css +1 -0
  77. package/dist/views/HierarchyList/HierarchyTable/SlotTable.css +1 -0
  78. package/dist/views/HierarchyList/index.css +1 -0
  79. package/dist/views/List/ListHeader/index.css +1 -0
  80. package/dist/views/List/ListHeader/index.d.ts +0 -1
  81. package/dist/views/List/ListHeader/index.d.ts.map +1 -1
  82. package/dist/views/List/ListHeader/index.js +2 -6
  83. package/dist/views/List/ListHeader/index.js.map +1 -1
  84. package/dist/views/List/index.client.d.ts.map +1 -1
  85. package/dist/views/List/index.client.js +3 -2
  86. package/dist/views/List/index.client.js.map +1 -1
  87. package/dist/views/List/index.css +2 -0
  88. package/dist/views/Root/index.d.ts.map +1 -1
  89. package/dist/views/Root/index.js +26 -19
  90. package/dist/views/Root/index.js.map +1 -1
  91. package/dist/views/Version/Default/index.css +2 -0
  92. package/dist/views/Version/RenderFieldsToDiff/fields/Date/index.css +8 -0
  93. package/dist/views/Version/RenderFieldsToDiff/fields/Relationship/index.css +1 -0
  94. package/dist/views/Version/RenderFieldsToDiff/fields/Upload/index.css +1 -0
  95. package/dist/views/Version/RenderFieldsToDiff/index.css +2 -0
  96. package/dist/views/Version/Restore/index.d.ts.map +1 -1
  97. package/dist/views/Version/Restore/index.js +9 -6
  98. package/dist/views/Version/Restore/index.js.map +1 -1
  99. package/dist/views/Versions/VersionPillLabel/index.css +1 -0
  100. package/dist/views/Versions/index.css +1 -0
  101. package/dist/widgets/CollectionCards/index.css +4 -0
  102. package/package.json +5 -5
  103. package/dist/elements/ClipboardAction/clipboardUtilities.spec.js +0 -120
  104. package/dist/elements/ClipboardAction/clipboardUtilities.spec.js.map +0 -1
  105. package/dist/elements/ClipboardAction/isClipboardDataValid.spec.js +0 -144
  106. package/dist/elements/ClipboardAction/isClipboardDataValid.spec.js.map +0 -1
  107. package/dist/elements/ClipboardAction/mergeFormStateFromClipboard.spec.js +0 -885
  108. package/dist/elements/ClipboardAction/mergeFormStateFromClipboard.spec.js.map +0 -1
  109. package/dist/elements/ColumnSelection/matchesColumnSearch.spec.js +0 -87
  110. package/dist/elements/ColumnSelection/matchesColumnSearch.spec.js.map +0 -1
  111. package/dist/elements/CommandPalette/buildActions.spec.js +0 -158
  112. package/dist/elements/CommandPalette/buildActions.spec.js.map +0 -1
  113. package/dist/elements/CommandPalette/highlightLabel.spec.js +0 -78
  114. package/dist/elements/CommandPalette/highlightLabel.spec.js.map +0 -1
  115. package/dist/elements/FieldSelect/reduceFieldOptions.spec.js +0 -143
  116. package/dist/elements/FieldSelect/reduceFieldOptions.spec.js.map +0 -1
  117. package/dist/elements/Toasts/fieldErrors.spec.js +0 -46
  118. package/dist/elements/Toasts/fieldErrors.spec.js.map +0 -1
  119. package/dist/elements/WhereBuilder/Condition/Relationship/optionsReducer.spec.js +0 -152
  120. package/dist/elements/WhereBuilder/Condition/Relationship/optionsReducer.spec.js.map +0 -1
  121. package/dist/elements/WhereBuilder/conditionValue.spec.js +0 -65
  122. package/dist/elements/WhereBuilder/conditionValue.spec.js.map +0 -1
  123. package/dist/fields/Upload/Input.spec.js +0 -242
  124. package/dist/fields/Upload/Input.spec.js.map +0 -1
  125. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.d.ts +0 -2
  126. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.d.ts.map +0 -1
  127. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js +0 -67
  128. package/dist/forms/fieldSchemasToFormState/fieldSchemasToFormState.spec.js.map +0 -1
  129. package/dist/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.spec.js +0 -150
  130. package/dist/forms/fieldSchemasToFormState/serverFunctions/renderFieldServerFn.spec.js.map +0 -1
  131. package/dist/layouts/Root/index.spec.js +0 -20
  132. package/dist/layouts/Root/index.spec.js.map +0 -1
  133. package/dist/providers/Auth/authSessionRequests.spec.js +0 -121
  134. package/dist/providers/Auth/authSessionRequests.spec.js.map +0 -1
  135. package/dist/providers/Auth/sessionActivity.spec.js +0 -44
  136. package/dist/providers/Auth/sessionActivity.spec.js.map +0 -1
  137. package/dist/providers/Auth/tabSessionSync/index.spec.js +0 -463
  138. package/dist/providers/Auth/tabSessionSync/index.spec.js.map +0 -1
  139. package/dist/providers/Auth/useAuthSessionTimers.spec.js +0 -311
  140. package/dist/providers/Auth/useAuthSessionTimers.spec.js.map +0 -1
  141. package/dist/providers/RouteTransition/ProgressBar/index.spec.js +0 -44
  142. package/dist/providers/RouteTransition/ProgressBar/index.spec.js.map +0 -1
  143. package/dist/providers/TableColumns/buildColumnState/index.spec.js +0 -40
  144. package/dist/providers/TableColumns/buildColumnState/index.spec.js.map +0 -1
  145. package/dist/utilities/appendCacheTag.spec.js +0 -34
  146. package/dist/utilities/appendCacheTag.spec.js.map +0 -1
  147. package/dist/utilities/formatAbsoluteURL.spec.js +0 -27
  148. package/dist/utilities/formatAbsoluteURL.spec.js.map +0 -1
  149. package/dist/utilities/formatMetadata.spec.js +0 -83
  150. package/dist/utilities/formatMetadata.spec.js.map +0 -1
  151. package/dist/utilities/fuzzyMatch.spec.js +0 -38
  152. package/dist/utilities/fuzzyMatch.spec.js.map +0 -1
  153. package/dist/utilities/initReq.spec.js +0 -226
  154. package/dist/utilities/initReq.spec.js.map +0 -1
  155. package/dist/utilities/isAbsoluteURL.spec.js +0 -11
  156. package/dist/utilities/isAbsoluteURL.spec.js.map +0 -1
  157. package/dist/utilities/isCustomAdminView.spec.js +0 -90
  158. package/dist/utilities/isCustomAdminView.spec.js.map +0 -1
  159. package/dist/utilities/isHttpURL.spec.js +0 -25
  160. package/dist/utilities/isHttpURL.spec.js.map +0 -1
  161. package/dist/utilities/isPathMatchingRoute.spec.js +0 -178
  162. package/dist/utilities/isPathMatchingRoute.spec.js.map +0 -1
  163. package/dist/utilities/isPublicAdminRoute.spec.js +0 -34
  164. package/dist/utilities/isPublicAdminRoute.spec.js.map +0 -1
  165. package/dist/utilities/normalizeRelationshipValue.spec.js +0 -373
  166. package/dist/utilities/normalizeRelationshipValue.spec.js.map +0 -1
  167. package/dist/utilities/recentlyViewed.spec.js +0 -92
  168. package/dist/utilities/recentlyViewed.spec.js.map +0 -1
  169. package/dist/views/Root/getCustomCollectionViewByRoute.spec.js +0 -168
  170. package/dist/views/Root/getCustomCollectionViewByRoute.spec.js.map +0 -1
  171. package/dist/views/Version/RenderFieldsToDiff/buildVersionFields.spec.js +0 -258
  172. package/dist/views/Version/RenderFieldsToDiff/buildVersionFields.spec.js.map +0 -1
  173. package/dist/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.js +0 -915
  174. package/dist/views/Version/RenderFieldsToDiff/utilities/countChangedFields.spec.js.map +0 -1
  175. package/dist/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.js +0 -47
  176. package/dist/views/Version/RenderFieldsToDiff/utilities/fieldHasChanges.spec.js.map +0 -1
  177. package/dist/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.js +0 -125
  178. package/dist/views/Version/RenderFieldsToDiff/utilities/getFieldsForRowComparison.spec.js.map +0 -1
  179. package/dist/widgets/CollectionQuery/getCollectionFieldPaths.spec.js +0 -100
  180. package/dist/widgets/CollectionQuery/getCollectionFieldPaths.spec.js.map +0 -1
@@ -1,463 +0,0 @@
1
- // @vitest-environment jsdom
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { TAB_SESSION_EVENT_TYPES, createTabSessionSync } from './index.js';
4
- const tabSessionSyncCleanups = [];
5
- beforeEach(() => {
6
- resetMockBroadcastChannels();
7
- });
8
- afterEach(() => {
9
- for (const cleanup of tabSessionSyncCleanups.splice(0)) {
10
- cleanup();
11
- }
12
- vi.restoreAllMocks();
13
- vi.unstubAllGlobals();
14
- vi.clearAllMocks();
15
- });
16
- describe('createTabSessionSync', () => {
17
- it('should broadcast refreshed sessions with source-tab and timing metadata', () => {
18
- const session = createSession({
19
- expirationMs: 20_000,
20
- token: 'refreshed-token'
21
- });
22
- const tabSessionSync = createTestTabSessionSync({
23
- now: () => 123
24
- });
25
- tabSessionSync.broadcast({
26
- refreshStartedAt: 100,
27
- session,
28
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
29
- });
30
- expect(getBroadcastChannel().postMessage).toHaveBeenCalledWith({
31
- refreshStartedAt: 100,
32
- session,
33
- sourceTabID: 'local-tab',
34
- sentAt: 123,
35
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
36
- });
37
- });
38
- it('should apply a newer refresh when the provider shortens the token lifetime', () => {
39
- const onSessionRefreshed = vi.fn();
40
- const session = createSession({
41
- expirationMs: 30_000
42
- });
43
- createTestTabSessionSync({
44
- localExpirationMs: 40_000,
45
- onSessionRefreshed
46
- });
47
- const channel = getBroadcastChannel();
48
- channel.emit(createTabSessionMessage({
49
- sentAt: 100,
50
- session,
51
- sourceTabID: 'refresh-tab',
52
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
53
- }));
54
- expect(onSessionRefreshed).toHaveBeenCalledWith(session);
55
- });
56
- it('should ignore expiration events for older sessions', () => {
57
- const onSessionExpired = vi.fn();
58
- createTestTabSessionSync({
59
- localExpirationMs: 40_000,
60
- onSessionExpired
61
- });
62
- const channel = getBroadcastChannel();
63
- channel.emit(createTabSessionMessage({
64
- expiredTokenAt: 30_000,
65
- sourceTabID: 'stale-expiration-tab',
66
- type: TAB_SESSION_EVENT_TYPES.EXPIRED
67
- }));
68
- expect(onSessionExpired).not.toHaveBeenCalled();
69
- });
70
- it('should converge on logout when equal-time events arrive in opposite orders', () => {
71
- let firstState = 'initial';
72
- let secondState = 'initial';
73
- const refreshMessage = createTabSessionMessage({
74
- sentAt: 500,
75
- session: createSession({
76
- expirationMs: 30_000,
77
- token: 'refreshed-token'
78
- }),
79
- sourceTabID: 'refresh-tab',
80
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
81
- });
82
- const logoutMessage = createTabSessionMessage({
83
- sentAt: 500,
84
- sourceTabID: 'logout-tab',
85
- type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT
86
- });
87
- createTestTabSessionSync({
88
- onSessionLoggedOut: () => {
89
- firstState = 'logged-out';
90
- },
91
- onSessionRefreshed: () => {
92
- firstState = 'refreshed';
93
- },
94
- sourceTabID: 'first-local-tab'
95
- });
96
- const firstChannel = getBroadcastChannel();
97
- createTestTabSessionSync({
98
- onSessionLoggedOut: () => {
99
- secondState = 'logged-out';
100
- },
101
- onSessionRefreshed: () => {
102
- secondState = 'refreshed';
103
- },
104
- sourceTabID: 'second-local-tab'
105
- });
106
- const secondChannel = getBroadcastChannel();
107
- firstChannel.emit(refreshMessage);
108
- firstChannel.emit(logoutMessage);
109
- secondChannel.emit(logoutMessage);
110
- secondChannel.emit(refreshMessage);
111
- expect(firstState).toBe('logged-out');
112
- expect(secondState).toBe('logged-out');
113
- });
114
- it('should keep logout ahead of a refresh that started earlier and broadcast later', () => {
115
- const onSessionLoggedOut = vi.fn();
116
- const onSessionRefreshed = vi.fn();
117
- const refreshMessage = createTabSessionMessage({
118
- refreshStartedAt: 100,
119
- sentAt: 300,
120
- session: createSession({
121
- expirationMs: 30_000,
122
- token: 'late-refreshed-token'
123
- }),
124
- sourceTabID: 'refresh-tab',
125
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
126
- });
127
- const logoutMessage = createTabSessionMessage({
128
- sentAt: 200,
129
- sourceTabID: 'logout-tab',
130
- type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT
131
- });
132
- createTestTabSessionSync({
133
- onSessionLoggedOut,
134
- onSessionRefreshed,
135
- sourceTabID: 'receiving-tab'
136
- });
137
- const channel = getBroadcastChannel();
138
- channel.emit(logoutMessage);
139
- channel.emit(refreshMessage);
140
- expect(onSessionLoggedOut).toHaveBeenCalledOnce();
141
- expect(onSessionRefreshed).not.toHaveBeenCalled();
142
- });
143
- it('should apply refreshes in publication order instead of request-start ordering for refresh-vs-refresh', () => {
144
- let appliedSession;
145
- const onSessionRefreshed = vi.fn(session => {
146
- appliedSession = session;
147
- });
148
- const refreshB = createTabSessionMessage({
149
- refreshStartedAt: 200,
150
- sentAt: 100,
151
- session: createSession({
152
- expirationMs: 30_000,
153
- token: 'refresh-b'
154
- }),
155
- sourceTabID: 'refresh-b-tab',
156
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
157
- });
158
- const refreshA = createTabSessionMessage({
159
- refreshStartedAt: 100,
160
- sentAt: 200,
161
- session: createSession({
162
- expirationMs: 40_000,
163
- token: 'refresh-a'
164
- }),
165
- sourceTabID: 'refresh-a-tab',
166
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
167
- });
168
- createTestTabSessionSync({
169
- onSessionRefreshed,
170
- sourceTabID: 'receiving-tab'
171
- });
172
- const channel = getBroadcastChannel();
173
- channel.emit(refreshB);
174
- channel.emit(refreshA);
175
- expect(onSessionRefreshed).toHaveBeenCalledTimes(2);
176
- expect(onSessionRefreshed).toHaveBeenLastCalledWith(refreshA.session);
177
- expect(appliedSession).toBe(refreshA.session);
178
- });
179
- it('should ignore storage notifications while BroadcastChannel is healthy', async () => {
180
- const reconcileSession = vi.fn().mockResolvedValue({
181
- status: 'indeterminate'
182
- });
183
- createTestTabSessionSync({
184
- reconcileSession,
185
- sourceTabID: 'receiving-tab'
186
- });
187
- window.dispatchEvent(new StorageEvent('storage', {
188
- key: 'payload:auth-session:tab-sync',
189
- newValue: JSON.stringify({
190
- affectedExpirationMs: 30_000,
191
- refreshStartedAt: 100,
192
- sentAt: 200,
193
- sourceTabID: 'refreshing-tab',
194
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
195
- })
196
- }));
197
- await Promise.resolve();
198
- expect(reconcileSession).not.toHaveBeenCalled();
199
- });
200
- it('should ignore a late storage refresh whose request started before logout', () => {
201
- vi.stubGlobal('BroadcastChannel', undefined);
202
- const reconcileSession = vi.fn().mockResolvedValue({
203
- status: 'indeterminate'
204
- });
205
- const onSessionLoggedOut = vi.fn();
206
- createTestTabSessionSync({
207
- reconcileSession,
208
- onSessionLoggedOut,
209
- sourceTabID: 'receiving-tab'
210
- });
211
- window.dispatchEvent(new StorageEvent('storage', {
212
- key: 'payload:auth-session:tab-sync',
213
- newValue: JSON.stringify({
214
- affectedExpirationMs: 0,
215
- settlesSentAt: 200,
216
- sentAt: 201,
217
- sourceTabID: 'logout-tab',
218
- type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT
219
- })
220
- }));
221
- window.dispatchEvent(new StorageEvent('storage', {
222
- key: 'payload:auth-session:tab-sync',
223
- newValue: JSON.stringify({
224
- affectedExpirationMs: 30_000,
225
- refreshStartedAt: 100,
226
- sentAt: 300,
227
- sourceTabID: 'refresh-tab',
228
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
229
- })
230
- }));
231
- expect(onSessionLoggedOut).toHaveBeenCalledOnce();
232
- expect(reconcileSession).not.toHaveBeenCalled();
233
- });
234
- it('should keep storage fallback notification-only while reconciling refresh and settling logout', async () => {
235
- vi.stubGlobal('BroadcastChannel', undefined);
236
- const reconcileSession = vi.fn().mockResolvedValue({
237
- status: 'indeterminate'
238
- });
239
- const onSessionLoggedOut = vi.fn();
240
- createTestTabSessionSync({
241
- reconcileSession,
242
- onSessionLoggedOut,
243
- sourceTabID: 'receiving-tab'
244
- });
245
- const setItem = vi.spyOn(Storage.prototype, 'setItem');
246
- const broadcaster = createTestTabSessionSync({
247
- now: () => 123,
248
- sourceTabID: 'broadcasting-tab'
249
- });
250
- broadcaster.broadcast({
251
- refreshStartedAt: 100,
252
- session: createSession({
253
- expirationMs: 20_000,
254
- token: 'sensitive-token'
255
- }),
256
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
257
- });
258
- const [key, value] = setItem.mock.calls[0];
259
- expect(JSON.parse(value)).toEqual({
260
- affectedExpirationMs: 20_000,
261
- isBroadcastChannelFallback: true,
262
- refreshStartedAt: 100,
263
- type: TAB_SESSION_EVENT_TYPES.REFRESHED,
264
- sentAt: 123,
265
- sourceTabID: 'broadcasting-tab'
266
- });
267
- expect(value).not.toContain('sensitive-token');
268
- expect(value).not.toContain('user');
269
- window.dispatchEvent(new StorageEvent('storage', {
270
- key,
271
- newValue: value
272
- }));
273
- await Promise.resolve();
274
- expect(reconcileSession).toHaveBeenCalledOnce();
275
- reconcileSession.mockClear();
276
- const logoutPublication = broadcaster.broadcast({
277
- type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT
278
- });
279
- expect(setItem).toHaveBeenCalledOnce();
280
- expect(logoutPublication.type).toBe(TAB_SESSION_EVENT_TYPES.LOGGED_OUT);
281
- if (logoutPublication.type !== TAB_SESSION_EVENT_TYPES.LOGGED_OUT) {
282
- throw new Error('Expected a logged-out publication.');
283
- }
284
- broadcaster.broadcastLogoutSettlement(logoutPublication);
285
- const [logoutKey, logoutValue] = setItem.mock.calls[1];
286
- expect(JSON.parse(logoutValue)).toEqual({
287
- affectedExpirationMs: 0,
288
- isBroadcastChannelFallback: true,
289
- settlesSentAt: 124,
290
- sentAt: 125,
291
- sourceTabID: 'broadcasting-tab',
292
- type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT
293
- });
294
- expect(logoutValue).not.toContain('sensitive-token');
295
- expect(logoutValue).not.toContain('user');
296
- window.dispatchEvent(new StorageEvent('storage', {
297
- key: logoutKey,
298
- newValue: logoutValue
299
- }));
300
- expect(onSessionLoggedOut).toHaveBeenCalledOnce();
301
- expect(reconcileSession).not.toHaveBeenCalled();
302
- await Promise.resolve();
303
- expect(reconcileSession).not.toHaveBeenCalled();
304
- });
305
- it('should downgrade a failed channel and reconcile through storage', async () => {
306
- const reconcileSession = vi.fn().mockResolvedValue({
307
- status: 'indeterminate'
308
- });
309
- createTestTabSessionSync({
310
- reconcileSession,
311
- sourceTabID: 'storage-peer'
312
- });
313
- const addEventListener = vi.spyOn(window, 'addEventListener');
314
- const setItem = vi.spyOn(Storage.prototype, 'setItem');
315
- const broadcaster = createTestTabSessionSync({
316
- sourceTabID: 'channel-broadcaster'
317
- });
318
- const failedChannel = getBroadcastChannel();
319
- failedChannel.postMessage.mockImplementationOnce(() => {
320
- throw new Error('channel closed');
321
- });
322
- broadcaster.broadcast({
323
- refreshStartedAt: 100,
324
- session: createSession({
325
- expirationMs: 20_000
326
- }),
327
- type: TAB_SESSION_EVENT_TYPES.REFRESHED
328
- });
329
- expect(failedChannel.close).toHaveBeenCalledOnce();
330
- expect(addEventListener).toHaveBeenCalledWith('storage', expect.any(Function));
331
- expect(setItem).toHaveBeenCalledOnce();
332
- const [key, newValue] = setItem.mock.calls[0];
333
- window.dispatchEvent(new StorageEvent('storage', {
334
- key,
335
- newValue
336
- }));
337
- await Promise.resolve();
338
- expect(reconcileSession).toHaveBeenCalledOnce();
339
- });
340
- it('should ignore a pending storage reconciliation after cleanup', async () => {
341
- vi.stubGlobal('BroadcastChannel', undefined);
342
- let resolveReconciliation;
343
- const reconcileSession = vi.fn(() => new Promise(resolve => {
344
- resolveReconciliation = resolve;
345
- }));
346
- const onTabSessionUnauthenticated = vi.fn();
347
- const tabSessionSync = createTestTabSessionSync({
348
- reconcileSession,
349
- onTabSessionUnauthenticated
350
- });
351
- window.dispatchEvent(new StorageEvent('storage', {
352
- key: 'payload:auth-session:tab-sync',
353
- newValue: JSON.stringify({
354
- affectedExpirationMs: 40_000,
355
- refreshStartedAt: 400,
356
- type: TAB_SESSION_EVENT_TYPES.REFRESHED,
357
- sentAt: 500,
358
- sourceTabID: 'remote-tab'
359
- })
360
- }));
361
- tabSessionSync.cleanup();
362
- resolveReconciliation?.({
363
- status: 'unauthenticated'
364
- });
365
- await Promise.resolve();
366
- expect(onTabSessionUnauthenticated).not.toHaveBeenCalled();
367
- });
368
- });
369
- function createTestTabSessionSync({
370
- reconcileSession = vi.fn().mockResolvedValue({
371
- status: 'indeterminate'
372
- }),
373
- localExpirationMs,
374
- now,
375
- onSessionExpired = vi.fn(),
376
- onSessionLoggedOut = vi.fn(),
377
- onSessionRefreshed = vi.fn(),
378
- onTabSessionUnauthenticated = vi.fn(),
379
- sourceTabID = 'local-tab'
380
- } = {}) {
381
- const tabSessionSync = createTabSessionSync({
382
- reconcileSession,
383
- getTokenExpirationMs: () => localExpirationMs,
384
- now,
385
- onSessionExpired,
386
- onSessionLoggedOut,
387
- onSessionRefreshed,
388
- onTabSessionUnauthenticated,
389
- sourceTabID
390
- });
391
- tabSessionSyncCleanups.push(tabSessionSync.cleanup);
392
- return tabSessionSync;
393
- }
394
- class MockBroadcastChannel {
395
- static instances = [];
396
- listeners = new Set();
397
- addEventListener = vi.fn((_type, listener) => {
398
- this.listeners.add(listener);
399
- });
400
- close = vi.fn();
401
- postMessage = vi.fn();
402
- removeEventListener = vi.fn((_type, listener) => {
403
- this.listeners.delete(listener);
404
- });
405
- emit(message) {
406
- for (const listener of this.listeners) {
407
- listener(new MessageEvent('message', {
408
- data: message
409
- }));
410
- }
411
- }
412
- }
413
- function createTabSessionMessage(message) {
414
- const {
415
- sentAt = 100,
416
- ...messageWithoutTimestamp
417
- } = message;
418
- if (messageWithoutTimestamp.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {
419
- const {
420
- refreshStartedAt = sentAt,
421
- ...refreshedMessage
422
- } = messageWithoutTimestamp;
423
- return {
424
- ...refreshedMessage,
425
- refreshStartedAt,
426
- sentAt
427
- };
428
- }
429
- return {
430
- ...messageWithoutTimestamp,
431
- sentAt
432
- };
433
- }
434
- function createSession({
435
- expirationMs,
436
- token = 'token'
437
- }) {
438
- return {
439
- exp: expirationMs / 1000,
440
- token,
441
- user: {
442
- id: '1',
443
- collection: 'users'
444
- }
445
- };
446
- }
447
- function getBroadcastChannel() {
448
- const channel = MockBroadcastChannel.instances.at(-1);
449
- if (!channel) {
450
- throw new Error('Expected a BroadcastChannel instance');
451
- }
452
- return channel;
453
- }
454
- function resetMockBroadcastChannels() {
455
- MockBroadcastChannel.instances.length = 0;
456
- vi.stubGlobal('BroadcastChannel', class extends MockBroadcastChannel {
457
- constructor() {
458
- super();
459
- MockBroadcastChannel.instances.push(this);
460
- }
461
- });
462
- }
463
- //# sourceMappingURL=index.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.spec.js","names":["afterEach","beforeEach","describe","expect","it","vi","TAB_SESSION_EVENT_TYPES","createTabSessionSync","tabSessionSyncCleanups","resetMockBroadcastChannels","cleanup","splice","restoreAllMocks","unstubAllGlobals","clearAllMocks","session","createSession","expirationMs","token","tabSessionSync","createTestTabSessionSync","now","broadcast","refreshStartedAt","type","REFRESHED","getBroadcastChannel","postMessage","toHaveBeenCalledWith","sourceTabID","sentAt","onSessionRefreshed","fn","localExpirationMs","channel","emit","createTabSessionMessage","onSessionExpired","expiredTokenAt","EXPIRED","not","toHaveBeenCalled","firstState","secondState","refreshMessage","logoutMessage","LOGGED_OUT","onSessionLoggedOut","firstChannel","secondChannel","toBe","toHaveBeenCalledOnce","appliedSession","refreshB","refreshA","toHaveBeenCalledTimes","toHaveBeenLastCalledWith","reconcileSession","mockResolvedValue","status","window","dispatchEvent","StorageEvent","key","newValue","JSON","stringify","affectedExpirationMs","Promise","resolve","stubGlobal","undefined","settlesSentAt","setItem","spyOn","Storage","prototype","broadcaster","value","mock","calls","parse","toEqual","isBroadcastChannelFallback","toContain","mockClear","logoutPublication","Error","broadcastLogoutSettlement","logoutKey","logoutValue","addEventListener","failedChannel","mockImplementationOnce","close","any","Function","resolveReconciliation","onTabSessionUnauthenticated","getTokenExpirationMs","push","MockBroadcastChannel","instances","listeners","Set","_type","listener","add","removeEventListener","delete","message","MessageEvent","data","messageWithoutTimestamp","refreshedMessage","exp","user","id","collection","at","length","constructor"],"sources":["../../../../src/providers/Auth/tabSessionSync/index.spec.ts"],"sourcesContent":["// @vitest-environment jsdom\nimport { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'\n\nimport type { UserWithToken } from '../types.js'\nimport type { TabSessionMessage, TabSessionReconciliationResult } from './index.js'\n\nimport { TAB_SESSION_EVENT_TYPES, createTabSessionSync } from './index.js'\n\nconst tabSessionSyncCleanups: Array<() => void> = []\n\nbeforeEach(() => {\n resetMockBroadcastChannels()\n})\n\nafterEach(() => {\n for (const cleanup of tabSessionSyncCleanups.splice(0)) {\n cleanup()\n }\n\n vi.restoreAllMocks()\n vi.unstubAllGlobals()\n vi.clearAllMocks()\n})\n\ndescribe('createTabSessionSync', () => {\n it('should broadcast refreshed sessions with source-tab and timing metadata', () => {\n const session = createSession({ expirationMs: 20_000, token: 'refreshed-token' })\n const tabSessionSync = createTestTabSessionSync({ now: () => 123 })\n\n tabSessionSync.broadcast({\n refreshStartedAt: 100,\n session,\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n\n expect(getBroadcastChannel().postMessage).toHaveBeenCalledWith({\n refreshStartedAt: 100,\n session,\n sourceTabID: 'local-tab',\n sentAt: 123,\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n })\n\n it('should apply a newer refresh when the provider shortens the token lifetime', () => {\n const onSessionRefreshed = vi.fn()\n const session = createSession({ expirationMs: 30_000 })\n\n createTestTabSessionSync({\n localExpirationMs: 40_000,\n onSessionRefreshed,\n })\n const channel = getBroadcastChannel()\n\n channel.emit(\n createTabSessionMessage({\n sentAt: 100,\n session,\n sourceTabID: 'refresh-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n }),\n )\n\n expect(onSessionRefreshed).toHaveBeenCalledWith(session)\n })\n\n it('should ignore expiration events for older sessions', () => {\n const onSessionExpired = vi.fn()\n\n createTestTabSessionSync({\n localExpirationMs: 40_000,\n onSessionExpired,\n })\n const channel = getBroadcastChannel()\n\n channel.emit(\n createTabSessionMessage({\n expiredTokenAt: 30_000,\n sourceTabID: 'stale-expiration-tab',\n type: TAB_SESSION_EVENT_TYPES.EXPIRED,\n }),\n )\n\n expect(onSessionExpired).not.toHaveBeenCalled()\n })\n\n it('should converge on logout when equal-time events arrive in opposite orders', () => {\n let firstState = 'initial'\n let secondState = 'initial'\n const refreshMessage = createTabSessionMessage({\n sentAt: 500,\n session: createSession({ expirationMs: 30_000, token: 'refreshed-token' }),\n sourceTabID: 'refresh-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n const logoutMessage = createTabSessionMessage({\n sentAt: 500,\n sourceTabID: 'logout-tab',\n type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT,\n })\n\n createTestTabSessionSync({\n onSessionLoggedOut: () => {\n firstState = 'logged-out'\n },\n onSessionRefreshed: () => {\n firstState = 'refreshed'\n },\n sourceTabID: 'first-local-tab',\n })\n const firstChannel = getBroadcastChannel()\n createTestTabSessionSync({\n onSessionLoggedOut: () => {\n secondState = 'logged-out'\n },\n onSessionRefreshed: () => {\n secondState = 'refreshed'\n },\n sourceTabID: 'second-local-tab',\n })\n const secondChannel = getBroadcastChannel()\n\n firstChannel.emit(refreshMessage)\n firstChannel.emit(logoutMessage)\n secondChannel.emit(logoutMessage)\n secondChannel.emit(refreshMessage)\n\n expect(firstState).toBe('logged-out')\n expect(secondState).toBe('logged-out')\n })\n\n it('should keep logout ahead of a refresh that started earlier and broadcast later', () => {\n const onSessionLoggedOut = vi.fn()\n const onSessionRefreshed = vi.fn()\n const refreshMessage = createTabSessionMessage({\n refreshStartedAt: 100,\n sentAt: 300,\n session: createSession({ expirationMs: 30_000, token: 'late-refreshed-token' }),\n sourceTabID: 'refresh-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n const logoutMessage = createTabSessionMessage({\n sentAt: 200,\n sourceTabID: 'logout-tab',\n type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT,\n })\n\n createTestTabSessionSync({\n onSessionLoggedOut,\n onSessionRefreshed,\n sourceTabID: 'receiving-tab',\n })\n const channel = getBroadcastChannel()\n\n channel.emit(logoutMessage)\n channel.emit(refreshMessage)\n\n expect(onSessionLoggedOut).toHaveBeenCalledOnce()\n expect(onSessionRefreshed).not.toHaveBeenCalled()\n })\n\n it('should apply refreshes in publication order instead of request-start ordering for refresh-vs-refresh', () => {\n let appliedSession: UserWithToken | undefined\n const onSessionRefreshed = vi.fn((session: UserWithToken) => {\n appliedSession = session\n })\n const refreshB = createTabSessionMessage({\n refreshStartedAt: 200,\n sentAt: 100,\n session: createSession({ expirationMs: 30_000, token: 'refresh-b' }),\n sourceTabID: 'refresh-b-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n const refreshA = createTabSessionMessage({\n refreshStartedAt: 100,\n sentAt: 200,\n session: createSession({ expirationMs: 40_000, token: 'refresh-a' }),\n sourceTabID: 'refresh-a-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n\n createTestTabSessionSync({ onSessionRefreshed, sourceTabID: 'receiving-tab' })\n const channel = getBroadcastChannel()\n\n channel.emit(refreshB)\n channel.emit(refreshA)\n\n expect(onSessionRefreshed).toHaveBeenCalledTimes(2)\n expect(onSessionRefreshed).toHaveBeenLastCalledWith(refreshA.session)\n expect(appliedSession).toBe(refreshA.session)\n })\n\n it('should ignore storage notifications while BroadcastChannel is healthy', async () => {\n const reconcileSession = vi.fn().mockResolvedValue({ status: 'indeterminate' } as const)\n\n createTestTabSessionSync({ reconcileSession, sourceTabID: 'receiving-tab' })\n\n window.dispatchEvent(\n new StorageEvent('storage', {\n key: 'payload:auth-session:tab-sync',\n newValue: JSON.stringify({\n affectedExpirationMs: 30_000,\n refreshStartedAt: 100,\n sentAt: 200,\n sourceTabID: 'refreshing-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n }),\n }),\n )\n await Promise.resolve()\n\n expect(reconcileSession).not.toHaveBeenCalled()\n })\n\n it('should ignore a late storage refresh whose request started before logout', () => {\n vi.stubGlobal('BroadcastChannel', undefined)\n const reconcileSession = vi.fn().mockResolvedValue({ status: 'indeterminate' } as const)\n const onSessionLoggedOut = vi.fn()\n\n createTestTabSessionSync({\n reconcileSession,\n onSessionLoggedOut,\n sourceTabID: 'receiving-tab',\n })\n\n window.dispatchEvent(\n new StorageEvent('storage', {\n key: 'payload:auth-session:tab-sync',\n newValue: JSON.stringify({\n affectedExpirationMs: 0,\n settlesSentAt: 200,\n sentAt: 201,\n sourceTabID: 'logout-tab',\n type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT,\n }),\n }),\n )\n window.dispatchEvent(\n new StorageEvent('storage', {\n key: 'payload:auth-session:tab-sync',\n newValue: JSON.stringify({\n affectedExpirationMs: 30_000,\n refreshStartedAt: 100,\n sentAt: 300,\n sourceTabID: 'refresh-tab',\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n }),\n }),\n )\n\n expect(onSessionLoggedOut).toHaveBeenCalledOnce()\n expect(reconcileSession).not.toHaveBeenCalled()\n })\n\n it('should keep storage fallback notification-only while reconciling refresh and settling logout', async () => {\n vi.stubGlobal('BroadcastChannel', undefined)\n const reconcileSession = vi.fn().mockResolvedValue({ status: 'indeterminate' })\n const onSessionLoggedOut = vi.fn()\n\n createTestTabSessionSync({\n reconcileSession,\n onSessionLoggedOut,\n sourceTabID: 'receiving-tab',\n })\n const setItem = vi.spyOn(Storage.prototype, 'setItem')\n const broadcaster = createTestTabSessionSync({\n now: () => 123,\n sourceTabID: 'broadcasting-tab',\n })\n\n broadcaster.broadcast({\n refreshStartedAt: 100,\n session: createSession({ expirationMs: 20_000, token: 'sensitive-token' }),\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n const [key, value] = setItem.mock.calls[0] as [string, string]\n\n expect(JSON.parse(value)).toEqual({\n affectedExpirationMs: 20_000,\n isBroadcastChannelFallback: true,\n refreshStartedAt: 100,\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n sentAt: 123,\n sourceTabID: 'broadcasting-tab',\n })\n expect(value).not.toContain('sensitive-token')\n expect(value).not.toContain('user')\n\n window.dispatchEvent(new StorageEvent('storage', { key, newValue: value }))\n await Promise.resolve()\n\n expect(reconcileSession).toHaveBeenCalledOnce()\n\n reconcileSession.mockClear()\n\n const logoutPublication = broadcaster.broadcast({\n type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT,\n })\n\n expect(setItem).toHaveBeenCalledOnce()\n expect(logoutPublication.type).toBe(TAB_SESSION_EVENT_TYPES.LOGGED_OUT)\n\n if (logoutPublication.type !== TAB_SESSION_EVENT_TYPES.LOGGED_OUT) {\n throw new Error('Expected a logged-out publication.')\n }\n\n broadcaster.broadcastLogoutSettlement(logoutPublication)\n\n const [logoutKey, logoutValue] = setItem.mock.calls[1] as [string, string]\n\n expect(JSON.parse(logoutValue)).toEqual({\n affectedExpirationMs: 0,\n isBroadcastChannelFallback: true,\n settlesSentAt: 124,\n sentAt: 125,\n sourceTabID: 'broadcasting-tab',\n type: TAB_SESSION_EVENT_TYPES.LOGGED_OUT,\n })\n expect(logoutValue).not.toContain('sensitive-token')\n expect(logoutValue).not.toContain('user')\n\n window.dispatchEvent(new StorageEvent('storage', { key: logoutKey, newValue: logoutValue }))\n\n expect(onSessionLoggedOut).toHaveBeenCalledOnce()\n expect(reconcileSession).not.toHaveBeenCalled()\n\n await Promise.resolve()\n\n expect(reconcileSession).not.toHaveBeenCalled()\n })\n\n it('should downgrade a failed channel and reconcile through storage', async () => {\n const reconcileSession = vi.fn().mockResolvedValue({ status: 'indeterminate' })\n\n createTestTabSessionSync({ reconcileSession, sourceTabID: 'storage-peer' })\n const addEventListener = vi.spyOn(window, 'addEventListener')\n const setItem = vi.spyOn(Storage.prototype, 'setItem')\n const broadcaster = createTestTabSessionSync({ sourceTabID: 'channel-broadcaster' })\n const failedChannel = getBroadcastChannel()\n\n failedChannel.postMessage.mockImplementationOnce(() => {\n throw new Error('channel closed')\n })\n broadcaster.broadcast({\n refreshStartedAt: 100,\n session: createSession({ expirationMs: 20_000 }),\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n })\n\n expect(failedChannel.close).toHaveBeenCalledOnce()\n expect(addEventListener).toHaveBeenCalledWith('storage', expect.any(Function))\n expect(setItem).toHaveBeenCalledOnce()\n\n const [key, newValue] = setItem.mock.calls[0] as [string, string]\n\n window.dispatchEvent(new StorageEvent('storage', { key, newValue }))\n await Promise.resolve()\n\n expect(reconcileSession).toHaveBeenCalledOnce()\n })\n\n it('should ignore a pending storage reconciliation after cleanup', async () => {\n vi.stubGlobal('BroadcastChannel', undefined)\n let resolveReconciliation: ((result: TabSessionReconciliationResult) => void) | undefined\n const reconcileSession = vi.fn(\n () =>\n new Promise<TabSessionReconciliationResult>((resolve) => {\n resolveReconciliation = resolve\n }),\n )\n const onTabSessionUnauthenticated = vi.fn()\n const tabSessionSync = createTestTabSessionSync({\n reconcileSession,\n onTabSessionUnauthenticated,\n })\n\n window.dispatchEvent(\n new StorageEvent('storage', {\n key: 'payload:auth-session:tab-sync',\n newValue: JSON.stringify({\n affectedExpirationMs: 40_000,\n refreshStartedAt: 400,\n type: TAB_SESSION_EVENT_TYPES.REFRESHED,\n sentAt: 500,\n sourceTabID: 'remote-tab',\n }),\n }),\n )\n tabSessionSync.cleanup()\n resolveReconciliation?.({ status: 'unauthenticated' })\n await Promise.resolve()\n\n expect(onTabSessionUnauthenticated).not.toHaveBeenCalled()\n })\n})\n\nfunction createTestTabSessionSync({\n reconcileSession = vi.fn().mockResolvedValue({ status: 'indeterminate' } as const),\n localExpirationMs,\n now,\n onSessionExpired = vi.fn(),\n onSessionLoggedOut = vi.fn(),\n onSessionRefreshed = vi.fn(),\n onTabSessionUnauthenticated = vi.fn(),\n sourceTabID = 'local-tab',\n}: {\n reconcileSession?: () => Promise<TabSessionReconciliationResult>\n localExpirationMs?: number\n now?: () => number\n onSessionExpired?: (expiredTokenAt: number) => void\n onSessionLoggedOut?: () => void\n onSessionRefreshed?: (session: UserWithToken) => void\n onTabSessionUnauthenticated?: () => void\n sourceTabID?: string\n} = {}) {\n const tabSessionSync = createTabSessionSync({\n reconcileSession,\n getTokenExpirationMs: () => localExpirationMs,\n now,\n onSessionExpired,\n onSessionLoggedOut,\n onSessionRefreshed,\n onTabSessionUnauthenticated,\n sourceTabID,\n })\n\n tabSessionSyncCleanups.push(tabSessionSync.cleanup)\n\n return tabSessionSync\n}\n\nclass MockBroadcastChannel {\n static instances: MockBroadcastChannel[] = []\n\n listeners = new Set<(event: MessageEvent<TabSessionMessage>) => void>()\n addEventListener = vi.fn(\n (_type: string, listener: (event: MessageEvent<TabSessionMessage>) => void) => {\n this.listeners.add(listener)\n },\n )\n close = vi.fn()\n postMessage = vi.fn()\n removeEventListener = vi.fn(\n (_type: string, listener: (event: MessageEvent<TabSessionMessage>) => void) => {\n this.listeners.delete(listener)\n },\n )\n\n emit(message: TabSessionMessage): void {\n for (const listener of this.listeners) {\n listener(new MessageEvent('message', { data: message }))\n }\n }\n}\n\nfunction createTabSessionMessage(\n message:\n | ({\n sentAt?: number\n } & Omit<\n Extract<TabSessionMessage, { type: typeof TAB_SESSION_EVENT_TYPES.EXPIRED }>,\n 'sentAt'\n >)\n | ({\n sentAt?: number\n } & Omit<\n Extract<TabSessionMessage, { type: typeof TAB_SESSION_EVENT_TYPES.LOGGED_OUT }>,\n 'sentAt'\n >)\n | ({\n refreshStartedAt?: number\n sentAt?: number\n } & Omit<\n Extract<TabSessionMessage, { type: typeof TAB_SESSION_EVENT_TYPES.REFRESHED }>,\n 'refreshStartedAt' | 'sentAt'\n >),\n): TabSessionMessage {\n const { sentAt = 100, ...messageWithoutTimestamp } = message\n\n if (messageWithoutTimestamp.type === TAB_SESSION_EVENT_TYPES.REFRESHED) {\n const { refreshStartedAt = sentAt, ...refreshedMessage } = messageWithoutTimestamp\n\n return { ...refreshedMessage, refreshStartedAt, sentAt }\n }\n\n return { ...messageWithoutTimestamp, sentAt } as TabSessionMessage\n}\n\nfunction createSession({\n expirationMs,\n token = 'token',\n}: {\n expirationMs: number\n token?: string\n}): UserWithToken {\n return {\n exp: expirationMs / 1000,\n token,\n user: { id: '1', collection: 'users' },\n }\n}\n\nfunction getBroadcastChannel(): MockBroadcastChannel {\n const channel = MockBroadcastChannel.instances.at(-1)\n\n if (!channel) {\n throw new Error('Expected a BroadcastChannel instance')\n }\n\n return channel\n}\n\nfunction resetMockBroadcastChannels(): void {\n MockBroadcastChannel.instances.length = 0\n vi.stubGlobal(\n 'BroadcastChannel',\n class extends MockBroadcastChannel {\n constructor() {\n super()\n MockBroadcastChannel.instances.push(this)\n }\n },\n )\n}\n"],"mappings":"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","ignoreList":[]}