@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,119 @@
1
+ /**
2
+ * Coordinates requests that read or update the current auth session.
3
+ *
4
+ * Requests run in order, concurrent refreshes and logouts share a promise, and outdated results can
5
+ * be discarded after the session changes.
6
+ */export function createAuthSessionRequests() {
7
+ let authRequestQueue = Promise.resolve();
8
+ let authRequestSequence = 0;
9
+ let isLoggingOut = false;
10
+ let logoutRequest;
11
+ let pendingAuthInvalidation;
12
+ let refreshRequest;
13
+ let sessionGeneration = 0;
14
+ const clearPendingInvalidation = () => {
15
+ pendingAuthInvalidation = undefined;
16
+ };
17
+ const discardPendingResults = () => {
18
+ sessionGeneration += 1;
19
+ clearPendingInvalidation();
20
+ };
21
+ const queue = request => {
22
+ const requestGeneration = sessionGeneration;
23
+ const requestSequence = ++authRequestSequence;
24
+ const runRequest = async () => {
25
+ const isResultStale = () => sessionGeneration !== requestGeneration || isLoggingOut;
26
+ const result = await request({
27
+ acceptResult: () => {
28
+ if (isResultStale()) {
29
+ return false;
30
+ }
31
+ clearPendingInvalidation();
32
+ return true;
33
+ },
34
+ invalidateWhenIdle: invalidate => {
35
+ if (isResultStale()) {
36
+ return;
37
+ }
38
+ if (requestSequence < authRequestSequence) {
39
+ pendingAuthInvalidation = {
40
+ generation: requestGeneration,
41
+ run: invalidate
42
+ };
43
+ } else {
44
+ invalidate();
45
+ }
46
+ },
47
+ isResultStale
48
+ });
49
+ if (requestSequence === authRequestSequence) {
50
+ const pendingInvalidation = pendingAuthInvalidation;
51
+ clearPendingInvalidation();
52
+ if (pendingInvalidation?.generation === sessionGeneration) {
53
+ pendingInvalidation.run();
54
+ }
55
+ }
56
+ return result;
57
+ };
58
+ const queuedRequest = authRequestQueue.then(runRequest, runRequest);
59
+ authRequestQueue = queuedRequest.then(() => undefined, () => undefined);
60
+ return queuedRequest;
61
+ };
62
+ const refresh = request => {
63
+ const requestGeneration = sessionGeneration;
64
+ const activeRequest = refreshRequest;
65
+ if (isLoggingOut) {
66
+ return Promise.resolve(null);
67
+ }
68
+ if (activeRequest?.generation === requestGeneration) {
69
+ return activeRequest.promise;
70
+ }
71
+ const refreshPromise = queue(request);
72
+ refreshRequest = {
73
+ generation: requestGeneration,
74
+ promise: refreshPromise
75
+ };
76
+ /** Stops sharing this refresh after it settles without clearing a newer refresh request. */
77
+ const clearRefreshRequest = () => {
78
+ if (refreshRequest?.promise === refreshPromise) {
79
+ refreshRequest = undefined;
80
+ }
81
+ };
82
+ void refreshPromise.then(clearRefreshRequest, clearRefreshRequest);
83
+ return refreshPromise;
84
+ };
85
+ const logOut = ({
86
+ clearSession,
87
+ request
88
+ }) => {
89
+ if (logoutRequest !== undefined) {
90
+ return logoutRequest;
91
+ }
92
+ isLoggingOut = true;
93
+ clearSession();
94
+ const pendingLogout = queue(async () => {
95
+ try {
96
+ await request();
97
+ } finally {
98
+ isLoggingOut = false;
99
+ }
100
+ });
101
+ logoutRequest = pendingLogout;
102
+ /** Stops sharing this logout after it settles without clearing a newer logout request. */
103
+ const clearLogoutRequest = () => {
104
+ if (logoutRequest === pendingLogout) {
105
+ logoutRequest = undefined;
106
+ }
107
+ };
108
+ void pendingLogout.then(clearLogoutRequest, clearLogoutRequest);
109
+ return pendingLogout;
110
+ };
111
+ return {
112
+ discardPendingResults,
113
+ isLoggingOut: () => isLoggingOut,
114
+ logOut,
115
+ queue,
116
+ refresh
117
+ };
118
+ }
119
+ //# sourceMappingURL=authSessionRequests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authSessionRequests.js","names":["createAuthSessionRequests","authRequestQueue","Promise","resolve","authRequestSequence","isLoggingOut","logoutRequest","pendingAuthInvalidation","refreshRequest","sessionGeneration","clearPendingInvalidation","undefined","discardPendingResults","queue","request","requestGeneration","requestSequence","runRequest","isResultStale","result","acceptResult","invalidateWhenIdle","invalidate","generation","run","pendingInvalidation","queuedRequest","then","refresh","activeRequest","promise","refreshPromise","clearRefreshRequest","logOut","clearSession","pendingLogout","clearLogoutRequest"],"sources":["../../../src/providers/Auth/authSessionRequests.ts"],"sourcesContent":["import type { AuthenticatedUser } from 'payload'\n\nexport type AuthRequestContext = {\n /** Accepts the result when its session is still active and cancels any deferred invalidation. */\n acceptResult: () => boolean\n /** Invalidates the session after newer queued auth requests have had a chance to restore it. */\n invalidateWhenIdle: (invalidate: () => void) => void\n /** Whether the session changed or logout began after this request was queued. */\n isResultStale: () => boolean\n}\n\nexport type AuthSessionRequests = {\n discardPendingResults: () => void\n isLoggingOut: () => boolean\n logOut: ({\n clearSession,\n request,\n }: {\n clearSession: () => void\n request: () => Promise<void>\n }) => Promise<void>\n queue: <Result>(request: (context: AuthRequestContext) => Promise<Result>) => Promise<Result>\n refresh: (\n request: (context: AuthRequestContext) => Promise<AuthenticatedUser | null>,\n ) => Promise<AuthenticatedUser | null>\n}\n\n/**\n * Coordinates requests that read or update the current auth session.\n *\n * Requests run in order, concurrent refreshes and logouts share a promise, and outdated results can\n * be discarded after the session changes.\n */\nexport function createAuthSessionRequests(): AuthSessionRequests {\n let authRequestQueue = Promise.resolve()\n let authRequestSequence = 0\n let isLoggingOut = false\n let logoutRequest: Promise<void> | undefined\n let pendingAuthInvalidation:\n | {\n generation: number\n run: () => void\n }\n | undefined\n let refreshRequest:\n | {\n generation: number\n promise: Promise<AuthenticatedUser | null>\n }\n | undefined\n let sessionGeneration = 0\n\n const clearPendingInvalidation = (): void => {\n pendingAuthInvalidation = undefined\n }\n\n const discardPendingResults = (): void => {\n sessionGeneration += 1\n clearPendingInvalidation()\n }\n\n const queue = <Result>(\n request: (context: AuthRequestContext) => Promise<Result>,\n ): Promise<Result> => {\n const requestGeneration = sessionGeneration\n const requestSequence = ++authRequestSequence\n const runRequest = async (): Promise<Result> => {\n const isResultStale = () => sessionGeneration !== requestGeneration || isLoggingOut\n const result = await request({\n acceptResult: () => {\n if (isResultStale()) {\n return false\n }\n\n clearPendingInvalidation()\n return true\n },\n invalidateWhenIdle: (invalidate) => {\n if (isResultStale()) {\n return\n }\n\n if (requestSequence < authRequestSequence) {\n pendingAuthInvalidation = { generation: requestGeneration, run: invalidate }\n } else {\n invalidate()\n }\n },\n isResultStale,\n })\n\n if (requestSequence === authRequestSequence) {\n const pendingInvalidation = pendingAuthInvalidation\n\n clearPendingInvalidation()\n\n if (pendingInvalidation?.generation === sessionGeneration) {\n pendingInvalidation.run()\n }\n }\n\n return result\n }\n const queuedRequest = authRequestQueue.then(runRequest, runRequest)\n\n authRequestQueue = queuedRequest.then(\n () => undefined,\n () => undefined,\n )\n\n return queuedRequest\n }\n\n const refresh = (\n request: (context: AuthRequestContext) => Promise<AuthenticatedUser | null>,\n ): Promise<AuthenticatedUser | null> => {\n const requestGeneration = sessionGeneration\n const activeRequest = refreshRequest\n\n if (isLoggingOut) {\n return Promise.resolve(null)\n }\n\n if (activeRequest?.generation === requestGeneration) {\n return activeRequest.promise\n }\n\n const refreshPromise = queue(request)\n\n refreshRequest = { generation: requestGeneration, promise: refreshPromise }\n /** Stops sharing this refresh after it settles without clearing a newer refresh request. */\n const clearRefreshRequest = () => {\n if (refreshRequest?.promise === refreshPromise) {\n refreshRequest = undefined\n }\n }\n\n void refreshPromise.then(clearRefreshRequest, clearRefreshRequest)\n\n return refreshPromise\n }\n\n const logOut = ({\n clearSession,\n request,\n }: {\n clearSession: () => void\n request: () => Promise<void>\n }): Promise<void> => {\n if (logoutRequest !== undefined) {\n return logoutRequest\n }\n\n isLoggingOut = true\n clearSession()\n\n const pendingLogout = queue(async () => {\n try {\n await request()\n } finally {\n isLoggingOut = false\n }\n })\n\n logoutRequest = pendingLogout\n /** Stops sharing this logout after it settles without clearing a newer logout request. */\n const clearLogoutRequest = () => {\n if (logoutRequest === pendingLogout) {\n logoutRequest = undefined\n }\n }\n\n void pendingLogout.then(\n clearLogoutRequest, // onSuccess\n clearLogoutRequest, // onFailure\n )\n\n return pendingLogout\n }\n\n return {\n discardPendingResults,\n isLoggingOut: () => isLoggingOut,\n logOut,\n queue,\n refresh,\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,121 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createAuthSessionRequests } from './authSessionRequests.js';
3
+ describe('createAuthSessionRequests', () => {
4
+ it('should serialize auth requests in queue order', async () => {
5
+ const authRequests = createAuthSessionRequests();
6
+ const first = createDeferred();
7
+ const order = [];
8
+ const firstRequest = authRequests.queue(async () => {
9
+ order.push('first:start');
10
+ await first.promise;
11
+ order.push('first:end');
12
+ });
13
+ const secondRequest = authRequests.queue(async () => {
14
+ order.push('second');
15
+ });
16
+ expect(order).toEqual([]);
17
+ await Promise.resolve();
18
+ expect(order).toEqual(['first:start']);
19
+ first.resolve();
20
+ await Promise.all([firstRequest, secondRequest]);
21
+ expect(order).toEqual(['first:start', 'first:end', 'second']);
22
+ });
23
+ it('should share a refresh while session results remain current', async () => {
24
+ const authRequests = createAuthSessionRequests();
25
+ const refresh = createDeferred();
26
+ let runs = 0;
27
+ const run = () => authRequests.refresh(async () => {
28
+ runs += 1;
29
+ return refresh.promise;
30
+ });
31
+ const first = run();
32
+ const second = run();
33
+ expect(first).toBe(second);
34
+ refresh.resolve(null);
35
+ await Promise.all([first, second]);
36
+ expect(runs).toBe(1);
37
+ });
38
+ it('should discard a queued result after the session changes', async () => {
39
+ const authRequests = createAuthSessionRequests();
40
+ const operation = createDeferred();
41
+ let isResultStaleAfterSettlement = false;
42
+ const request = authRequests.queue(async ({
43
+ isResultStale
44
+ }) => {
45
+ await operation.promise;
46
+ isResultStaleAfterSettlement = isResultStale();
47
+ });
48
+ await Promise.resolve();
49
+ authRequests.discardPendingResults();
50
+ operation.resolve();
51
+ await request;
52
+ expect(isResultStaleAfterSettlement).toBe(true);
53
+ });
54
+ it('should settle a logout once and prevent refresh from committing', async () => {
55
+ const authRequests = createAuthSessionRequests();
56
+ const logout = createDeferred();
57
+ let clears = 0;
58
+ let logoutRequests = 0;
59
+ const first = authRequests.logOut({
60
+ clearSession: () => {
61
+ clears += 1;
62
+ authRequests.discardPendingResults();
63
+ },
64
+ request: async () => {
65
+ logoutRequests += 1;
66
+ await logout.promise;
67
+ }
68
+ });
69
+ const second = authRequests.logOut({
70
+ clearSession: () => {
71
+ clears += 1;
72
+ },
73
+ request: async () => {
74
+ logoutRequests += 1;
75
+ }
76
+ });
77
+ expect(first).toBe(second);
78
+ expect(authRequests.isLoggingOut()).toBe(true);
79
+ expect(await authRequests.refresh(async () => null)).toBeNull();
80
+ logout.resolve();
81
+ await first;
82
+ expect({
83
+ clears,
84
+ logoutRequests
85
+ }).toEqual({
86
+ clears: 1,
87
+ logoutRequests: 1
88
+ });
89
+ });
90
+ it('should discard a deferred invalidation after the session changes', async () => {
91
+ const authRequests = createAuthSessionRequests();
92
+ let invalidations = 0;
93
+ const first = authRequests.refresh(async ({
94
+ invalidateWhenIdle
95
+ }) => {
96
+ invalidateWhenIdle(() => {
97
+ invalidations += 1;
98
+ });
99
+ return null;
100
+ });
101
+ const second = authRequests.queue(async () => {
102
+ authRequests.discardPendingResults();
103
+ });
104
+ await Promise.all([first, second]);
105
+ expect(invalidations).toBe(0);
106
+ });
107
+ });
108
+ function createDeferred() {
109
+ let resolve;
110
+ const promise = new Promise(resolvePromise => {
111
+ resolve = resolvePromise;
112
+ });
113
+ if (!resolve) {
114
+ throw new Error('Expected deferred promise resolver.');
115
+ }
116
+ return {
117
+ promise,
118
+ resolve
119
+ };
120
+ }
121
+ //# sourceMappingURL=authSessionRequests.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authSessionRequests.spec.js","names":["describe","expect","it","createAuthSessionRequests","authRequests","first","createDeferred","order","firstRequest","queue","push","promise","secondRequest","toEqual","Promise","resolve","all","refresh","runs","run","second","toBe","operation","isResultStaleAfterSettlement","request","isResultStale","discardPendingResults","logout","clears","logoutRequests","logOut","clearSession","isLoggingOut","toBeNull","invalidations","invalidateWhenIdle","resolvePromise","Error"],"sources":["../../../src/providers/Auth/authSessionRequests.spec.ts"],"sourcesContent":["import { describe, expect, it } from 'vitest'\n\nimport { createAuthSessionRequests } from './authSessionRequests.js'\n\ndescribe('createAuthSessionRequests', () => {\n it('should serialize auth requests in queue order', async () => {\n const authRequests = createAuthSessionRequests()\n const first = createDeferred<void>()\n const order: string[] = []\n\n const firstRequest = authRequests.queue(async () => {\n order.push('first:start')\n await first.promise\n order.push('first:end')\n })\n const secondRequest = authRequests.queue(async () => {\n order.push('second')\n })\n\n expect(order).toEqual([])\n await Promise.resolve()\n expect(order).toEqual(['first:start'])\n\n first.resolve()\n await Promise.all([firstRequest, secondRequest])\n expect(order).toEqual(['first:start', 'first:end', 'second'])\n })\n\n it('should share a refresh while session results remain current', async () => {\n const authRequests = createAuthSessionRequests()\n const refresh = createDeferred<null>()\n let runs = 0\n const run = () =>\n authRequests.refresh(async () => {\n runs += 1\n return refresh.promise\n })\n\n const first = run()\n const second = run()\n expect(first).toBe(second)\n\n refresh.resolve(null)\n await Promise.all([first, second])\n expect(runs).toBe(1)\n })\n\n it('should discard a queued result after the session changes', async () => {\n const authRequests = createAuthSessionRequests()\n const operation = createDeferred<void>()\n let isResultStaleAfterSettlement = false\n\n const request = authRequests.queue(async ({ isResultStale }) => {\n await operation.promise\n isResultStaleAfterSettlement = isResultStale()\n })\n\n await Promise.resolve()\n authRequests.discardPendingResults()\n operation.resolve()\n await request\n\n expect(isResultStaleAfterSettlement).toBe(true)\n })\n\n it('should settle a logout once and prevent refresh from committing', async () => {\n const authRequests = createAuthSessionRequests()\n const logout = createDeferred<void>()\n let clears = 0\n let logoutRequests = 0\n\n const first = authRequests.logOut({\n clearSession: () => {\n clears += 1\n authRequests.discardPendingResults()\n },\n request: async () => {\n logoutRequests += 1\n await logout.promise\n },\n })\n const second = authRequests.logOut({\n clearSession: () => {\n clears += 1\n },\n request: async () => {\n logoutRequests += 1\n },\n })\n\n expect(first).toBe(second)\n expect(authRequests.isLoggingOut()).toBe(true)\n expect(await authRequests.refresh(async () => null)).toBeNull()\n logout.resolve()\n await first\n expect({ clears, logoutRequests }).toEqual({ clears: 1, logoutRequests: 1 })\n })\n\n it('should discard a deferred invalidation after the session changes', async () => {\n const authRequests = createAuthSessionRequests()\n let invalidations = 0\n\n const first = authRequests.refresh(async ({ invalidateWhenIdle }) => {\n invalidateWhenIdle(() => {\n invalidations += 1\n })\n return null\n })\n const second = authRequests.queue(async () => {\n authRequests.discardPendingResults()\n })\n\n await Promise.all([first, second])\n expect(invalidations).toBe(0)\n })\n})\n\nfunction createDeferred<Value>(): {\n promise: Promise<Value>\n resolve: (value: Value | PromiseLike<Value>) => void\n} {\n let resolve: ((value: Value | PromiseLike<Value>) => void) | undefined\n const promise = new Promise<Value>((resolvePromise) => {\n resolve = resolvePromise\n })\n\n if (!resolve) {\n throw new Error('Expected deferred promise resolver.')\n }\n\n return { promise, resolve }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,60 +1,7 @@
1
1
  import type { AuthenticatedUser, SanitizedPermissions } from 'payload';
