payload-subscribers-plugin 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/contexts/SubscriberProvider.js +37 -25
- package/dist/contexts/SubscriberProvider.js.map +1 -1
- package/dist/endpoints/logout.d.ts +3 -1
- package/dist/endpoints/logout.js +14 -30
- package/dist/endpoints/logout.js.map +1 -1
- package/dist/endpoints/verifyMagicLink.js +53 -15
- package/dist/endpoints/verifyMagicLink.js.map +1 -1
- package/dist/hooks/useVerifyMagicLink.d.ts +3 -0
- package/dist/hooks/useVerifyMagicLink.js +11 -4
- package/dist/hooks/useVerifyMagicLink.js.map +1 -1
- package/dist/server-functions/serverUrl.js +2 -1
- package/dist/server-functions/serverUrl.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,7 +49,7 @@ export default buildConfig({
|
|
|
49
49
|
subscribersCollectionSlug?: CollectionSlug
|
|
50
50
|
|
|
51
51
|
// Provide a custom expiration for magic link tokens. The default is 30 minutes.
|
|
52
|
-
tokenExpiration:
|
|
52
|
+
tokenExpiration: 30 * 60,
|
|
53
53
|
|
|
54
54
|
// Provide your unsubscribe route. This route should include the Unsubscribe component, or implement your own with the useUnsubscribe hook. If not provided, your payload config must have serverURL defined, and the default will be serverURL+'/unsubscribe'
|
|
55
55
|
unsubscribeURL?: string,
|
|
@@ -18,36 +18,46 @@ const SubscriberContext = /*#__PURE__*/ createContext(undefined);
|
|
|
18
18
|
// Keep track of if the selection content is loaded yet
|
|
19
19
|
const [isLoaded, setIsLoaded] = useState(false);
|
|
20
20
|
const [permissions, setPermissions] = useState();
|
|
21
|
-
const initSubscriber = async ()=>{
|
|
22
|
-
console.log('initSubscriber');
|
|
21
|
+
const initSubscriber = useCallback(async ()=>{
|
|
22
|
+
console.log('initSubscriber', serverURL);
|
|
23
23
|
setIsLoaded(false);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
24
|
+
if (serverURL) {
|
|
25
|
+
try {
|
|
26
|
+
const authResponse = await fetch(`${serverURL}/api/subscriberAuth`, {
|
|
27
|
+
// body: JSON.stringify({}),
|
|
28
|
+
method: 'POST'
|
|
29
|
+
});
|
|
30
|
+
if (authResponse.ok) {
|
|
31
|
+
try {
|
|
32
|
+
const authResponseJson = await authResponse.json();
|
|
33
|
+
// console.log('authResponseJson', JSON.stringify(authResponseJson, undefined, 2))
|
|
34
|
+
const { permissions, subscriber } = authResponseJson;
|
|
35
|
+
console.log(`subscriber = `, subscriber);
|
|
36
|
+
// console.log(`permissions = `, permissions)
|
|
37
|
+
setPermissions(permissions);
|
|
38
|
+
setSubscriber(subscriber);
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.log('authResponse error, with json:', error);
|
|
41
|
+
const authResponseText = await authResponse.text();
|
|
42
|
+
console.log('authResponse error, text:', authResponseText);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
console.log('authResponse not ok', authResponse);
|
|
46
|
+
setPermissions(null);
|
|
47
|
+
setSubscriber(null);
|
|
48
|
+
}
|
|
49
|
+
setIsLoaded(true);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.log(`authResponse error`, error);
|
|
41
52
|
}
|
|
42
|
-
} catch (error) {
|
|
43
|
-
console.log(`authResponse error`, error);
|
|
44
53
|
}
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
}, [
|
|
55
|
+
serverURL
|
|
56
|
+
]);
|
|
47
57
|
const refreshSubscriber = useCallback(async ()=>{
|
|
48
58
|
await initSubscriber();
|
|
49
59
|
}, [
|
|
50
|
-
|
|
60
|
+
initSubscriber
|
|
51
61
|
]);
|
|
52
62
|
const logOut = useCallback(async ()=>{
|
|
53
63
|
setIsLoaded(false);
|
|
@@ -76,7 +86,9 @@ const SubscriberContext = /*#__PURE__*/ createContext(undefined);
|
|
|
76
86
|
}, []);
|
|
77
87
|
useEffect(()=>{
|
|
78
88
|
void initSubscriber();
|
|
79
|
-
}, [
|
|
89
|
+
}, [
|
|
90
|
+
initSubscriber
|
|
91
|
+
]);
|
|
80
92
|
// Memoize the value to prevent unnecessary re-renders in consumers
|
|
81
93
|
const contextValue = useMemo(()=>({
|
|
82
94
|
isLoaded,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/contexts/SubscriberProvider.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ReactNode, useCallback, useEffect } from 'react'\nimport { createContext, useContext, useMemo, useState } from 'react'\n\nimport type { Config, OptInChannel, Subscriber } from '../copied/payload-types.js'\n\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/** Value provided by SubscriberProvider: current subscriber, auth state, and actions. */\nexport type SubscriberContextType = {\n isLoaded: boolean\n logOut: () => void\n permissions: any\n refreshSubscriber: () => void\n subscriber: ({ optIns?: null | OptInChannel[] } & Omit<Subscriber, 'optIns'>) | null\n}\n\nconst SubscriberContext = createContext<SubscriberContextType | undefined>(undefined)\n\n/** Props for SubscriberProvider. */\ninterface ProviderProps {\n children?: ReactNode\n}\n\n/**\n * Provider that fetches and holds the current subscriber auth state (via POST /api/subscriberAuth).\n * Exposes subscriber, permissions, refreshSubscriber, and logOut to descendants. Must wrap any\n * component that uses useSubscriber().\n *\n * @param props.children - React tree to wrap\n * @returns SubscriberContext.Provider with current auth state and actions\n */\nexport function SubscriberProvider({ children }: ProviderProps) {\n // eslint-disable-next-line\n const [subscriber, setSubscriber] = useState<null | (Subscriber & { optIns: OptInChannel[] })>(\n null,\n )\n\n const { serverURL } = useServerUrl()\n\n // Keep track of if the selection content is loaded yet\n const [isLoaded, setIsLoaded] = useState(false)\n\n const [permissions, setPermissions] = useState<any>()\n\n const initSubscriber = async () => {\n console.log('initSubscriber')\n setIsLoaded(false)\n try {\n
|
|
1
|
+
{"version":3,"sources":["../../src/contexts/SubscriberProvider.tsx"],"sourcesContent":["'use client'\n\nimport { PayloadSDK } from '@payloadcms/sdk'\nimport { type ReactNode, useCallback, useEffect } from 'react'\nimport { createContext, useContext, useMemo, useState } from 'react'\n\nimport type { Config, OptInChannel, Subscriber } from '../copied/payload-types.js'\n\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/** Value provided by SubscriberProvider: current subscriber, auth state, and actions. */\nexport type SubscriberContextType = {\n isLoaded: boolean\n logOut: () => void\n permissions: any\n refreshSubscriber: () => void\n subscriber: ({ optIns?: null | OptInChannel[] } & Omit<Subscriber, 'optIns'>) | null\n}\n\nconst SubscriberContext = createContext<SubscriberContextType | undefined>(undefined)\n\n/** Props for SubscriberProvider. */\ninterface ProviderProps {\n children?: ReactNode\n}\n\n/**\n * Provider that fetches and holds the current subscriber auth state (via POST /api/subscriberAuth).\n * Exposes subscriber, permissions, refreshSubscriber, and logOut to descendants. Must wrap any\n * component that uses useSubscriber().\n *\n * @param props.children - React tree to wrap\n * @returns SubscriberContext.Provider with current auth state and actions\n */\nexport function SubscriberProvider({ children }: ProviderProps) {\n // eslint-disable-next-line\n const [subscriber, setSubscriber] = useState<null | (Subscriber & { optIns: OptInChannel[] })>(\n null,\n )\n\n const { serverURL } = useServerUrl()\n\n // Keep track of if the selection content is loaded yet\n const [isLoaded, setIsLoaded] = useState(false)\n\n const [permissions, setPermissions] = useState<any>()\n\n const initSubscriber = useCallback(async () => {\n console.log('initSubscriber', serverURL)\n setIsLoaded(false)\n if (serverURL) {\n try {\n const authResponse = await fetch(`${serverURL}/api/subscriberAuth`, {\n // body: JSON.stringify({}),\n method: 'POST',\n })\n\n if (authResponse.ok) {\n try {\n const authResponseJson = await authResponse.json()\n // console.log('authResponseJson', JSON.stringify(authResponseJson, undefined, 2))\n const { permissions, subscriber } = authResponseJson\n console.log(`subscriber = `, subscriber)\n // console.log(`permissions = `, permissions)\n setPermissions(permissions)\n setSubscriber(subscriber)\n } catch (error) {\n console.log('authResponse error, with json:', error)\n const authResponseText = await authResponse.text()\n console.log('authResponse error, text:', authResponseText)\n }\n } else {\n console.log('authResponse not ok', authResponse)\n setPermissions(null)\n setSubscriber(null)\n }\n setIsLoaded(true)\n } catch (error: unknown) {\n console.log(`authResponse error`, error)\n }\n }\n }, [serverURL])\n\n const refreshSubscriber = useCallback(async () => {\n await initSubscriber()\n }, [initSubscriber])\n\n const logOut = useCallback(async () => {\n setIsLoaded(false)\n try {\n // const sdk = new PayloadSDK<Config>({\n // baseURL: serverURL || '',\n // })\n // const logoutResponse = await sdk.request({\n // json: {},\n // method: 'POST',\n // path: '/api/logout',\n // })\n // Unsure why sdk isn't working here\n const logoutResponse = await fetch('/api/logout', {\n method: 'POST',\n })\n\n // console.log(`logoutResponse`, logoutResponse)\n\n if (logoutResponse.ok) {\n setSubscriber(null)\n setPermissions(null)\n }\n } catch (error: unknown) {\n console.log(`logoutResponse error`, error)\n }\n setIsLoaded(true)\n }, [])\n\n useEffect(() => {\n void initSubscriber()\n }, [initSubscriber])\n\n // Memoize the value to prevent unnecessary re-renders in consumers\n const contextValue: SubscriberContextType = useMemo(\n () => ({\n isLoaded,\n logOut,\n permissions,\n refreshSubscriber,\n subscriber,\n }),\n [isLoaded, logOut, permissions, refreshSubscriber, subscriber],\n )\n\n return <SubscriberContext.Provider value={contextValue}>{children}</SubscriberContext.Provider>\n}\n\n/**\n * Consumes SubscriberContext. Use only inside a SubscriberProvider.\n *\n * @returns Current subscriber (or null), permissions, isLoaded, refreshSubscriber, and logOut\n * @throws Error if used outside SubscriberProvider\n */\nexport function useSubscriber() {\n const context = useContext(SubscriberContext)\n if (context === undefined) {\n throw new Error('useSubscriber must be used within a SubscriberProvider')\n }\n return context\n}\n"],"names":["useCallback","useEffect","createContext","useContext","useMemo","useState","useServerUrl","SubscriberContext","undefined","SubscriberProvider","children","subscriber","setSubscriber","serverURL","isLoaded","setIsLoaded","permissions","setPermissions","initSubscriber","console","log","authResponse","fetch","method","ok","authResponseJson","json","error","authResponseText","text","refreshSubscriber","logOut","logoutResponse","contextValue","Provider","value","useSubscriber","context","Error"],"mappings":"AAAA;;AAGA,SAAyBA,WAAW,EAAEC,SAAS,QAAQ,QAAO;AAC9D,SAASC,aAAa,EAAEC,UAAU,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,QAAO;AAIpE,SAASC,YAAY,QAAQ,iCAAgC;AAW7D,MAAMC,kCAAoBL,cAAiDM;AAO3E;;;;;;;CAOC,GACD,OAAO,SAASC,mBAAmB,EAAEC,QAAQ,EAAiB;IAC5D,2BAA2B;IAC3B,MAAM,CAACC,YAAYC,cAAc,GAAGP,SAClC;IAGF,MAAM,EAAEQ,SAAS,EAAE,GAAGP;IAEtB,uDAAuD;IACvD,MAAM,CAACQ,UAAUC,YAAY,GAAGV,SAAS;IAEzC,MAAM,CAACW,aAAaC,eAAe,GAAGZ;IAEtC,MAAMa,iBAAiBlB,YAAY;QACjCmB,QAAQC,GAAG,CAAC,kBAAkBP;QAC9BE,YAAY;QACZ,IAAIF,WAAW;YACb,IAAI;gBACF,MAAMQ,eAAe,MAAMC,MAAM,GAAGT,UAAU,mBAAmB,CAAC,EAAE;oBAClE,4BAA4B;oBAC5BU,QAAQ;gBACV;gBAEA,IAAIF,aAAaG,EAAE,EAAE;oBACnB,IAAI;wBACF,MAAMC,mBAAmB,MAAMJ,aAAaK,IAAI;wBAChD,kFAAkF;wBAClF,MAAM,EAAEV,WAAW,EAAEL,UAAU,EAAE,GAAGc;wBACpCN,QAAQC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAET;wBAC7B,6CAA6C;wBAC7CM,eAAeD;wBACfJ,cAAcD;oBAChB,EAAE,OAAOgB,OAAO;wBACdR,QAAQC,GAAG,CAAC,kCAAkCO;wBAC9C,MAAMC,mBAAmB,MAAMP,aAAaQ,IAAI;wBAChDV,QAAQC,GAAG,CAAC,6BAA6BQ;oBAC3C;gBACF,OAAO;oBACLT,QAAQC,GAAG,CAAC,uBAAuBC;oBACnCJ,eAAe;oBACfL,cAAc;gBAChB;gBACAG,YAAY;YACd,EAAE,OAAOY,OAAgB;gBACvBR,QAAQC,GAAG,CAAC,CAAC,kBAAkB,CAAC,EAAEO;YACpC;QACF;IACF,GAAG;QAACd;KAAU;IAEd,MAAMiB,oBAAoB9B,YAAY;QACpC,MAAMkB;IACR,GAAG;QAACA;KAAe;IAEnB,MAAMa,SAAS/B,YAAY;QACzBe,YAAY;QACZ,IAAI;YACF,uCAAuC;YACvC,8BAA8B;YAC9B,KAAK;YACL,6CAA6C;YAC7C,cAAc;YACd,oBAAoB;YACpB,yBAAyB;YACzB,KAAK;YACL,oCAAoC;YACpC,MAAMiB,iBAAiB,MAAMV,MAAM,eAAe;gBAChDC,QAAQ;YACV;YAEA,gDAAgD;YAEhD,IAAIS,eAAeR,EAAE,EAAE;gBACrBZ,cAAc;gBACdK,eAAe;YACjB;QACF,EAAE,OAAOU,OAAgB;YACvBR,QAAQC,GAAG,CAAC,CAAC,oBAAoB,CAAC,EAAEO;QACtC;QACAZ,YAAY;IACd,GAAG,EAAE;IAELd,UAAU;QACR,KAAKiB;IACP,GAAG;QAACA;KAAe;IAEnB,mEAAmE;IACnE,MAAMe,eAAsC7B,QAC1C,IAAO,CAAA;YACLU;YACAiB;YACAf;YACAc;YACAnB;QACF,CAAA,GACA;QAACG;QAAUiB;QAAQf;QAAac;QAAmBnB;KAAW;IAGhE,qBAAO,KAACJ,kBAAkB2B,QAAQ;QAACC,OAAOF;kBAAevB;;AAC3D;AAEA;;;;;CAKC,GACD,OAAO,SAAS0B;IACd,MAAMC,UAAUlC,WAAWI;IAC3B,IAAI8B,YAAY7B,WAAW;QACzB,MAAM,IAAI8B,MAAM;IAClB;IACA,OAAOD;AACT"}
|
|
@@ -8,7 +8,9 @@ export type LogoutResponse = {
|
|
|
8
8
|
};
|
|
9
9
|
/**
|
|
10
10
|
* Factory that creates the logout endpoint config and handler.
|
|
11
|
-
* Clears the current subscriber session by
|
|
11
|
+
* Clears the current subscriber session by deleting Payload's cookie directly.
|
|
12
|
+
* (Delegating to Payload's collection logout is causing timing issues with the
|
|
13
|
+
* serverless function to serverless function call.)
|
|
12
14
|
*
|
|
13
15
|
* @param options - Config options for the endpoint
|
|
14
16
|
* @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)
|
package/dist/endpoints/logout.js
CHANGED
|
@@ -1,48 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cookies as nextCookies } from 'next/headers.js';
|
|
2
|
+
import { NextResponse } from 'next/server.js';
|
|
2
3
|
import { defaultCollectionSlug } from '../collections/Subscribers.js';
|
|
3
4
|
/**
|
|
4
5
|
* Factory that creates the logout endpoint config and handler.
|
|
5
|
-
* Clears the current subscriber session by
|
|
6
|
+
* Clears the current subscriber session by deleting Payload's cookie directly.
|
|
7
|
+
* (Delegating to Payload's collection logout is causing timing issues with the
|
|
8
|
+
* serverless function to serverless function call.)
|
|
6
9
|
*
|
|
7
10
|
* @param options - Config options for the endpoint
|
|
8
11
|
* @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)
|
|
9
12
|
* @returns Payload Endpoint config for POST /logout
|
|
10
13
|
*/ function createEndpointLogout({ subscribersCollectionSlug = defaultCollectionSlug }) {
|
|
11
14
|
const logoutHandler = async (req)=>{
|
|
12
|
-
const
|
|
15
|
+
const collectionLogoutEndpoint = `${req.payload.config.serverURL}/api/${subscribersCollectionSlug}/logout`;
|
|
13
16
|
try {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const cookies = await nextCookies();
|
|
18
|
+
cookies.set('payload-token', '', {
|
|
19
|
+
expires: new Date(0)
|
|
17
20
|
});
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return Response.json({
|
|
21
|
-
message: logoutResultData.message,
|
|
22
|
-
now: new Date().toISOString()
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
if (logoutResult.status == 400 && logoutResultData.errors?.map((e)=>e.message).includes('No User')) {
|
|
26
|
-
return Response.json({
|
|
27
|
-
error: `Logout failed: 'No User'`,
|
|
28
|
-
now: new Date().toISOString()
|
|
29
|
-
}, {
|
|
30
|
-
status: 400
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
return Response.json({
|
|
34
|
-
error: `Logout failed: ${logoutResultData.errors ? logoutResultData.errors?.map((e)=>e.message).join(' // ') : JSON.stringify(logoutResultData)}`,
|
|
21
|
+
return NextResponse.json({
|
|
22
|
+
message: 'Logged out',
|
|
35
23
|
now: new Date().toISOString()
|
|
36
|
-
}, {
|
|
37
|
-
status: 400
|
|
38
24
|
});
|
|
39
25
|
} catch (error) {
|
|
26
|
+
req.payload.logger.error(`logoutHandler error: ${JSON.stringify(error, undefined, 2)}`);
|
|
40
27
|
// throw new Error(`Logout failed: ${error instanceof Error ? error.message : 'Unknown error'}`)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
now: new Date().toISOString()
|
|
44
|
-
}, {
|
|
45
|
-
status: 400
|
|
28
|
+
throw new Error(`Logout failed: ${collectionLogoutEndpoint} : ${JSON.stringify(error, undefined, 2)}`, {
|
|
29
|
+
cause: error
|
|
46
30
|
});
|
|
47
31
|
}
|
|
48
32
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/logout.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\n\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/logout.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\n\nimport { cookies as nextCookies } from 'next/headers.js'\nimport { NextResponse } from 'next/server.js'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\n\nexport type LogoutResponse =\n | {\n error: string\n now: string\n }\n | {\n message: string\n now: string\n }\n\n/**\n * Factory that creates the logout endpoint config and handler.\n * Clears the current subscriber session by deleting Payload's cookie directly.\n * (Delegating to Payload's collection logout is causing timing issues with the\n * serverless function to serverless function call.)\n *\n * @param options - Config options for the endpoint\n * @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)\n * @returns Payload Endpoint config for POST /logout\n */\nfunction createEndpointLogout({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n const logoutHandler: PayloadHandler = async (req) => {\n const collectionLogoutEndpoint = `${req.payload.config.serverURL}/api/${subscribersCollectionSlug}/logout`\n try {\n const cookies = await nextCookies()\n cookies.set('payload-token', '', { expires: new Date(0) })\n\n return NextResponse.json({\n message: 'Logged out',\n now: new Date().toISOString(),\n } as LogoutResponse)\n } catch (error) {\n req.payload.logger.error(`logoutHandler error: ${JSON.stringify(error, undefined, 2)}`)\n\n // throw new Error(`Logout failed: ${error instanceof Error ? error.message : 'Unknown error'}`)\n throw new Error(\n `Logout failed: ${collectionLogoutEndpoint} : ${JSON.stringify(error, undefined, 2)}`,\n { cause: error },\n )\n }\n }\n\n /** Endpoint config for subscriber logout. Mount as POST /logout. */\n const logoutEndpoint: Endpoint = {\n handler: logoutHandler,\n method: 'post',\n path: '/logout',\n }\n\n return logoutEndpoint\n}\n\nexport default createEndpointLogout\n"],"names":["cookies","nextCookies","NextResponse","defaultCollectionSlug","createEndpointLogout","subscribersCollectionSlug","logoutHandler","req","collectionLogoutEndpoint","payload","config","serverURL","set","expires","Date","json","message","now","toISOString","error","logger","JSON","stringify","undefined","Error","cause","logoutEndpoint","handler","method","path"],"mappings":"AAEA,SAASA,WAAWC,WAAW,QAAQ,kBAAiB;AACxD,SAASC,YAAY,QAAQ,iBAAgB;AAE7C,SAASC,qBAAqB,QAAQ,gCAA+B;AAYrE;;;;;;;;;CASC,GACD,SAASC,qBAAqB,EAC5BC,4BAA4BF,qBAAqB,EAGlD;IACC,MAAMG,gBAAgC,OAAOC;QAC3C,MAAMC,2BAA2B,GAAGD,IAAIE,OAAO,CAACC,MAAM,CAACC,SAAS,CAAC,KAAK,EAAEN,0BAA0B,OAAO,CAAC;QAC1G,IAAI;YACF,MAAML,UAAU,MAAMC;YACtBD,QAAQY,GAAG,CAAC,iBAAiB,IAAI;gBAAEC,SAAS,IAAIC,KAAK;YAAG;YAExD,OAAOZ,aAAaa,IAAI,CAAC;gBACvBC,SAAS;gBACTC,KAAK,IAAIH,OAAOI,WAAW;YAC7B;QACF,EAAE,OAAOC,OAAO;YACdZ,IAAIE,OAAO,CAACW,MAAM,CAACD,KAAK,CAAC,CAAC,qBAAqB,EAAEE,KAAKC,SAAS,CAACH,OAAOI,WAAW,IAAI;YAEtF,gGAAgG;YAChG,MAAM,IAAIC,MACR,CAAC,eAAe,EAAEhB,yBAAyB,GAAG,EAAEa,KAAKC,SAAS,CAACH,OAAOI,WAAW,IAAI,EACrF;gBAAEE,OAAON;YAAM;QAEnB;IACF;IAEA,kEAAkE,GAClE,MAAMO,iBAA2B;QAC/BC,SAASrB;QACTsB,QAAQ;QACRC,MAAM;IACR;IAEA,OAAOH;AACT;AAEA,eAAetB,qBAAoB"}
|
|
@@ -15,11 +15,13 @@ import { getHash, getTokenAndHash } from '../helpers/token.js';
|
|
|
15
15
|
* @param req - Payload request; body must include `email` and `token`
|
|
16
16
|
* @returns 200 with `message`, `now` and Set-Cookie on success; 400 with `error` and `now` on bad data, invalid token, or expiry
|
|
17
17
|
*/ const verifyMagicLinkHandler = async (req)=>{
|
|
18
|
+
// req.payload.logger.info('verifyMagicLinkHandler')
|
|
18
19
|
const reqData = req?.json ? await req.json() : {};
|
|
19
20
|
const { email, token } = reqData // if by POST reqData
|
|
20
21
|
;
|
|
21
22
|
// const { email, token } = req.routeParams // if by path
|
|
22
23
|
if (!email || !token) {
|
|
24
|
+
req.payload.logger.info('verifyMagicLinkHandler Bad data');
|
|
23
25
|
return Response.json({
|
|
24
26
|
error: 'Bad data',
|
|
25
27
|
now: new Date().toISOString()
|
|
@@ -37,6 +39,7 @@ import { getHash, getTokenAndHash } from '../helpers/token.js';
|
|
|
37
39
|
});
|
|
38
40
|
const user = userResults.docs[0];
|
|
39
41
|
if (!user) {
|
|
42
|
+
req.payload.logger.info('verifyMagicLinkHandler no user');
|
|
40
43
|
return Response.json({
|
|
41
44
|
error: 'Bad data',
|
|
42
45
|
now: new Date().toISOString()
|
|
@@ -58,6 +61,7 @@ import { getHash, getTokenAndHash } from '../helpers/token.js';
|
|
|
58
61
|
});
|
|
59
62
|
}
|
|
60
63
|
if (new Date(Date.now()) > new Date(user.verificationTokenExpires)) {
|
|
64
|
+
req.payload.logger.info('verifyMagicLinkHandler Token expired');
|
|
61
65
|
return Response.json({
|
|
62
66
|
error: 'Token expired',
|
|
63
67
|
now: new Date().toISOString()
|
|
@@ -65,18 +69,25 @@ import { getHash, getTokenAndHash } from '../helpers/token.js';
|
|
|
65
69
|
status: 400
|
|
66
70
|
});
|
|
67
71
|
}
|
|
68
|
-
//
|
|
72
|
+
// req.payload.logger.info(
|
|
73
|
+
// `verifyMagicLinkHandler user found and token validated, prepping to authencticate ${user.email}`,
|
|
74
|
+
// )
|
|
75
|
+
// Update user with token password
|
|
69
76
|
await req.payload.update({
|
|
70
77
|
collection: subscribersCollectionSlug,
|
|
71
78
|
data: {
|
|
72
79
|
password: tokenHash
|
|
73
80
|
},
|
|
81
|
+
disableTransaction: true,
|
|
74
82
|
where: {
|
|
75
83
|
email: {
|
|
76
84
|
equals: user.email
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
});
|
|
88
|
+
// req.payload.logger.info(
|
|
89
|
+
// 'verifyMagicLinkHandler user found and token validated, prepping to authencticate DONE',
|
|
90
|
+
// )
|
|
80
91
|
// Log the user in via Payload headers
|
|
81
92
|
let headers;
|
|
82
93
|
try {
|
|
@@ -96,13 +107,12 @@ import { getHash, getTokenAndHash } from '../helpers/token.js';
|
|
|
96
107
|
}
|
|
97
108
|
} catch (error) {
|
|
98
109
|
// console.log(error)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
status: 400
|
|
110
|
+
req.payload.logger.info(`verifyMagicLinkHandler catch error ${JSON.stringify(error, undefined, 2)}`);
|
|
111
|
+
throw new Error(`verifyMagicLinkHandler catch error: ${JSON.stringify(error, undefined, 2)}`, {
|
|
112
|
+
cause: error
|
|
103
113
|
});
|
|
114
|
+
// return Response.json({ error } as VerifyMagicLinkResponse, { status: 400 })
|
|
104
115
|
}
|
|
105
|
-
// console.log('login', headers)
|
|
106
116
|
const status = user?.status == 'pending' ? 'subscribed' : user?.status;
|
|
107
117
|
const { tokenHash: tokenHash2 } = getTokenAndHash() // Unknowable
|
|
108
118
|
;
|
|
@@ -112,21 +122,49 @@ import { getHash, getTokenAndHash } from '../helpers/token.js';
|
|
|
112
122
|
verificationToken: '',
|
|
113
123
|
verificationTokenExpires: null
|
|
114
124
|
};
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
let updateResult;
|
|
126
|
+
try {
|
|
127
|
+
// Update user
|
|
128
|
+
updateResult = await req.payload.update({
|
|
129
|
+
collection: subscribersCollectionSlug,
|
|
130
|
+
data,
|
|
131
|
+
where: {
|
|
132
|
+
email: {
|
|
133
|
+
equals: user.email
|
|
134
|
+
}
|
|
122
135
|
}
|
|
136
|
+
});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
// console.log(error)
|
|
139
|
+
req.payload.logger.info(`verifyMagicLinkHandler update catch error ${JSON.stringify(error, undefined, 2)}`);
|
|
140
|
+
throw new Error(`verifyMagicLinkHandler update catch error: ${JSON.stringify(error, undefined, 2)}`, {
|
|
141
|
+
cause: error
|
|
142
|
+
});
|
|
143
|
+
// return Response.json({ error } as VerifyMagicLinkResponse, { status: 400 })
|
|
144
|
+
}
|
|
145
|
+
function keepOnlySetCookie(originalHeaders) {
|
|
146
|
+
// Use getSetCookie() to get all values as an array
|
|
147
|
+
const setCookieValues = originalHeaders.getSetCookie();
|
|
148
|
+
// Create a new Headers object
|
|
149
|
+
const newHeaders = new Headers();
|
|
150
|
+
// Append each 'set-cookie' value individually
|
|
151
|
+
for (const cookieValue of setCookieValues){
|
|
152
|
+
newHeaders.append('set-cookie', cookieValue);
|
|
123
153
|
}
|
|
124
|
-
|
|
154
|
+
return newHeaders;
|
|
155
|
+
}
|
|
156
|
+
const newHeaders = headers ? keepOnlySetCookie(headers) : undefined;
|
|
157
|
+
// req.payload.logger.info(
|
|
158
|
+
// `verifyMagicLinkHandler headers ${JSON.stringify(headers?.entries(), undefined, 2)}`,
|
|
159
|
+
// )
|
|
160
|
+
// req.payload.logger.info(
|
|
161
|
+
// `verifyMagicLinkHandler newHeaders ${JSON.stringify(newHeaders?.entries(), undefined, 2)}`,
|
|
162
|
+
// )
|
|
125
163
|
return Response.json({
|
|
126
164
|
message: 'Token verified',
|
|
127
165
|
now: new Date().toISOString()
|
|
128
166
|
}, {
|
|
129
|
-
headers
|
|
167
|
+
headers: newHeaders
|
|
130
168
|
});
|
|
131
169
|
};
|
|
132
170
|
/** Endpoint config for verifying magic link and logging in. Mount as POST /verifyToken. */ const verifyMagicLinkEndpoint = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/verifyMagicLink.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\nimport type { Subscriber } from 'src/copied/payload-types.js'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\nimport { getHash, getTokenAndHash } from '../helpers/token.js'\n\nexport type VerifyMagicLinkResponse =\n | {\n error: string\n now: string\n }\n | {\n message: string\n now: string\n }\n\n/**\n * Factory that creates the verify-magic-link endpoint config and handler.\n * Validates token from the magic link, marks the subscriber as verified, and logs them in.\n *\n * @param options - Config options for the endpoint\n * @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)\n * @returns Payload Endpoint config for POST /verifyToken\n */\nfunction createEndpointVerifyMagicLink({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * Handler for POST /verifyToken. Validates email + token from magic link, updates subscriber\n * password and status, and performs login to set auth cookies.\n *\n * @param req - Payload request; body must include `email` and `token`\n * @returns 200 with `message`, `now` and Set-Cookie on success; 400 with `error` and `now` on bad data, invalid token, or expiry\n */\n const verifyMagicLinkHandler: PayloadHandler = async (req) => {\n const reqData = req?.json ? await req.json() : {}\n const { email, token }: { email: string; token: string } = reqData // if by POST reqData\n // const { email, token } = req.routeParams // if by path\n\n if (!email || !token) {\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n const userResults = await req.payload.find({\n collection: subscribersCollectionSlug,\n where: {\n email: { equals: email },\n },\n })\n\n type SubscriberType = {\n // @ts-expect-error Why is this not correct, isn't it how Payload does it?\n collection: subscribersCollectionSlug\n } & Subscriber\n\n const user = userResults.docs[0] as SubscriberType\n\n if (!user) {\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n const { tokenHash } = getHash(token)\n\n // req.payload.logger.info(\n // `verifyMagicLinkHandler ${email} \\n ${tokenHash} \\n ${user.verificationTokenExpires} \\n ${user.verificationToken}`,\n // )\n if (!user.verificationTokenExpires || tokenHash != user.verificationToken) {\n req.payload.logger.info(`Token not verified: ${tokenHash} != ${user.verificationToken}`)\n return Response.json(\n { error: 'Token not verified', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n if (new Date(Date.now()) > new Date(user.verificationTokenExpires)) {\n return Response.json(\n { error: 'Token expired', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n // Update user\n await req.payload.update({\n collection: subscribersCollectionSlug,\n data: {\n password: tokenHash,\n },\n where: {\n email: { equals: user.email },\n },\n })\n\n // Log the user in via Payload headers\n let headers\n try {\n const loginReq = await fetch(\n `${req.payload.config.serverURL}/api/${subscribersCollectionSlug}/login`,\n {\n body: JSON.stringify({\n email,\n password: tokenHash,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n },\n )\n if (loginReq && loginReq.ok) {\n headers = loginReq.headers\n }\n } catch (error) {\n // console.log(error)\n return Response.json({ error } as VerifyMagicLinkResponse, { status: 400 })\n }\n // console.log('login', headers)\n\n const status: 'pending' | 'subscribed' | 'unsubscribed' | undefined =\n user?.status == 'pending' ? 'subscribed' : user?.status\n\n const { tokenHash: tokenHash2 } = getTokenAndHash() // Unknowable\n const data = {\n password: tokenHash2,\n status,\n verificationToken: '',\n verificationTokenExpires: null,\n }\n // Update user\n await req.payload.update({\n collection: subscribersCollectionSlug,\n data,\n where: {\n email: { equals: user.email },\n },\n })\n\n return Response.json(\n {\n message: 'Token verified',\n now: new Date().toISOString(),\n } as VerifyMagicLinkResponse,\n { headers },\n )\n }\n\n /** Endpoint config for verifying magic link and logging in. Mount as POST /verifyToken. */\n const verifyMagicLinkEndpoint: Endpoint = {\n handler: verifyMagicLinkHandler,\n method: 'post',\n path: '/verifyToken',\n }\n\n return verifyMagicLinkEndpoint\n}\n\nexport default createEndpointVerifyMagicLink\n"],"names":["defaultCollectionSlug","getHash","getTokenAndHash","createEndpointVerifyMagicLink","subscribersCollectionSlug","verifyMagicLinkHandler","req","reqData","json","email","token","Response","error","now","Date","toISOString","status","userResults","payload","find","collection","where","equals","user","docs","tokenHash","verificationTokenExpires","verificationToken","logger","info","update","data","password","headers","loginReq","fetch","config","serverURL","body","JSON","stringify","credentials","method","ok","tokenHash2","message","verifyMagicLinkEndpoint","handler","path"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/verifyMagicLink.ts"],"sourcesContent":["import type { CollectionSlug, Endpoint, PayloadHandler } from 'payload'\nimport type { Subscriber } from 'src/copied/payload-types.js'\n\nimport { defaultCollectionSlug } from '../collections/Subscribers.js'\nimport { getHash, getTokenAndHash } from '../helpers/token.js'\n\nexport type VerifyMagicLinkResponse =\n | {\n error: string\n now: string\n }\n | {\n message: string\n now: string\n }\n\n/**\n * Factory that creates the verify-magic-link endpoint config and handler.\n * Validates token from the magic link, marks the subscriber as verified, and logs them in.\n *\n * @param options - Config options for the endpoint\n * @param options.subscribersCollectionSlug - Collection slug for subscribers (default from Subscribers collection)\n * @returns Payload Endpoint config for POST /verifyToken\n */\nfunction createEndpointVerifyMagicLink({\n subscribersCollectionSlug = defaultCollectionSlug,\n}: {\n subscribersCollectionSlug: CollectionSlug\n}): Endpoint {\n /**\n * Handler for POST /verifyToken. Validates email + token from magic link, updates subscriber\n * password and status, and performs login to set auth cookies.\n *\n * @param req - Payload request; body must include `email` and `token`\n * @returns 200 with `message`, `now` and Set-Cookie on success; 400 with `error` and `now` on bad data, invalid token, or expiry\n */\n const verifyMagicLinkHandler: PayloadHandler = async (req) => {\n // req.payload.logger.info('verifyMagicLinkHandler')\n const reqData = req?.json ? await req.json() : {}\n const { email, token }: { email: string; token: string } = reqData // if by POST reqData\n // const { email, token } = req.routeParams // if by path\n\n if (!email || !token) {\n req.payload.logger.info('verifyMagicLinkHandler Bad data')\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n const userResults = await req.payload.find({\n collection: subscribersCollectionSlug,\n where: {\n email: { equals: email },\n },\n })\n\n type SubscriberType = {\n // @ts-expect-error Why is this not correct, isn't it how Payload does it?\n collection: subscribersCollectionSlug\n } & Subscriber\n\n const user = userResults.docs[0] as SubscriberType\n\n if (!user) {\n req.payload.logger.info('verifyMagicLinkHandler no user')\n return Response.json(\n { error: 'Bad data', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n const { tokenHash } = getHash(token)\n\n // req.payload.logger.info(\n // `verifyMagicLinkHandler ${email} \\n ${tokenHash} \\n ${user.verificationTokenExpires} \\n ${user.verificationToken}`,\n // )\n if (!user.verificationTokenExpires || tokenHash != user.verificationToken) {\n req.payload.logger.info(`Token not verified: ${tokenHash} != ${user.verificationToken}`)\n return Response.json(\n { error: 'Token not verified', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n if (new Date(Date.now()) > new Date(user.verificationTokenExpires)) {\n req.payload.logger.info('verifyMagicLinkHandler Token expired')\n return Response.json(\n { error: 'Token expired', now: new Date().toISOString() } as VerifyMagicLinkResponse,\n { status: 400 },\n )\n }\n\n // req.payload.logger.info(\n // `verifyMagicLinkHandler user found and token validated, prepping to authencticate ${user.email}`,\n // )\n // Update user with token password\n await req.payload.update({\n collection: subscribersCollectionSlug,\n data: {\n password: tokenHash,\n },\n disableTransaction: true,\n where: {\n email: { equals: user.email },\n },\n })\n // req.payload.logger.info(\n // 'verifyMagicLinkHandler user found and token validated, prepping to authencticate DONE',\n // )\n\n // Log the user in via Payload headers\n let headers\n try {\n const loginReq = await fetch(\n `${req.payload.config.serverURL}/api/${subscribersCollectionSlug}/login`,\n {\n body: JSON.stringify({\n email,\n password: tokenHash,\n }),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n },\n )\n if (loginReq && loginReq.ok) {\n headers = loginReq.headers\n }\n } catch (error) {\n // console.log(error)\n req.payload.logger.info(\n `verifyMagicLinkHandler catch error ${JSON.stringify(error, undefined, 2)}`,\n )\n throw new Error(\n `verifyMagicLinkHandler catch error: ${JSON.stringify(error, undefined, 2)}`,\n { cause: error },\n )\n // return Response.json({ error } as VerifyMagicLinkResponse, { status: 400 })\n }\n\n const status: 'pending' | 'subscribed' | 'unsubscribed' | undefined =\n user?.status == 'pending' ? 'subscribed' : user?.status\n\n const { tokenHash: tokenHash2 } = getTokenAndHash() // Unknowable\n const data = {\n password: tokenHash2,\n status,\n verificationToken: '',\n verificationTokenExpires: null,\n }\n let updateResult\n try {\n // Update user\n updateResult = await req.payload.update({\n collection: subscribersCollectionSlug,\n data,\n where: {\n email: { equals: user.email },\n },\n })\n } catch (error) {\n // console.log(error)\n req.payload.logger.info(\n `verifyMagicLinkHandler update catch error ${JSON.stringify(error, undefined, 2)}`,\n )\n throw new Error(\n `verifyMagicLinkHandler update catch error: ${JSON.stringify(error, undefined, 2)}`,\n { cause: error },\n )\n // return Response.json({ error } as VerifyMagicLinkResponse, { status: 400 })\n }\n\n function keepOnlySetCookie(originalHeaders: Headers): Headers {\n // Use getSetCookie() to get all values as an array\n const setCookieValues = originalHeaders.getSetCookie()\n\n // Create a new Headers object\n const newHeaders = new Headers()\n\n // Append each 'set-cookie' value individually\n for (const cookieValue of setCookieValues) {\n newHeaders.append('set-cookie', cookieValue)\n }\n\n return newHeaders\n }\n\n const newHeaders = headers ? keepOnlySetCookie(headers) : undefined\n // req.payload.logger.info(\n // `verifyMagicLinkHandler headers ${JSON.stringify(headers?.entries(), undefined, 2)}`,\n // )\n // req.payload.logger.info(\n // `verifyMagicLinkHandler newHeaders ${JSON.stringify(newHeaders?.entries(), undefined, 2)}`,\n // )\n\n return Response.json(\n {\n message: 'Token verified',\n now: new Date().toISOString(),\n } as VerifyMagicLinkResponse,\n { headers: newHeaders },\n )\n }\n\n /** Endpoint config for verifying magic link and logging in. Mount as POST /verifyToken. */\n const verifyMagicLinkEndpoint: Endpoint = {\n handler: verifyMagicLinkHandler,\n method: 'post',\n path: '/verifyToken',\n }\n\n return verifyMagicLinkEndpoint\n}\n\nexport default createEndpointVerifyMagicLink\n"],"names":["defaultCollectionSlug","getHash","getTokenAndHash","createEndpointVerifyMagicLink","subscribersCollectionSlug","verifyMagicLinkHandler","req","reqData","json","email","token","payload","logger","info","Response","error","now","Date","toISOString","status","userResults","find","collection","where","equals","user","docs","tokenHash","verificationTokenExpires","verificationToken","update","data","password","disableTransaction","headers","loginReq","fetch","config","serverURL","body","JSON","stringify","credentials","method","ok","undefined","Error","cause","tokenHash2","updateResult","keepOnlySetCookie","originalHeaders","setCookieValues","getSetCookie","newHeaders","Headers","cookieValue","append","message","verifyMagicLinkEndpoint","handler","path"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { VerifyMagicLinkResponse } from '../endpoints/verifyMagicLink.js';
|
|
2
2
|
export { VerifyMagicLinkResponse };
|
|
3
|
+
type VerifyStatus = 'default' | 'error' | 'verified' | 'verifying';
|
|
3
4
|
/**
|
|
4
5
|
* Return value of useVerifyMagicLink.
|
|
5
6
|
*
|
|
@@ -12,6 +13,7 @@ export interface IUseVerifyMagicLink {
|
|
|
12
13
|
isError: boolean;
|
|
13
14
|
isLoading: boolean;
|
|
14
15
|
result: string;
|
|
16
|
+
status: VerifyStatus;
|
|
15
17
|
verify: () => void;
|
|
16
18
|
}
|
|
17
19
|
/**
|
|
@@ -25,6 +27,7 @@ export declare const useVerifyMagicLink: () => {
|
|
|
25
27
|
isError: boolean;
|
|
26
28
|
isLoading: boolean;
|
|
27
29
|
result: string;
|
|
30
|
+
status: VerifyStatus;
|
|
28
31
|
verify: () => Promise<{
|
|
29
32
|
error: string;
|
|
30
33
|
} | undefined>;
|
|
@@ -16,9 +16,11 @@ import { useServerUrl } from '../react-hooks/useServerUrl.js';
|
|
|
16
16
|
const email = searchParams.get('email');
|
|
17
17
|
const token = searchParams.get('token');
|
|
18
18
|
const [result, setResult] = useState();
|
|
19
|
+
const [status, setStatus] = useState('default');
|
|
19
20
|
const [isError, setIsError] = useState(false);
|
|
20
21
|
// const [email, setEmail] = useState('')
|
|
21
22
|
const verify = useCallback(async ()=>{
|
|
23
|
+
setStatus('verifying');
|
|
22
24
|
if (!email || !token) {
|
|
23
25
|
return {
|
|
24
26
|
error: 'Invalid input'
|
|
@@ -38,20 +40,24 @@ import { useServerUrl } from '../react-hooks/useServerUrl.js';
|
|
|
38
40
|
});
|
|
39
41
|
if (verifyEndpointResult && verifyEndpointResult.json) {
|
|
40
42
|
const resultJson = await verifyEndpointResult.json();
|
|
41
|
-
setResult(resultJson.error || resultJson.message);
|
|
42
43
|
setIsError(!!resultJson.error);
|
|
44
|
+
setResult(resultJson.error || resultJson.message);
|
|
45
|
+
setStatus(resultJson.error ? 'error' : 'verified');
|
|
43
46
|
// return { error: resultJson.error, message: resultJson.message }
|
|
44
47
|
} else if (verifyEndpointResult && verifyEndpointResult.text) {
|
|
45
48
|
const resultText = await verifyEndpointResult.text();
|
|
46
|
-
setResult(resultText);
|
|
47
49
|
setIsError(true);
|
|
50
|
+
setResult(resultText);
|
|
51
|
+
setStatus('error');
|
|
48
52
|
} else {
|
|
49
|
-
setResult(`Error: ${verifyEndpointResult.status}`);
|
|
50
53
|
setIsError(true);
|
|
54
|
+
setResult(`Error: ${verifyEndpointResult.status}`);
|
|
55
|
+
setStatus('error');
|
|
51
56
|
}
|
|
52
57
|
} catch (error) {
|
|
53
|
-
setResult(`Error: ${error}`);
|
|
54
58
|
setIsError(true);
|
|
59
|
+
setResult(`Error: ${error}`);
|
|
60
|
+
setStatus('error');
|
|
55
61
|
}
|
|
56
62
|
if (!isError) {
|
|
57
63
|
refreshSubscriber();
|
|
@@ -67,6 +73,7 @@ import { useServerUrl } from '../react-hooks/useServerUrl.js';
|
|
|
67
73
|
isError,
|
|
68
74
|
isLoading: !result,
|
|
69
75
|
result: result || '',
|
|
76
|
+
status,
|
|
70
77
|
verify
|
|
71
78
|
};
|
|
72
79
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/hooks/useVerifyMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { useSearchParams } from 'next/navigation.js'\nimport { useCallback, useState } from 'react'\n\nimport type { VerifyMagicLinkResponse } from '../endpoints/verifyMagicLink.js'\n\nexport { VerifyMagicLinkResponse }\nimport { useSubscriber } from '../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\n/**\n * Return value of useVerifyMagicLink.\n *\n * @property isError - True if the last verify attempt failed\n * @property isLoading - True until verify has been run and has a result\n * @property result - Result message from the last verify attempt\n * @property verify - Calls POST /api/verifyToken with email and token from URL search params\n */\nexport interface IUseVerifyMagicLink {\n isError: boolean\n isLoading: boolean\n result: string\n verify: () => void\n}\n\n/**\n * Hook for the verify step of the magic-link flow. Reads email and token from URL search params,\n * calls POST /api/verifyToken to verify and log in, and refreshes subscriber on success.\n * Takes no parameters.\n *\n * @returns verify function plus isLoading, isError, and result (see IUseVerifyMagicLink)\n */\nexport const useVerifyMagicLink = () => {\n const { serverURL } = useServerUrl()\n\n const { refreshSubscriber } = useSubscriber()\n\n const searchParams = useSearchParams()\n const email = searchParams.get('email')\n const token = searchParams.get('token')\n\n const [result, setResult] = useState<string>()\n const [isError, setIsError] = useState<boolean>(false)\n // const [email, setEmail] = useState('')\n\n const verify = useCallback(async () => {\n if (!email || !token) {\n return { error: 'Invalid input' }\n }\n try {\n // I tried using PayloadSDK.request, but when the endpoint\n // returns a not-okay status, PayloadSDK.request returns its\n // own \"Bad request\" error, and doesn't share the endpoint\n // result data.\n const verifyEndpointResult = await fetch(`${serverURL ? serverURL : ''}/api/verifyToken`, {\n body: JSON.stringify({\n email,\n token,\n }),\n method: 'POST',\n })\n\n if (verifyEndpointResult && verifyEndpointResult.json) {\n const resultJson = await verifyEndpointResult.json()\n setResult(resultJson.error || resultJson.message)\n
|
|
1
|
+
{"version":3,"sources":["../../src/hooks/useVerifyMagicLink.tsx"],"sourcesContent":["'use client'\n\nimport { useSearchParams } from 'next/navigation.js'\nimport { useCallback, useState } from 'react'\n\nimport type { VerifyMagicLinkResponse } from '../endpoints/verifyMagicLink.js'\n\nexport { VerifyMagicLinkResponse }\nimport { useSubscriber } from '../contexts/SubscriberProvider.js'\nimport { useServerUrl } from '../react-hooks/useServerUrl.js'\n\ntype VerifyStatus = 'default' | 'error' | 'verified' | 'verifying'\n\n/**\n * Return value of useVerifyMagicLink.\n *\n * @property isError - True if the last verify attempt failed\n * @property isLoading - True until verify has been run and has a result\n * @property result - Result message from the last verify attempt\n * @property verify - Calls POST /api/verifyToken with email and token from URL search params\n */\nexport interface IUseVerifyMagicLink {\n isError: boolean\n isLoading: boolean\n result: string\n status: VerifyStatus\n verify: () => void\n}\n\n/**\n * Hook for the verify step of the magic-link flow. Reads email and token from URL search params,\n * calls POST /api/verifyToken to verify and log in, and refreshes subscriber on success.\n * Takes no parameters.\n *\n * @returns verify function plus isLoading, isError, and result (see IUseVerifyMagicLink)\n */\nexport const useVerifyMagicLink = () => {\n const { serverURL } = useServerUrl()\n\n const { refreshSubscriber } = useSubscriber()\n\n const searchParams = useSearchParams()\n const email = searchParams.get('email')\n const token = searchParams.get('token')\n\n const [result, setResult] = useState<string>()\n const [status, setStatus] = useState<VerifyStatus>('default')\n const [isError, setIsError] = useState<boolean>(false)\n // const [email, setEmail] = useState('')\n\n const verify = useCallback(async () => {\n setStatus('verifying')\n if (!email || !token) {\n return { error: 'Invalid input' }\n }\n try {\n // I tried using PayloadSDK.request, but when the endpoint\n // returns a not-okay status, PayloadSDK.request returns its\n // own \"Bad request\" error, and doesn't share the endpoint\n // result data.\n const verifyEndpointResult = await fetch(`${serverURL ? serverURL : ''}/api/verifyToken`, {\n body: JSON.stringify({\n email,\n token,\n }),\n method: 'POST',\n })\n\n if (verifyEndpointResult && verifyEndpointResult.json) {\n const resultJson = await verifyEndpointResult.json()\n setIsError(!!resultJson.error)\n setResult(resultJson.error || resultJson.message)\n setStatus(resultJson.error ? 'error' : 'verified')\n // return { error: resultJson.error, message: resultJson.message }\n } else if (verifyEndpointResult && verifyEndpointResult.text) {\n const resultText = await verifyEndpointResult.text()\n setIsError(true)\n setResult(resultText)\n setStatus('error')\n } else {\n setIsError(true)\n setResult(`Error: ${verifyEndpointResult.status}`)\n setStatus('error')\n }\n } catch (error: unknown) {\n setIsError(true)\n setResult(`Error: ${error}`)\n setStatus('error')\n }\n if (!isError) {\n refreshSubscriber()\n }\n }, [email, isError, refreshSubscriber, serverURL, token])\n\n return {\n isError,\n isLoading: !result,\n result: result || '',\n status,\n verify,\n }\n}\n"],"names":["useSearchParams","useCallback","useState","useSubscriber","useServerUrl","useVerifyMagicLink","serverURL","refreshSubscriber","searchParams","email","get","token","result","setResult","status","setStatus","isError","setIsError","verify","error","verifyEndpointResult","fetch","body","JSON","stringify","method","json","resultJson","message","text","resultText","isLoading"],"mappings":"AAAA;AAEA,SAASA,eAAe,QAAQ,qBAAoB;AACpD,SAASC,WAAW,EAAEC,QAAQ,QAAQ,QAAO;AAK7C,SAASC,aAAa,QAAQ,oCAAmC;AACjE,SAASC,YAAY,QAAQ,iCAAgC;AAoB7D;;;;;;CAMC,GACD,OAAO,MAAMC,qBAAqB;IAChC,MAAM,EAAEC,SAAS,EAAE,GAAGF;IAEtB,MAAM,EAAEG,iBAAiB,EAAE,GAAGJ;IAE9B,MAAMK,eAAeR;IACrB,MAAMS,QAAQD,aAAaE,GAAG,CAAC;IAC/B,MAAMC,QAAQH,aAAaE,GAAG,CAAC;IAE/B,MAAM,CAACE,QAAQC,UAAU,GAAGX;IAC5B,MAAM,CAACY,QAAQC,UAAU,GAAGb,SAAuB;IACnD,MAAM,CAACc,SAASC,WAAW,GAAGf,SAAkB;IAChD,yCAAyC;IAEzC,MAAMgB,SAASjB,YAAY;QACzBc,UAAU;QACV,IAAI,CAACN,SAAS,CAACE,OAAO;YACpB,OAAO;gBAAEQ,OAAO;YAAgB;QAClC;QACA,IAAI;YACF,0DAA0D;YAC1D,4DAA4D;YAC5D,0DAA0D;YAC1D,eAAe;YACf,MAAMC,uBAAuB,MAAMC,MAAM,GAAGf,YAAYA,YAAY,GAAG,gBAAgB,CAAC,EAAE;gBACxFgB,MAAMC,KAAKC,SAAS,CAAC;oBACnBf;oBACAE;gBACF;gBACAc,QAAQ;YACV;YAEA,IAAIL,wBAAwBA,qBAAqBM,IAAI,EAAE;gBACrD,MAAMC,aAAa,MAAMP,qBAAqBM,IAAI;gBAClDT,WAAW,CAAC,CAACU,WAAWR,KAAK;gBAC7BN,UAAUc,WAAWR,KAAK,IAAIQ,WAAWC,OAAO;gBAChDb,UAAUY,WAAWR,KAAK,GAAG,UAAU;YACvC,kEAAkE;YACpE,OAAO,IAAIC,wBAAwBA,qBAAqBS,IAAI,EAAE;gBAC5D,MAAMC,aAAa,MAAMV,qBAAqBS,IAAI;gBAClDZ,WAAW;gBACXJ,UAAUiB;gBACVf,UAAU;YACZ,OAAO;gBACLE,WAAW;gBACXJ,UAAU,CAAC,OAAO,EAAEO,qBAAqBN,MAAM,EAAE;gBACjDC,UAAU;YACZ;QACF,EAAE,OAAOI,OAAgB;YACvBF,WAAW;YACXJ,UAAU,CAAC,OAAO,EAAEM,OAAO;YAC3BJ,UAAU;QACZ;QACA,IAAI,CAACC,SAAS;YACZT;QACF;IACF,GAAG;QAACE;QAAOO;QAAST;QAAmBD;QAAWK;KAAM;IAExD,OAAO;QACLK;QACAe,WAAW,CAACnB;QACZA,QAAQA,UAAU;QAClBE;QACAI;IACF;AACF,EAAC"}
|
|
@@ -3,7 +3,7 @@ const getServerSideURL = ()=>{
|
|
|
3
3
|
const serverSideURL = process.env.NEXT_PUBLIC_VERCEL_URL ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` : process.env.VERCEL_PROJECT_PRODUCTION_URL ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}` : process.env.NEXT_PUBLIC_DEV_URL ? `http://${process.env.NEXT_PUBLIC_DEV_URL}` : 'http://localhost:3000';
|
|
4
4
|
// console.log(`process.env.NEXT_PUBLIC_DEV_URL: ${process.env.NEXT_PUBLIC_DEV_URL}`)
|
|
5
5
|
// console.log(`serverSideURL: ${serverSideURL}`)
|
|
6
|
-
return serverSideURL;
|
|
6
|
+
return serverSideURL || '';
|
|
7
7
|
};
|
|
8
8
|
// const canUseDOM = !!(
|
|
9
9
|
// typeof window !== 'undefined' &&
|
|
@@ -22,6 +22,7 @@ const getServerSideURL = ()=>{
|
|
|
22
22
|
// }
|
|
23
23
|
// return getServerSideURL()
|
|
24
24
|
// }
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
25
26
|
export const getServerUrl = async ()=>{
|
|
26
27
|
return {
|
|
27
28
|
serverURL: getServerSideURL()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server-functions/serverUrl.ts"],"sourcesContent":["'use server'\n\nconst getServerSideURL = () => {\n const serverSideURL = process.env.NEXT_PUBLIC_VERCEL_URL\n ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`\n : process.env.VERCEL_PROJECT_PRODUCTION_URL\n ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`\n : process.env.NEXT_PUBLIC_DEV_URL\n ? `http://${process.env.NEXT_PUBLIC_DEV_URL}`\n : 'http://localhost:3000'\n // console.log(`process.env.NEXT_PUBLIC_DEV_URL: ${process.env.NEXT_PUBLIC_DEV_URL}`)\n // console.log(`serverSideURL: ${serverSideURL}`)\n return serverSideURL\n}\n\n// const canUseDOM = !!(\n// typeof window !== 'undefined' &&\n// window.document &&\n// window.document.createElement\n// )\n\n// const getClientSideURL = () => {\n// if (canUseDOM) {\n// const protocol = window.location.protocol\n// const domain = window.location.hostname\n// const port = window.location.port\n// // `${window.location.protocol}//${window.location.host}\n// const clientSideURL = `${protocol}//${domain}${port ? `:${port}` : ''}`\n// // console.log(`clientSideURL: ${clientSideURL}`)\n// return clientSideURL\n// }\n\n// return getServerSideURL()\n// }\n\nexport const getServerUrl = async (): Promise<{ serverURL: string }> => {\n return { serverURL: getServerSideURL() }\n}\n"],"names":["getServerSideURL","serverSideURL","process","env","NEXT_PUBLIC_VERCEL_URL","VERCEL_PROJECT_PRODUCTION_URL","NEXT_PUBLIC_DEV_URL","getServerUrl","serverURL"],"mappings":"AAAA;AAEA,MAAMA,mBAAmB;IACvB,MAAMC,gBAAgBC,QAAQC,GAAG,CAACC,sBAAsB,GACpD,CAAC,QAAQ,EAAEF,QAAQC,GAAG,CAACC,sBAAsB,EAAE,GAC/CF,QAAQC,GAAG,CAACE,6BAA6B,GACvC,CAAC,QAAQ,EAAEH,QAAQC,GAAG,CAACE,6BAA6B,EAAE,GACtDH,QAAQC,GAAG,CAACG,mBAAmB,GAC7B,CAAC,OAAO,EAAEJ,QAAQC,GAAG,CAACG,mBAAmB,EAAE,GAC3C;IACR,qFAAqF;IACrF,iDAAiD;IACjD,OAAOL;
|
|
1
|
+
{"version":3,"sources":["../../src/server-functions/serverUrl.ts"],"sourcesContent":["'use server'\n\nconst getServerSideURL = () => {\n const serverSideURL = process.env.NEXT_PUBLIC_VERCEL_URL\n ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`\n : process.env.VERCEL_PROJECT_PRODUCTION_URL\n ? `https://${process.env.VERCEL_PROJECT_PRODUCTION_URL}`\n : process.env.NEXT_PUBLIC_DEV_URL\n ? `http://${process.env.NEXT_PUBLIC_DEV_URL}`\n : 'http://localhost:3000'\n // console.log(`process.env.NEXT_PUBLIC_DEV_URL: ${process.env.NEXT_PUBLIC_DEV_URL}`)\n // console.log(`serverSideURL: ${serverSideURL}`)\n return serverSideURL || ''\n}\n\n// const canUseDOM = !!(\n// typeof window !== 'undefined' &&\n// window.document &&\n// window.document.createElement\n// )\n\n// const getClientSideURL = () => {\n// if (canUseDOM) {\n// const protocol = window.location.protocol\n// const domain = window.location.hostname\n// const port = window.location.port\n// // `${window.location.protocol}//${window.location.host}\n// const clientSideURL = `${protocol}//${domain}${port ? `:${port}` : ''}`\n// // console.log(`clientSideURL: ${clientSideURL}`)\n// return clientSideURL\n// }\n\n// return getServerSideURL()\n// }\n\n// eslint-disable-next-line @typescript-eslint/require-await\nexport const getServerUrl = async (): Promise<{ serverURL: string }> => {\n return { serverURL: getServerSideURL() }\n}\n"],"names":["getServerSideURL","serverSideURL","process","env","NEXT_PUBLIC_VERCEL_URL","VERCEL_PROJECT_PRODUCTION_URL","NEXT_PUBLIC_DEV_URL","getServerUrl","serverURL"],"mappings":"AAAA;AAEA,MAAMA,mBAAmB;IACvB,MAAMC,gBAAgBC,QAAQC,GAAG,CAACC,sBAAsB,GACpD,CAAC,QAAQ,EAAEF,QAAQC,GAAG,CAACC,sBAAsB,EAAE,GAC/CF,QAAQC,GAAG,CAACE,6BAA6B,GACvC,CAAC,QAAQ,EAAEH,QAAQC,GAAG,CAACE,6BAA6B,EAAE,GACtDH,QAAQC,GAAG,CAACG,mBAAmB,GAC7B,CAAC,OAAO,EAAEJ,QAAQC,GAAG,CAACG,mBAAmB,EAAE,GAC3C;IACR,qFAAqF;IACrF,iDAAiD;IACjD,OAAOL,iBAAiB;AAC1B;AAEA,wBAAwB;AACxB,qCAAqC;AACrC,uBAAuB;AACvB,kCAAkC;AAClC,IAAI;AAEJ,mCAAmC;AACnC,qBAAqB;AACrB,gDAAgD;AAChD,8CAA8C;AAC9C,wCAAwC;AACxC,+DAA+D;AAC/D,8EAA8E;AAC9E,wDAAwD;AACxD,2BAA2B;AAC3B,MAAM;AAEN,8BAA8B;AAC9B,IAAI;AAEJ,4DAA4D;AAC5D,OAAO,MAAMM,eAAe;IAC1B,OAAO;QAAEC,WAAWR;IAAmB;AACzC,EAAC"}
|
package/package.json
CHANGED
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"registry": "https://registry.npmjs.org/",
|
|
71
71
|
"dependencies": {},
|
|
72
|
-
"version": "0.0.
|
|
72
|
+
"version": "0.0.17",
|
|
73
73
|
"scripts": {
|
|
74
74
|
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
75
75
|
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|