payload-subscribers-plugin 0.0.1 → 0.0.5
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/LICENSE +21 -0
- package/README.md +38 -2
- package/dist/collections/Subscribers.js +0 -5
- package/dist/collections/Subscribers.js.map +1 -1
- package/dist/components/app/SubscriberMenu.js +35 -18
- package/dist/components/app/SubscriberMenu.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -3
- package/dist/components/BeforeDashboardClient.d.ts +0 -1
- package/dist/components/BeforeDashboardClient.js +0 -40
- package/dist/components/BeforeDashboardClient.js.map +0 -1
- package/dist/components/BeforeDashboardServer.d.ts +0 -2
- package/dist/components/BeforeDashboardServer.js +0 -22
- package/dist/components/BeforeDashboardServer.js.map +0 -1
- package/dist/components/BeforeDashboardServer.module.css +0 -5
- package/dist/components/app/RequestMagicLink.module.css +0 -5
- package/dist/components/app/SelectOptInChannels.module.css +0 -5
- package/dist/components/app/Subscribe.module.css +0 -5
- package/dist/components/app/VerifyMagicLink.module.css +0 -5
- package/dist/copied/payload.config.d.ts +0 -2
- package/dist/endpoints/customEndpointHandler.d.ts +0 -2
- package/dist/endpoints/customEndpointHandler.js +0 -7
- package/dist/endpoints/customEndpointHandler.js.map +0 -1
- package/dist/exports/client.d.ts +0 -1
- package/dist/exports/client.js +0 -3
- package/dist/exports/client.js.map +0 -1
- package/dist/exports/rsc.d.ts +0 -1
- package/dist/exports/rsc.js +0 -3
- package/dist/exports/rsc.js.map +0 -1
- package/dist/helpers/serverConfig.d.ts +0 -4
- package/dist/helpers/serverConfig.js +0 -22
- package/dist/helpers/serverConfig.js.map +0 -1
- package/dist/server-functions/subscriberAuth.d.ts +0 -11
- package/src/collections/OptInChannels.ts +0 -45
- package/src/collections/Subscribers.ts +0 -99
- package/src/collections/fields/OptedInChannels.ts +0 -12
- package/src/components/app/RequestMagicLink.tsx +0 -129
- package/src/components/app/RequestOrSubscribe.tsx +0 -58
- package/src/components/app/SelectOptInChannels.tsx +0 -147
- package/src/components/app/Subscribe.tsx +0 -190
- package/src/components/app/SubscriberMenu.tsx +0 -46
- package/src/components/app/VerifyMagicLink.tsx +0 -197
- package/src/components/app/helpers.ts +0 -6
- package/src/components/app/shared.module.css +0 -14
- package/src/contexts/SubscriberProvider.tsx +0 -122
- package/src/copied/payload-types.ts +0 -478
- package/src/endpoints/getOptInChannels.ts +0 -56
- package/src/endpoints/logout.ts +0 -104
- package/src/endpoints/requestMagicLink.ts +0 -139
- package/src/endpoints/subscribe.ts +0 -435
- package/src/endpoints/subscriberAuth.ts +0 -100
- package/src/endpoints/verifyMagicLink.ts +0 -164
- package/src/exports/index.ts +0 -1
- package/src/exports/ui.ts +0 -17
- package/src/helpers/testData.ts +0 -2
- package/src/helpers/token.ts +0 -14
- package/src/helpers/verifyOptIns.ts +0 -39
- package/src/index.ts +0 -207
- package/src/react-hooks/useServerUrl.tsx +0 -18
- package/src/server-functions/serverUrl.ts +0 -38
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 C C C
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
A plugin to manage subscribers and the "channels" they can subscribe to.
|
|
4
4
|
|
|
5
|
+
This includes ways to allow your subscribers to:
|
|
6
|
+
* Sign up or sign in by requesting a magic link email
|
|
7
|
+
* Verify the magic link to authenticate
|
|
8
|
+
* Opt in or out of "opt-in channels"
|
|
9
|
+
|
|
10
|
+
You manage the opt-in channels via the Payload admin.
|
|
11
|
+
|
|
12
|
+
The plugin relies on your email adapter configured in your payload config to send emails.
|
|
13
|
+
|
|
14
|
+
That is all this plugin does currently. Potential features might include email authoring and send scheduler or simple CRM features.
|
|
15
|
+
|
|
16
|
+
|
|
5
17
|
## Installation
|
|
6
18
|
|
|
7
19
|
```bash
|
|
@@ -10,6 +22,8 @@ pnpm add payload-subscribers-plugin
|
|
|
10
22
|
|
|
11
23
|
## Usage
|
|
12
24
|
|
|
25
|
+
You need to have an email adapter configured in your Payload config.
|
|
26
|
+
|
|
13
27
|
Add the plugin to your Payload config.
|
|
14
28
|
|
|
15
29
|
```typescript
|
|
@@ -18,12 +32,22 @@ Add the plugin to your Payload config.
|
|
|
18
32
|
export default buildConfig({
|
|
19
33
|
plugins: [
|
|
20
34
|
payloadSubscribersPlugin({
|
|
35
|
+
|
|
36
|
+
// Add slugs of your collections which should have a relationship field to the optInChannels.
|
|
21
37
|
collections: {
|
|
22
|
-
// Add slugs of your collections which should have a relationship field to the optInChannels.
|
|
23
38
|
posts: true,
|
|
24
39
|
},
|
|
40
|
+
|
|
25
41
|
// Easily disable the collection logic.
|
|
26
42
|
disabled: false,
|
|
43
|
+
|
|
44
|
+
// Specify the collection to use as the subscribers collection
|
|
45
|
+
// - Optional. If not specified, the plugin will add a 'subscribers' collection.
|
|
46
|
+
// - Sets auth if not already
|
|
47
|
+
// - Adds (or overrides) fields: email, firstName, status, optIns,
|
|
48
|
+
// verificationToken, verificationTokenExpires, and source
|
|
49
|
+
subscribersCollectionSlug?: CollectionSlug
|
|
50
|
+
|
|
27
51
|
// Provide a custom expiration for magic link tokens. The default is 30 minutes.
|
|
28
52
|
tokenExpiration: 60 * 60,
|
|
29
53
|
}),
|
|
@@ -172,7 +196,7 @@ The **subscribe** endpoint will remove all optIns. But need a way to set the sub
|
|
|
172
196
|
|
|
173
197
|
#### **RequestOrSubscribe**
|
|
174
198
|
|
|
175
|
-
Shows Subscribe to authenticated subscribers, otherwise shows RequestMagicLink.
|
|
199
|
+
Shows the [Subscribe](#subscribe) component to authenticated subscribers, otherwise shows [RequestMagicLink](#RequestMagicLink).
|
|
176
200
|
|
|
177
201
|
<!-- <div style="border: 1px solid #ccc; padding: 15px; border-radius: 5px;">
|
|
178
202
|
</div> -->
|
|
@@ -207,6 +231,8 @@ Shows Subscribe to authenticated subscribers, otherwise shows RequestMagicLink.
|
|
|
207
231
|
|
|
208
232
|
Form to input email address and get a magic link email sent.
|
|
209
233
|
|
|
234
|
+
<img src="./docs/images/RequestMagicLink.png" alt="RequestMagicLink" style="max-width: 500px; width: 100%;">
|
|
235
|
+
|
|
210
236
|
```typescript
|
|
211
237
|
<RequestMagicLink
|
|
212
238
|
// Provide your own global class names to add to the component elements. Optional
|
|
@@ -233,6 +259,8 @@ Form to input email address and get a magic link email sent.
|
|
|
233
259
|
|
|
234
260
|
Component that verifies a magic link using expected url parameters.
|
|
235
261
|
|
|
262
|
+
<img src="./docs/images/VerifyMagicLink.png" alt="VerifyMagicLink" style="max-width: 500px; width: 100%;">
|
|
263
|
+
|
|
236
264
|
```typescript
|
|
237
265
|
<VerifyMagicLink
|
|
238
266
|
// Provide your own global class names to add to the component elements. Optional
|
|
@@ -269,6 +297,8 @@ Component that verifies a magic link using expected url parameters.
|
|
|
269
297
|
|
|
270
298
|
Allows a subscriber to select from among all active optInChannels.
|
|
271
299
|
|
|
300
|
+
<img src="./docs/images/Subscribe.png" alt="Subscribe" style="max-width: 500px; width: 100%;">
|
|
301
|
+
|
|
272
302
|
```typescript
|
|
273
303
|
<Subscribe
|
|
274
304
|
// Provide your own global class names to add to the component elements. Optional
|
|
@@ -295,6 +325,8 @@ Allows a subscriber to select from among all active optInChannels.
|
|
|
295
325
|
|
|
296
326
|
#### **SubscriberMenu**
|
|
297
327
|
|
|
328
|
+
A simple user menu, most useful for testing. Seen in the screenshots above. Includes a "welcome" message, a link to a /subscribe route, and a log out button.
|
|
329
|
+
|
|
298
330
|
```typescript
|
|
299
331
|
// classNames prop
|
|
300
332
|
|
|
@@ -303,3 +335,7 @@ export type SubscriberMenuClasses = {
|
|
|
303
335
|
container?: string
|
|
304
336
|
}
|
|
305
337
|
```
|
|
338
|
+
|
|
339
|
+
## Contributing
|
|
340
|
+
|
|
341
|
+
Community contributions are welcome! I haven't organized around that yet, so let me know if you're interested by opening an issue on the GitHub repo.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/collections/Subscribers.ts"],"sourcesContent":["import type { CollectionConfig, CollectionSlug, Field } from 'payload'\n\nimport { OptedInChannels } from './fields/OptedInChannels.js'\n\nexport const defaultTokenExpiration = 30 * 60 // 30 minutes\n\nexport const defaultCollectionSlug = 'subscribers'\n\nexport const SubscribersCollectionFactory = ({\n slug,\n tokenExpiration = defaultTokenExpiration,\n}: {\n slug?: CollectionSlug\n tokenExpiration?: number\n}) => {\n const Subscribers: CollectionConfig = {\n slug: slug ? slug : defaultCollectionSlug,\n access: {\n // Public access for creation (signup form)\n create: () => true,\n // Admin-only access for reading, updating, and deleting\n delete: ({ req }) => (req.user ? true : false),\n read: ({ req }) => (req.user ? true : false),\n update: ({ req }) => (req.user ? true : false),\n },\n admin: { useAsTitle: 'email' },\n auth: {\n tokenExpiration,\n // verify: true, // Require email verification before being allowed to authenticate\n // maxLoginAttempts: 5, // Automatically lock a user out after X amount of failed logins\n // lockTime: 600 * 1000, // Time period to allow the max login attempts\n },\n fields: [...subscribersCollectionFields],\n }\n\n return Subscribers\n}\n\nexport const subscribersCollectionFields: Field[] = [\n {\n name: 'email',\n type: 'email', // Enforces valid email format\n label: 'Email Address',\n required: true,\n unique: true, // Ensures no duplicate emails\n },\n {\n name: 'firstName',\n type: 'text',\n label: 'First Name',\n },\n {\n name: 'status',\n type: 'select',\n defaultValue: 'pending', // Default to pending until verified\n label: 'Subscription Status',\n options: [\n {\n label: 'Subscribed',\n value: 'subscribed',\n },\n {\n label: 'Unsubscribed',\n value: 'unsubscribed',\n },\n {\n label: 'Pending Verification',\n value: 'pending',\n },\n ],\n required: true,\n },\n {\n name: '
|
|
1
|
+
{"version":3,"sources":["../../src/collections/Subscribers.ts"],"sourcesContent":["import type { CollectionConfig, CollectionSlug, Field } from 'payload'\n\nimport { OptedInChannels } from './fields/OptedInChannels.js'\n\nexport const defaultTokenExpiration = 30 * 60 // 30 minutes\n\nexport const defaultCollectionSlug = 'subscribers'\n\nexport const SubscribersCollectionFactory = ({\n slug,\n tokenExpiration = defaultTokenExpiration,\n}: {\n slug?: CollectionSlug\n tokenExpiration?: number\n}) => {\n const Subscribers: CollectionConfig = {\n slug: slug ? slug : defaultCollectionSlug,\n access: {\n // Public access for creation (signup form)\n create: () => true,\n // Admin-only access for reading, updating, and deleting\n delete: ({ req }) => (req.user ? true : false),\n read: ({ req }) => (req.user ? true : false),\n update: ({ req }) => (req.user ? true : false),\n },\n admin: { useAsTitle: 'email' },\n auth: {\n tokenExpiration,\n // verify: true, // Require email verification before being allowed to authenticate\n // maxLoginAttempts: 5, // Automatically lock a user out after X amount of failed logins\n // lockTime: 600 * 1000, // Time period to allow the max login attempts\n },\n fields: [...subscribersCollectionFields],\n }\n\n return Subscribers\n}\n\nexport const subscribersCollectionFields: Field[] = [\n {\n name: 'email',\n type: 'email', // Enforces valid email format\n label: 'Email Address',\n required: true,\n unique: true, // Ensures no duplicate emails\n },\n {\n name: 'firstName',\n type: 'text',\n label: 'First Name',\n },\n {\n name: 'status',\n type: 'select',\n defaultValue: 'pending', // Default to pending until verified\n label: 'Subscription Status',\n options: [\n {\n label: 'Subscribed',\n value: 'subscribed',\n },\n {\n label: 'Unsubscribed',\n value: 'unsubscribed',\n },\n {\n label: 'Pending Verification',\n value: 'pending',\n },\n ],\n required: true,\n },\n {\n name: 'verificationToken',\n type: 'text',\n admin: {\n hidden: true, // Hide this field in the admin panel for security/cleanliness\n },\n label: 'Verification Token',\n },\n {\n name: 'verificationTokenExpires',\n type: 'date',\n admin: {\n hidden: true, // Hide this field in the admin panel for security/cleanliness\n },\n label: 'Verification Token Expiration',\n },\n\n /**\n * Plugin field relationship to optinchannels\n */\n OptedInChannels,\n]\n"],"names":["OptedInChannels","defaultTokenExpiration","defaultCollectionSlug","SubscribersCollectionFactory","slug","tokenExpiration","Subscribers","access","create","delete","req","user","read","update","admin","useAsTitle","auth","fields","subscribersCollectionFields","name","type","label","required","unique","defaultValue","options","value","hidden"],"mappings":"AAEA,SAASA,eAAe,QAAQ,8BAA6B;AAE7D,OAAO,MAAMC,yBAAyB,KAAK,GAAG,aAAa;CAAd;AAE7C,OAAO,MAAMC,wBAAwB,cAAa;AAElD,OAAO,MAAMC,+BAA+B,CAAC,EAC3CC,IAAI,EACJC,kBAAkBJ,sBAAsB,EAIzC;IACC,MAAMK,cAAgC;QACpCF,MAAMA,OAAOA,OAAOF;QACpBK,QAAQ;YACN,2CAA2C;YAC3CC,QAAQ,IAAM;YACd,wDAAwD;YACxDC,QAAQ,CAAC,EAAEC,GAAG,EAAE,GAAMA,IAAIC,IAAI,GAAG,OAAO;YACxCC,MAAM,CAAC,EAAEF,GAAG,EAAE,GAAMA,IAAIC,IAAI,GAAG,OAAO;YACtCE,QAAQ,CAAC,EAAEH,GAAG,EAAE,GAAMA,IAAIC,IAAI,GAAG,OAAO;QAC1C;QACAG,OAAO;YAAEC,YAAY;QAAQ;QAC7BC,MAAM;YACJX;QAIF;QACAY,QAAQ;eAAIC;SAA4B;IAC1C;IAEA,OAAOZ;AACT,EAAC;AAED,OAAO,MAAMY,8BAAuC;IAClD;QACEC,MAAM;QACNC,MAAM;QACNC,OAAO;QACPC,UAAU;QACVC,QAAQ;IACV;IACA;QACEJ,MAAM;QACNC,MAAM;QACNC,OAAO;IACT;IACA;QACEF,MAAM;QACNC,MAAM;QACNI,cAAc;QACdH,OAAO;QACPI,SAAS;YACP;gBACEJ,OAAO;gBACPK,OAAO;YACT;YACA;gBACEL,OAAO;gBACPK,OAAO;YACT;YACA;gBACEL,OAAO;gBACPK,OAAO;YACT;SACD;QACDJ,UAAU;IACZ;IACA;QACEH,MAAM;QACNC,MAAM;QACNN,OAAO;YACLa,QAAQ;QACV;QACAN,OAAO;IACT;IACA;QACEF,MAAM;QACNC,MAAM;QACNN,OAAO;YACLa,QAAQ;QACV;QACAN,OAAO;IACT;IAEA;;GAEC,GACDrB;CACD,CAAA"}
|
|
@@ -14,27 +14,44 @@ export const SubscriberMenu = ({ classNames = {
|
|
|
14
14
|
classNames.container
|
|
15
15
|
]),
|
|
16
16
|
children: subscriber && /*#__PURE__*/ _jsxs("div", {
|
|
17
|
+
style: {
|
|
18
|
+
display: 'flex'
|
|
19
|
+
},
|
|
17
20
|
children: [
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
22
|
+
style: {
|
|
23
|
+
flexGrow: 1
|
|
24
|
+
},
|
|
25
|
+
children: [
|
|
26
|
+
"Welcome, ",
|
|
27
|
+
subscriber?.email
|
|
28
|
+
]
|
|
29
|
+
}),
|
|
30
|
+
/*#__PURE__*/ _jsx("div", {
|
|
31
|
+
style: {
|
|
32
|
+
flexGrow: 1
|
|
33
|
+
},
|
|
34
|
+
children: /*#__PURE__*/ _jsx("a", {
|
|
35
|
+
href: '/subscribe',
|
|
36
|
+
children: "Manage subscriptions"
|
|
37
|
+
})
|
|
24
38
|
}),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
className: mergeClassNames([
|
|
29
|
-
styles.button,
|
|
30
|
-
classNames.button
|
|
31
|
-
]),
|
|
32
|
-
onClick: (e)=>{
|
|
33
|
-
e.preventDefault();
|
|
34
|
-
logOut();
|
|
39
|
+
/*#__PURE__*/ _jsx("div", {
|
|
40
|
+
style: {
|
|
41
|
+
flexGrow: 1
|
|
35
42
|
},
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
children: /*#__PURE__*/ _jsx("button", {
|
|
44
|
+
className: mergeClassNames([
|
|
45
|
+
styles.button,
|
|
46
|
+
classNames.button
|
|
47
|
+
]),
|
|
48
|
+
onClick: (e)=>{
|
|
49
|
+
e.preventDefault();
|
|
50
|
+
logOut();
|
|
51
|
+
},
|
|
52
|
+
type: "button",
|
|
53
|
+
children: "Log out"
|
|
54
|
+
})
|
|
38
55
|
})
|
|
39
56
|
]
|
|
40
57
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/app/SubscriberMenu.tsx"],"sourcesContent":["'use client'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\
|
|
1
|
+
{"version":3,"sources":["../../../src/components/app/SubscriberMenu.tsx"],"sourcesContent":["'use client'\n\nimport { useSubscriber } from '../../contexts/SubscriberProvider.js'\nimport { mergeClassNames } from './helpers.js'\nimport styles from './shared.module.css'\n\n// interface IAuth {\n// props?: any\n// }\n\nexport type SubscriberMenuClasses = {\n button?: string\n container?: string\n}\n\nexport const SubscriberMenu = ({\n classNames = {\n button: '',\n container: '',\n },\n}: {\n classNames?: SubscriberMenuClasses\n}) => {\n const { logOut, subscriber } = useSubscriber()\n return (\n <div className={mergeClassNames([styles.container, classNames.container])}>\n {/* <pre>{JSON.stringify(result, null, 2)}</pre> */}\n {subscriber && (\n <div style={{ display: 'flex' }}>\n <div style={{ flexGrow: 1 }}>Welcome, {subscriber?.email}</div>\n <div style={{ flexGrow: 1 }}>\n <a href={'/subscribe'}>Manage subscriptions</a>\n </div>\n <div style={{ flexGrow: 1 }}>\n <button\n className={mergeClassNames([styles.button, classNames.button])}\n onClick={(e) => {\n e.preventDefault()\n logOut()\n }}\n type=\"button\"\n >\n Log out\n </button>\n </div>\n </div>\n )}\n </div>\n )\n}\n"],"names":["useSubscriber","mergeClassNames","styles","SubscriberMenu","classNames","button","container","logOut","subscriber","div","className","style","display","flexGrow","email","a","href","onClick","e","preventDefault","type"],"mappings":"AAAA;;AAEA,SAASA,aAAa,QAAQ,uCAAsC;AACpE,SAASC,eAAe,QAAQ,eAAc;AAC9C,OAAOC,YAAY,sBAAqB;AAWxC,OAAO,MAAMC,iBAAiB,CAAC,EAC7BC,aAAa;IACXC,QAAQ;IACRC,WAAW;AACb,CAAC,EAGF;IACC,MAAM,EAAEC,MAAM,EAAEC,UAAU,EAAE,GAAGR;IAC/B,qBACE,KAACS;QAAIC,WAAWT,gBAAgB;YAACC,OAAOI,SAAS;YAAEF,WAAWE,SAAS;SAAC;kBAErEE,4BACC,MAACC;YAAIE,OAAO;gBAAEC,SAAS;YAAO;;8BAC5B,MAACH;oBAAIE,OAAO;wBAAEE,UAAU;oBAAE;;wBAAG;wBAAUL,YAAYM;;;8BACnD,KAACL;oBAAIE,OAAO;wBAAEE,UAAU;oBAAE;8BACxB,cAAA,KAACE;wBAAEC,MAAM;kCAAc;;;8BAEzB,KAACP;oBAAIE,OAAO;wBAAEE,UAAU;oBAAE;8BACxB,cAAA,KAACR;wBACCK,WAAWT,gBAAgB;4BAACC,OAAOG,MAAM;4BAAED,WAAWC,MAAM;yBAAC;wBAC7DY,SAAS,CAACC;4BACRA,EAAEC,cAAc;4BAChBZ;wBACF;wBACAa,MAAK;kCACN;;;;;;AAQb,EAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,9 +13,10 @@ export type PayloadSubscribersConfig = {
|
|
|
13
13
|
*/
|
|
14
14
|
disabled?: boolean;
|
|
15
15
|
/**
|
|
16
|
-
* The collection to
|
|
17
|
-
* -
|
|
18
|
-
* -
|
|
16
|
+
* The collection to use as the subscribers collection
|
|
17
|
+
* - Optional. If not specified, the plugin will add a 'subscribers' collection.
|
|
18
|
+
* - Sets the collection auth if not already.
|
|
19
|
+
* - Adds (or overrides) fields: email, firstName, status, optIns, verificationToken, verificationTokenExpires.
|
|
19
20
|
*/
|
|
20
21
|
subscribersCollectionSlug?: CollectionSlug;
|
|
21
22
|
/**
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { BasePayload, CollectionSlug, Config } from 'payload'\n\nimport { OptedInChannels } from './collections/fields/OptedInChannels.js'\nimport OptInChannels from './collections/OptInChannels.js'\nimport {\n defaultTokenExpiration,\n SubscribersCollectionFactory,\n subscribersCollectionFields,\n} from './collections/Subscribers.js'\nimport getOptInChannelsEndpoint from './endpoints/getOptInChannels.js'\nimport createEndpointLogout from './endpoints/logout.js'\nimport createEndpointRequestMagicLink from './endpoints/requestMagicLink.js'\nimport createEndpointSubscribe from './endpoints/subscribe.js'\nimport createEndpointSubscriberAuth from './endpoints/subscriberAuth.js'\nimport createEndpointVerifyMagicLink from './endpoints/verifyMagicLink.js'\nimport { getTestEmail } from './helpers/testData.js'\nimport { getTokenAndHash } from './helpers/token.js'\n\nexport type PayloadSubscribersConfig = {\n /**\n * List of collections to add a custom field\n */\n collections?: Partial<Record<CollectionSlug, true>>\n /**\n * Defaults to false-y. When true:\n * - Database schema changes are still made and seeded\n * - APIs return null or undefined success\n * - Admin components are not added\n * - App components return nothing\n */\n disabled?: boolean\n /**\n * The collection to make the subscribers collection\n * - Set auth if not\n * - Add optIns field\n */\n subscribersCollectionSlug?: CollectionSlug\n /**\n * Defaults to 30 minutes\n */\n tokenExpiration?: number\n}\n\nexport const payloadSubscribersPlugin =\n (pluginOptions: PayloadSubscribersConfig) =>\n (config: Config): Config => {\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(OptInChannels)\n let subscribersCollection = pluginOptions.subscribersCollectionSlug\n ? config.collections.find(\n (collection) => collection.slug == pluginOptions.subscribersCollectionSlug,\n )\n : undefined\n\n if (subscribersCollection) {\n // Configure the input collection to be the subscribers collection\n config.collections = config.collections.filter(\n (collection) => collection.slug != subscribersCollection?.slug,\n )\n subscribersCollection.fields.push(...subscribersCollectionFields)\n if (!subscribersCollection.auth) {\n subscribersCollection = {\n ...subscribersCollection,\n auth: { tokenExpiration: defaultTokenExpiration },\n }\n }\n if (!subscribersCollection.admin?.useAsTitle) {\n if (!subscribersCollection.admin) {\n subscribersCollection.admin = { useAsTitle: 'email' }\n } else {\n // Throw error? Or override?\n subscribersCollection.admin.useAsTitle = 'email'\n }\n }\n config.collections.push(subscribersCollection)\n } else {\n // Configure the default built-in subscribers collection\n subscribersCollection = SubscribersCollectionFactory({\n slug: pluginOptions.subscribersCollectionSlug,\n tokenExpiration: pluginOptions.tokenExpiration,\n })\n config.collections.push(subscribersCollection)\n }\n\n if (pluginOptions.collections) {\n for (const collectionSlug in pluginOptions.collections) {\n const collection = config.collections.find(\n (collection) => collection.slug === collectionSlug,\n )\n\n if (collection) {\n collection.fields.push(OptedInChannels)\n }\n }\n }\n\n /**\n * If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.\n * If your plugin heavily modifies the database schema, you may want to remove this property.\n */\n if (pluginOptions.disabled) {\n return config\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.beforeDashboard) {\n config.admin.components.beforeDashboard = []\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n config.endpoints.push(\n getOptInChannelsEndpoint,\n createEndpointLogout({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointRequestMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointSubscribe({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointSubscriberAuth({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointVerifyMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n )\n\n const incomingOnInit = config.onInit\n\n const genInit = (testData: { testEmail: string }) => async (payload: BasePayload) => {\n // Ensure we are executing any existing onInit functions before running our own.\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n // console.log('Object.keys(payload.collections)', Object.keys(payload.collections))\n const { totalDocs: totalOptIns } = await payload.count({\n collection: 'opt-in-channels',\n where: {\n title: {\n equals: 'seeded-by-plugin',\n },\n },\n })\n\n if (totalOptIns === 0) {\n await payload.create({\n collection: 'opt-in-channels',\n data: {\n active: true,\n title: 'seeded-by-plugin',\n },\n })\n }\n\n // const { seededChannel } = await payload.find({\n // collection: 'opt-in-channels',\n // where: {\n // title: {\n // equals: 'seeded-by-plugin',\n // },\n // },\n // })\n\n const { totalDocs: totalSubscribers } = await payload.count({\n collection: subscribersCollection.slug as CollectionSlug,\n where: {\n email: {\n equals: testData.testEmail,\n },\n },\n })\n\n const { tokenHash } = getTokenAndHash() // Unknowable\n // payload.logger.info(`testData.testEmail == '${testData.testEmail}'`)\n if (totalSubscribers === 0) {\n await payload.create({\n collection: subscribersCollection.slug as CollectionSlug,\n data: {\n email: testData.testEmail,\n password: tokenHash,\n status: 'pending',\n },\n })\n }\n }\n\n // console.log(`getTestEmail == '${getTestEmail()}'`)\n config.onInit = genInit({ testEmail: getTestEmail() })\n\n return config\n }\n"],"names":["OptedInChannels","OptInChannels","defaultTokenExpiration","SubscribersCollectionFactory","subscribersCollectionFields","getOptInChannelsEndpoint","createEndpointLogout","createEndpointRequestMagicLink","createEndpointSubscribe","createEndpointSubscriberAuth","createEndpointVerifyMagicLink","getTestEmail","getTokenAndHash","payloadSubscribersPlugin","pluginOptions","config","collections","push","subscribersCollection","subscribersCollectionSlug","find","collection","slug","undefined","filter","fields","auth","tokenExpiration","admin","useAsTitle","collectionSlug","disabled","components","beforeDashboard","endpoints","incomingOnInit","onInit","genInit","testData","payload","totalDocs","totalOptIns","count","where","title","equals","create","data","active","totalSubscribers","email","testEmail","tokenHash","password","status"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { BasePayload, CollectionSlug, Config } from 'payload'\n\nimport { OptedInChannels } from './collections/fields/OptedInChannels.js'\nimport OptInChannels from './collections/OptInChannels.js'\nimport {\n defaultTokenExpiration,\n SubscribersCollectionFactory,\n subscribersCollectionFields,\n} from './collections/Subscribers.js'\nimport getOptInChannelsEndpoint from './endpoints/getOptInChannels.js'\nimport createEndpointLogout from './endpoints/logout.js'\nimport createEndpointRequestMagicLink from './endpoints/requestMagicLink.js'\nimport createEndpointSubscribe from './endpoints/subscribe.js'\nimport createEndpointSubscriberAuth from './endpoints/subscriberAuth.js'\nimport createEndpointVerifyMagicLink from './endpoints/verifyMagicLink.js'\nimport { getTestEmail } from './helpers/testData.js'\nimport { getTokenAndHash } from './helpers/token.js'\n\nexport type PayloadSubscribersConfig = {\n /**\n * List of collections to add a custom field\n */\n collections?: Partial<Record<CollectionSlug, true>>\n /**\n * Defaults to false-y. When true:\n * - Database schema changes are still made and seeded\n * - APIs return null or undefined success\n * - Admin components are not added\n * - App components return nothing\n */\n disabled?: boolean\n /**\n * The collection to use as the subscribers collection\n * - Optional. If not specified, the plugin will add a 'subscribers' collection.\n * - Sets the collection auth if not already.\n * - Adds (or overrides) fields: email, firstName, status, optIns, verificationToken, verificationTokenExpires.\n */\n subscribersCollectionSlug?: CollectionSlug\n /**\n * Defaults to 30 minutes\n */\n tokenExpiration?: number\n}\n\nexport const payloadSubscribersPlugin =\n (pluginOptions: PayloadSubscribersConfig) =>\n (config: Config): Config => {\n if (!config.collections) {\n config.collections = []\n }\n\n config.collections.push(OptInChannels)\n let subscribersCollection = pluginOptions.subscribersCollectionSlug\n ? config.collections.find(\n (collection) => collection.slug == pluginOptions.subscribersCollectionSlug,\n )\n : undefined\n\n if (subscribersCollection) {\n // Configure the input collection to be the subscribers collection\n config.collections = config.collections.filter(\n (collection) => collection.slug != subscribersCollection?.slug,\n )\n subscribersCollection.fields.push(...subscribersCollectionFields)\n if (!subscribersCollection.auth) {\n subscribersCollection = {\n ...subscribersCollection,\n auth: { tokenExpiration: defaultTokenExpiration },\n }\n }\n if (!subscribersCollection.admin?.useAsTitle) {\n if (!subscribersCollection.admin) {\n subscribersCollection.admin = { useAsTitle: 'email' }\n } else {\n // Throw error? Or override?\n subscribersCollection.admin.useAsTitle = 'email'\n }\n }\n config.collections.push(subscribersCollection)\n } else {\n // Configure the default built-in subscribers collection\n subscribersCollection = SubscribersCollectionFactory({\n slug: pluginOptions.subscribersCollectionSlug,\n tokenExpiration: pluginOptions.tokenExpiration,\n })\n config.collections.push(subscribersCollection)\n }\n\n if (pluginOptions.collections) {\n for (const collectionSlug in pluginOptions.collections) {\n const collection = config.collections.find(\n (collection) => collection.slug === collectionSlug,\n )\n\n if (collection) {\n collection.fields.push(OptedInChannels)\n }\n }\n }\n\n /**\n * If the plugin is disabled, we still want to keep added collections/fields so the database schema is consistent which is important for migrations.\n * If your plugin heavily modifies the database schema, you may want to remove this property.\n */\n if (pluginOptions.disabled) {\n return config\n }\n\n if (!config.admin) {\n config.admin = {}\n }\n\n if (!config.admin.components) {\n config.admin.components = {}\n }\n\n if (!config.admin.components.beforeDashboard) {\n config.admin.components.beforeDashboard = []\n }\n\n if (!config.endpoints) {\n config.endpoints = []\n }\n\n config.endpoints.push(\n getOptInChannelsEndpoint,\n createEndpointLogout({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointRequestMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointSubscribe({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointSubscriberAuth({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n createEndpointVerifyMagicLink({\n subscribersCollectionSlug: subscribersCollection.slug as CollectionSlug,\n }),\n )\n\n const incomingOnInit = config.onInit\n\n const genInit = (testData: { testEmail: string }) => async (payload: BasePayload) => {\n // Ensure we are executing any existing onInit functions before running our own.\n if (incomingOnInit) {\n await incomingOnInit(payload)\n }\n\n // console.log('Object.keys(payload.collections)', Object.keys(payload.collections))\n const { totalDocs: totalOptIns } = await payload.count({\n collection: 'opt-in-channels',\n where: {\n title: {\n equals: 'seeded-by-plugin',\n },\n },\n })\n\n if (totalOptIns === 0) {\n await payload.create({\n collection: 'opt-in-channels',\n data: {\n active: true,\n title: 'seeded-by-plugin',\n },\n })\n }\n\n // const { seededChannel } = await payload.find({\n // collection: 'opt-in-channels',\n // where: {\n // title: {\n // equals: 'seeded-by-plugin',\n // },\n // },\n // })\n\n const { totalDocs: totalSubscribers } = await payload.count({\n collection: subscribersCollection.slug as CollectionSlug,\n where: {\n email: {\n equals: testData.testEmail,\n },\n },\n })\n\n const { tokenHash } = getTokenAndHash() // Unknowable\n // payload.logger.info(`testData.testEmail == '${testData.testEmail}'`)\n if (totalSubscribers === 0) {\n await payload.create({\n collection: subscribersCollection.slug as CollectionSlug,\n data: {\n email: testData.testEmail,\n password: tokenHash,\n status: 'pending',\n },\n })\n }\n }\n\n // console.log(`getTestEmail == '${getTestEmail()}'`)\n config.onInit = genInit({ testEmail: getTestEmail() })\n\n return config\n }\n"],"names":["OptedInChannels","OptInChannels","defaultTokenExpiration","SubscribersCollectionFactory","subscribersCollectionFields","getOptInChannelsEndpoint","createEndpointLogout","createEndpointRequestMagicLink","createEndpointSubscribe","createEndpointSubscriberAuth","createEndpointVerifyMagicLink","getTestEmail","getTokenAndHash","payloadSubscribersPlugin","pluginOptions","config","collections","push","subscribersCollection","subscribersCollectionSlug","find","collection","slug","undefined","filter","fields","auth","tokenExpiration","admin","useAsTitle","collectionSlug","disabled","components","beforeDashboard","endpoints","incomingOnInit","onInit","genInit","testData","payload","totalDocs","totalOptIns","count","where","title","equals","create","data","active","totalSubscribers","email","testEmail","tokenHash","password","status"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -23,8 +23,7 @@
|
|
|
23
23
|
"main": "./dist/index.js",
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"files": [
|
|
26
|
-
"dist"
|
|
27
|
-
"src"
|
|
26
|
+
"dist/"
|
|
28
27
|
],
|
|
29
28
|
"devDependencies": {
|
|
30
29
|
"@eslint/eslintrc": "^3.3.3",
|
|
@@ -70,7 +69,7 @@
|
|
|
70
69
|
},
|
|
71
70
|
"registry": "https://registry.npmjs.org/",
|
|
72
71
|
"dependencies": {},
|
|
73
|
-
"version": "0.0.
|
|
72
|
+
"version": "0.0.5",
|
|
74
73
|
"scripts": {
|
|
75
74
|
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
76
75
|
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const BeforeDashboardClient: () => import("react").JSX.Element;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useConfig } from '@payloadcms/ui';
|
|
4
|
-
import { formatAdminURL } from 'payload/shared';
|
|
5
|
-
import { useEffect, useState } from 'react';
|
|
6
|
-
export const BeforeDashboardClient = ()=>{
|
|
7
|
-
const { config } = useConfig();
|
|
8
|
-
const [message, setMessage] = useState('');
|
|
9
|
-
useEffect(()=>{
|
|
10
|
-
const fetchMessage = async ()=>{
|
|
11
|
-
const response = await fetch(formatAdminURL({
|
|
12
|
-
adminRoute: config.routes.api,
|
|
13
|
-
path: '/my-plugin-endpoint'
|
|
14
|
-
}));
|
|
15
|
-
const result = await response.json();
|
|
16
|
-
setMessage(result.message);
|
|
17
|
-
};
|
|
18
|
-
void fetchMessage();
|
|
19
|
-
}, [
|
|
20
|
-
config.serverURL,
|
|
21
|
-
config.routes.api
|
|
22
|
-
]);
|
|
23
|
-
return /*#__PURE__*/ _jsxs("div", {
|
|
24
|
-
children: [
|
|
25
|
-
/*#__PURE__*/ _jsx("h1", {
|
|
26
|
-
children: "Added by the plugin: Before Dashboard Client"
|
|
27
|
-
}),
|
|
28
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
29
|
-
children: [
|
|
30
|
-
"Message from the endpoint:",
|
|
31
|
-
/*#__PURE__*/ _jsx("div", {
|
|
32
|
-
children: message || 'Loading...'
|
|
33
|
-
})
|
|
34
|
-
]
|
|
35
|
-
})
|
|
36
|
-
]
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
//# sourceMappingURL=BeforeDashboardClient.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/BeforeDashboardClient.tsx"],"sourcesContent":["'use client'\nimport { useConfig } from '@payloadcms/ui'\nimport { formatAdminURL } from 'payload/shared'\nimport { useEffect, useState } from 'react'\n\nexport const BeforeDashboardClient = () => {\n const { config } = useConfig()\n\n const [message, setMessage] = useState('')\n\n useEffect(() => {\n const fetchMessage = async () => {\n const response = await fetch(\n formatAdminURL({\n adminRoute: config.routes.api,\n path: '/my-plugin-endpoint',\n }),\n )\n const result = await response.json()\n setMessage(result.message)\n }\n\n void fetchMessage()\n }, [config.serverURL, config.routes.api])\n\n return (\n <div>\n <h1>Added by the plugin: Before Dashboard Client</h1>\n <div>\n Message from the endpoint:\n <div>{message || 'Loading...'}</div>\n </div>\n </div>\n )\n}\n"],"names":["useConfig","formatAdminURL","useEffect","useState","BeforeDashboardClient","config","message","setMessage","fetchMessage","response","fetch","adminRoute","routes","api","path","result","json","serverURL","div","h1"],"mappings":"AAAA;;AACA,SAASA,SAAS,QAAQ,iBAAgB;AAC1C,SAASC,cAAc,QAAQ,iBAAgB;AAC/C,SAASC,SAAS,EAAEC,QAAQ,QAAQ,QAAO;AAE3C,OAAO,MAAMC,wBAAwB;IACnC,MAAM,EAAEC,MAAM,EAAE,GAAGL;IAEnB,MAAM,CAACM,SAASC,WAAW,GAAGJ,SAAS;IAEvCD,UAAU;QACR,MAAMM,eAAe;YACnB,MAAMC,WAAW,MAAMC,MACrBT,eAAe;gBACbU,YAAYN,OAAOO,MAAM,CAACC,GAAG;gBAC7BC,MAAM;YACR;YAEF,MAAMC,SAAS,MAAMN,SAASO,IAAI;YAClCT,WAAWQ,OAAOT,OAAO;QAC3B;QAEA,KAAKE;IACP,GAAG;QAACH,OAAOY,SAAS;QAAEZ,OAAOO,MAAM,CAACC,GAAG;KAAC;IAExC,qBACE,MAACK;;0BACC,KAACC;0BAAG;;0BACJ,MAACD;;oBAAI;kCAEH,KAACA;kCAAKZ,WAAW;;;;;;AAIzB,EAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import styles from './BeforeDashboardServer.module.css';
|
|
3
|
-
export const BeforeDashboardServer = async (props)=>{
|
|
4
|
-
const { payload } = props;
|
|
5
|
-
const { docs } = await payload.find({
|
|
6
|
-
collection: 'subscribers'
|
|
7
|
-
});
|
|
8
|
-
return /*#__PURE__*/ _jsxs("div", {
|
|
9
|
-
className: styles.wrapper,
|
|
10
|
-
children: [
|
|
11
|
-
/*#__PURE__*/ _jsx("h1", {
|
|
12
|
-
children: "Added by the plugin: Before Dashboard Server"
|
|
13
|
-
}),
|
|
14
|
-
"Docs from Local API:",
|
|
15
|
-
docs.map((doc)=>/*#__PURE__*/ _jsx("div", {
|
|
16
|
-
children: doc.id
|
|
17
|
-
}, doc.id))
|
|
18
|
-
]
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
//# sourceMappingURL=BeforeDashboardServer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/BeforeDashboardServer.tsx"],"sourcesContent":["import type { ServerComponentProps } from 'payload'\n\nimport styles from './BeforeDashboardServer.module.css'\n\nexport const BeforeDashboardServer = async (props: ServerComponentProps) => {\n const { payload } = props\n\n const { docs } = await payload.find({ collection: 'subscribers' })\n\n return (\n <div className={styles.wrapper}>\n <h1>Added by the plugin: Before Dashboard Server</h1>\n Docs from Local API:\n {docs.map((doc) => (\n <div key={doc.id}>{doc.id}</div>\n ))}\n </div>\n )\n}\n"],"names":["styles","BeforeDashboardServer","props","payload","docs","find","collection","div","className","wrapper","h1","map","doc","id"],"mappings":";AAEA,OAAOA,YAAY,qCAAoC;AAEvD,OAAO,MAAMC,wBAAwB,OAAOC;IAC1C,MAAM,EAAEC,OAAO,EAAE,GAAGD;IAEpB,MAAM,EAAEE,IAAI,EAAE,GAAG,MAAMD,QAAQE,IAAI,CAAC;QAAEC,YAAY;IAAc;IAEhE,qBACE,MAACC;QAAIC,WAAWR,OAAOS,OAAO;;0BAC5B,KAACC;0BAAG;;YAAiD;YAEpDN,KAAKO,GAAG,CAAC,CAACC,oBACT,KAACL;8BAAkBK,IAAIC,EAAE;mBAAfD,IAAIC,EAAE;;;AAIxB,EAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/customEndpointHandler.ts"],"sourcesContent":["import type { PayloadHandler } from 'payload'\n\nexport const customEndpointHandler: PayloadHandler = () => {\n return Response.json({ message: 'Hello from custom endpoint' })\n}\n"],"names":["customEndpointHandler","Response","json","message"],"mappings":"AAEA,OAAO,MAAMA,wBAAwC;IACnD,OAAOC,SAASC,IAAI,CAAC;QAAEC,SAAS;IAA6B;AAC/D,EAAC"}
|
package/dist/exports/client.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { BeforeDashboardClient } from '../components/BeforeDashboardClient.js';
|
package/dist/exports/client.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { BeforeDashboardClient } from '../components/BeforeDashboardClient.js'\n"],"names":["BeforeDashboardClient"],"mappings":"AAAA,SAASA,qBAAqB,QAAQ,yCAAwC"}
|
package/dist/exports/rsc.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { BeforeDashboardServer } from '../components/BeforeDashboardServer.js';
|
package/dist/exports/rsc.js
DELETED
package/dist/exports/rsc.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/rsc.ts"],"sourcesContent":["export { BeforeDashboardServer } from '../components/BeforeDashboardServer.js'\n"],"names":["BeforeDashboardServer"],"mappings":"AAAA,SAASA,qBAAqB,QAAQ,yCAAwC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export const canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
|
|
2
|
-
export const getServerSideURL = ()=>{
|
|
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
|
-
// console.log(`process.env.NEXT_PUBLIC_DEV_URL: ${process.env.NEXT_PUBLIC_DEV_URL}`)
|
|
5
|
-
// console.log(`serverSideURL: ${serverSideURL}`)
|
|
6
|
-
return serverSideURL;
|
|
7
|
-
};
|
|
8
|
-
export const getClientSideURL = ()=>{
|
|
9
|
-
if (canUseDOM) {
|
|
10
|
-
const protocol = window.location.protocol;
|
|
11
|
-
const domain = window.location.hostname;
|
|
12
|
-
const port = window.location.port;
|
|
13
|
-
// `${window.location.protocol}//${window.location.host}
|
|
14
|
-
const clientSideURL = `${protocol}//${domain}${port ? `:${port}` : ''}`;
|
|
15
|
-
// console.log(`clientSideURL: ${clientSideURL}`)
|
|
16
|
-
return clientSideURL;
|
|
17
|
-
}
|
|
18
|
-
return getServerSideURL();
|
|
19
|
-
};
|
|
20
|
-
export const serverURL = getClientSideURL();
|
|
21
|
-
|
|
22
|
-
//# sourceMappingURL=serverConfig.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/helpers/serverConfig.ts"],"sourcesContent":["export const canUseDOM = !!(\n typeof window !== 'undefined' &&\n window.document &&\n window.document.createElement\n)\n\nexport const 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\nexport 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 serverURL = getClientSideURL()\n"],"names":["canUseDOM","window","document","createElement","getServerSideURL","serverSideURL","process","env","NEXT_PUBLIC_VERCEL_URL","VERCEL_PROJECT_PRODUCTION_URL","NEXT_PUBLIC_DEV_URL","getClientSideURL","protocol","location","domain","hostname","port","clientSideURL","serverURL"],"mappings":"AAAA,OAAO,MAAMA,YAAY,CAAC,CACxB,CAAA,OAAOC,WAAW,eAClBA,OAAOC,QAAQ,IACfD,OAAOC,QAAQ,CAACC,aAAa,AAAD,EAC7B;AAED,OAAO,MAAMC,mBAAmB;IAC9B,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;AACT,EAAC;AAED,OAAO,MAAMM,mBAAmB;IAC9B,IAAIX,WAAW;QACb,MAAMY,WAAWX,OAAOY,QAAQ,CAACD,QAAQ;QACzC,MAAME,SAASb,OAAOY,QAAQ,CAACE,QAAQ;QACvC,MAAMC,OAAOf,OAAOY,QAAQ,CAACG,IAAI;QACjC,wDAAwD;QACxD,MAAMC,gBAAgB,GAAGL,SAAS,EAAE,EAAEE,SAASE,OAAO,CAAC,CAAC,EAAEA,MAAM,GAAG,IAAI;QACvE,iDAAiD;QACjD,OAAOC;IACT;IAEA,OAAOb;AACT,EAAC;AAED,OAAO,MAAMc,YAAYP,mBAAkB"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type SubscriberAuthReturn = {
|
|
2
|
-
error: any;
|
|
3
|
-
} | {
|
|
4
|
-
permissions: any;
|
|
5
|
-
subscriber: any;
|
|
6
|
-
};
|
|
7
|
-
export declare const subscriberAuth: () => Promise<SubscriberAuthReturn>;
|
|
8
|
-
export declare function logoutAction(): Promise<{
|
|
9
|
-
message: string;
|
|
10
|
-
success: boolean;
|
|
11
|
-
}>;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { CollectionConfig } from 'payload'
|
|
2
|
-
|
|
3
|
-
export const OptInChannels: CollectionConfig = {
|
|
4
|
-
slug: 'opt-in-channels',
|
|
5
|
-
access: {
|
|
6
|
-
// Public access for creation (signup form)
|
|
7
|
-
create: () => true,
|
|
8
|
-
// Admin-only access for reading, updating, and deleting
|
|
9
|
-
delete: ({ req }) => (req.user ? true : false),
|
|
10
|
-
// read: ({ req }) => (req.user ? true : false),
|
|
11
|
-
read: () => true,
|
|
12
|
-
update: ({ req }) => (req.user ? true : false),
|
|
13
|
-
},
|
|
14
|
-
admin: {
|
|
15
|
-
useAsTitle: 'title', // Specify the field to use as the title
|
|
16
|
-
},
|
|
17
|
-
fields: [
|
|
18
|
-
{
|
|
19
|
-
name: 'title',
|
|
20
|
-
type: 'text', // Enforces valid email format
|
|
21
|
-
label: 'Title',
|
|
22
|
-
required: true,
|
|
23
|
-
unique: true, // Ensures no duplicate titles
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: 'description',
|
|
27
|
-
type: 'text',
|
|
28
|
-
label: 'Description',
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: 'active',
|
|
32
|
-
type: 'checkbox',
|
|
33
|
-
defaultValue: true, // Default to pending until verified
|
|
34
|
-
label: 'Active',
|
|
35
|
-
required: true,
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: 'slug',
|
|
39
|
-
type: 'text',
|
|
40
|
-
label: 'slug',
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export default OptInChannels
|