2
2
  import React from 'react';
3
- export type UserWithToken<T = AuthenticatedUser> = {
4
- /** seconds until expiration */
5
- exp: number;
6
- refreshedToken?: string;
7
- token?: string;
8
- user: T;
9
- };
10
- export type AuthContext<T = AuthenticatedUser> = {
11
- fetchFullUser: () => Promise<null | T>;
12
- logOut: () => Promise<boolean>;
13
- /**
14
- * These are the permissions for the current user from a global scope.
15
- *
16
- * When checking for permissions on document specific level, use the `useDocumentInfo` hook instead.
17
- *
18
- * @example
19
- *
20
- * ```tsx
21
- * import { useAuth } from 'payload/ui'
22
- *
23
- * const MyComponent: React.FC = () => {
24
- * const { permissions } = useAuth()
25
- *
26
- * if (permissions?.collections?.myCollection?.create) {
27
- * // user can create documents in 'myCollection'
28
- * }
29
- *
30
- * return null
31
- * }
32
- * ```
33
- *
34
- * with useDocumentInfo:
35
- *
36
- * ```tsx
37
- * import { useDocumentInfo } from 'payload/ui'
38
- *
39
- * const MyComponent: React.FC = () => {
40
- * const { docPermissions } = useDocumentInfo()
41
- * if (docPermissions?.create) {
42
- * // user can create this document
43
- * }
44
- * return null
45
- * } ```
46
- */
47
- permissions?: SanitizedPermissions;
48
- refreshCookie: (forceRefresh?: boolean) => void;
49
- refreshCookieAsync: () => Promise<null | T>;
50
- refreshPermissions: () => Promise<void>;
51
- setPermissions: (permissions: SanitizedPermissions) => void;
52
- setUser: (user: null | UserWithToken<T>) => void;
53
- strategy?: string;
54
- token?: string;
55
- tokenExpirationMs?: number;
56
- user?: null | T;
57
- };
3
+ import type { AuthContext } from './types.js';
4
+ export type { AuthContext, AuthSession, UserWithToken } from './types.js';
58
5
  type Props = {
59
6
  children: React.ReactNode;
60
7
  permissions?: SanitizedPermissions;
@@ -62,5 +9,4 @@ type Props = {
62
9
  };
63
10
  export declare function AuthProvider({ children, permissions: initialPermissions, user: initialUser, }: Props): React.JSX.Element;
64
11
  export declare const useAuth: <T = AuthenticatedUser>() => AuthContext<T>;
65
- export {};
66
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/Auth/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAKtE,OAAO,KAA+D,MAAM,OAAO,CAAA;AAWnF,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,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,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,CAAA;CAChB,CAAA;AAMD,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,oBAAoB,CAAA;IAClC,IAAI,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAChC,CAAA;AAED,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,WAAW,EAAE,kBAAkB,EAC/B,IAAI,EAAE,WAAW,GAClB,EAAE,KAAK,qBAgUP;AAED,eAAO,MAAM,OAAO,GAAI,CAAC,GAAG,iBAAiB,OAAM,WAAW,CAAC,CAAC,CAAmC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/Auth/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAKtE,OAAO,KAA+D,MAAM,OAAO,CAAA;AAInF,OAAO,KAAK,EAAE,WAAW,EAA8B,MAAM,YAAY,CAAA;AAczE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAIzE,KAAK,KAAK,GAAG;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,oBAAoB,CAAA;IAClC,IAAI,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAChC,CAAA;AAsBD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,WAAW,EAAE,kBAAkB,EAC/B,IAAI,EAAE,WAAW,GAClB,EAAE,KAAK,qBAodP;AAED,eAAO,MAAM,OAAO,GAAI,CAAC,GAAG,iBAAiB,OAAM,WAAW,CAAC,CAAC,CAAmC,CAAA"}