payload-plugin-marketing 0.9.0 → 0.9.2
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 +62 -32
- package/dist/adapters/mailchimp.cjs +2 -0
- package/dist/adapters/mailchimp.cjs.map +1 -0
- package/dist/adapters/mailchimp.js +2 -0
- package/dist/adapters/mailchimp.js.map +1 -0
- package/dist/adapters/resend.cjs +2 -0
- package/dist/adapters/resend.cjs.map +1 -0
- package/dist/adapters/resend.js +2 -0
- package/dist/adapters/resend.js.map +1 -0
- package/dist/admin/audience-buttons.d.ts +6 -0
- package/dist/admin/audience-buttons.d.ts.map +1 -0
- package/dist/admin/broadcasts-table.d.ts +14 -0
- package/dist/admin/broadcasts-table.d.ts.map +1 -0
- package/dist/admin/components.d.ts +2 -1
- package/dist/admin/components.d.ts.map +1 -1
- package/dist/admin/contacts-table.d.ts +12 -0
- package/dist/admin/contacts-table.d.ts.map +1 -0
- package/dist/admin/create-broadcast-button.d.ts +6 -0
- package/dist/admin/create-broadcast-button.d.ts.map +1 -0
- package/dist/admin/date-format.d.ts +2 -0
- package/dist/admin/date-format.d.ts.map +1 -0
- package/dist/admin/index.cjs +1 -1
- package/dist/admin/index.cjs.map +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/paths.d.ts +2 -0
- package/dist/admin/paths.d.ts.map +1 -0
- package/dist/admin/payload-modal.d.ts +13 -0
- package/dist/admin/payload-modal.d.ts.map +1 -0
- package/dist/admin/provider-dashboard-link.d.ts +8 -0
- package/dist/admin/provider-dashboard-link.d.ts.map +1 -0
- package/dist/admin/use-marketing-api.d.ts +5 -0
- package/dist/admin/use-marketing-api.d.ts.map +1 -0
- package/dist/endpoints/marketing-endpoints.d.ts +3 -0
- package/dist/endpoints/marketing-endpoints.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/marketing-integration.d.ts +15 -0
- package/dist/marketing-integration.d.ts.map +1 -0
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/actions/factories.d.ts +0 -18
- package/dist/actions/factories.d.ts.map +0 -1
- package/dist/actions/index.cjs +0 -2
- package/dist/actions/index.cjs.map +0 -1
- package/dist/actions/index.d.ts +0 -2
- package/dist/actions/index.d.ts.map +0 -1
- package/dist/actions/index.js +0 -2
- package/dist/actions/index.js.map +0 -1
- package/dist/adapters/index.cjs +0 -2
- package/dist/adapters/index.cjs.map +0 -1
- package/dist/adapters/index.d.ts +0 -3
- package/dist/adapters/index.d.ts.map +0 -1
- package/dist/adapters/index.js +0 -2
- package/dist/adapters/index.js.map +0 -1
- package/dist/chunk-KBN7IE22.js +0 -2
- package/dist/chunk-KBN7IE22.js.map +0 -1
- package/dist/chunk-RBBHOL35.js +0 -2
- package/dist/chunk-RBBHOL35.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,21 +15,24 @@ pnpm add resend
|
|
|
15
15
|
pnpm add @mailchimp/mailchimp_marketing
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
Import adapters from **`payload-plugin-marketing/adapters/resend`** or **`payload-plugin-marketing/adapters/mailchimp`**.
|
|
19
|
+
|
|
18
20
|
## Usage
|
|
19
21
|
|
|
20
|
-
Call `formBuilderPlugin(...)` yourself, then add `
|
|
22
|
+
Call `formBuilderPlugin(...)` yourself, then add `marketingPlugin(...)` after it:
|
|
21
23
|
|
|
22
24
|
```ts
|
|
23
25
|
import { formBuilderPlugin } from "@payloadcms/plugin-form-builder"
|
|
24
26
|
import { buildConfig } from "payload"
|
|
25
|
-
import {
|
|
27
|
+
import { marketingPlugin } from "payload-plugin-marketing"
|
|
28
|
+
import { resendAdapter } from "payload-plugin-marketing/adapters/resend"
|
|
26
29
|
|
|
27
30
|
export default buildConfig({
|
|
28
31
|
plugins: [
|
|
29
32
|
formBuilderPlugin({
|
|
30
33
|
defaultToEmail: process.env.EMAIL_DEFAULT_RECEIVER,
|
|
31
34
|
}),
|
|
32
|
-
|
|
35
|
+
marketingPlugin({
|
|
33
36
|
adapter: resendAdapter({ apiKey: process.env.RESEND_API_KEY }),
|
|
34
37
|
}),
|
|
35
38
|
],
|
|
@@ -40,7 +43,7 @@ The plugin mutates the generated `forms` and `form-submissions` collections. If
|
|
|
40
43
|
slugs are customized, pass them explicitly:
|
|
41
44
|
|
|
42
45
|
```ts
|
|
43
|
-
|
|
46
|
+
marketingPlugin({
|
|
44
47
|
adapter: resendAdapter({ apiKey: process.env.RESEND_API_KEY }),
|
|
45
48
|
formBuilder: {
|
|
46
49
|
formsSlug: "marketing-forms",
|
|
@@ -71,7 +74,7 @@ formBuilderPlugin({
|
|
|
71
74
|
Customize block labels and nested field config from the marketing plugin:
|
|
72
75
|
|
|
73
76
|
```ts
|
|
74
|
-
|
|
77
|
+
marketingPlugin({
|
|
75
78
|
adapter: resendAdapter({ apiKey: process.env.RESEND_API_KEY }),
|
|
76
79
|
formBuilder: {
|
|
77
80
|
fields: {
|
|
@@ -103,9 +106,9 @@ newsletter, {{firstName}}, product-interest
|
|
|
103
106
|
## Resend
|
|
104
107
|
|
|
105
108
|
```ts
|
|
106
|
-
import { resendAdapter } from "payload-plugin-marketing"
|
|
109
|
+
import { resendAdapter } from "payload-plugin-marketing/adapters/resend"
|
|
107
110
|
|
|
108
|
-
|
|
111
|
+
marketingPlugin({
|
|
109
112
|
adapter: resendAdapter({
|
|
110
113
|
apiKey: process.env.RESEND_API_KEY,
|
|
111
114
|
defaultSender: "hello@example.com",
|
|
@@ -116,9 +119,9 @@ payloadMarketingPlugin({
|
|
|
116
119
|
## Mailchimp
|
|
117
120
|
|
|
118
121
|
```ts
|
|
119
|
-
import { mailchimpAdapter } from "payload-plugin-marketing"
|
|
122
|
+
import { mailchimpAdapter } from "payload-plugin-marketing/adapters/mailchimp"
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
marketingPlugin({
|
|
122
125
|
adapter: mailchimpAdapter({
|
|
123
126
|
apiKey: process.env.MAILCHIMP_API_KEY!,
|
|
124
127
|
defaultSender: "hello@example.com",
|
|
@@ -135,7 +138,7 @@ Default admin views are registered for audience and broadcast management. Overri
|
|
|
135
138
|
through plugin options:
|
|
136
139
|
|
|
137
140
|
```ts
|
|
138
|
-
|
|
141
|
+
marketingPlugin({
|
|
139
142
|
adapter: resendAdapter({ apiKey: process.env.RESEND_API_KEY }),
|
|
140
143
|
admin: {
|
|
141
144
|
basePath: "/marketing",
|
|
@@ -153,40 +156,68 @@ payloadMarketingPlugin({
|
|
|
153
156
|
|
|
154
157
|
Components are also exported from `payload-plugin-marketing/admin`.
|
|
155
158
|
|
|
156
|
-
##
|
|
159
|
+
## Endpoint permissions
|
|
157
160
|
|
|
158
|
-
|
|
161
|
+
Marketing REST routes (`GET /marketing/meta`, audiences, contacts, broadcasts) require an authenticated
|
|
162
|
+
admin user. You can narrow access with **`permissions`**: each of **`audiences`**, **`contacts`**, and
|
|
163
|
+
**`broadcasts`** accepts optional **`read`** and **`write`**. Omitted flags default to **`true`** for
|
|
164
|
+
that resource. If you omit **`permissions`** entirely, behavior matches previous releases (any signed-in
|
|
165
|
+
user can call all routes).
|
|
159
166
|
|
|
160
|
-
|
|
161
|
-
import { createMarketingActions, resendAdapter } from "payload-plugin-marketing"
|
|
167
|
+
**`GET /marketing/meta`** is allowed when at least one resource has **`read: true`** after resolution.
|
|
162
168
|
|
|
163
|
-
|
|
169
|
+
```ts
|
|
170
|
+
marketingPlugin({
|
|
164
171
|
adapter: resendAdapter({ apiKey: process.env.RESEND_API_KEY }),
|
|
172
|
+
permissions: {
|
|
173
|
+
audiences: { read: true, write: true },
|
|
174
|
+
contacts: { read: true, write: false },
|
|
175
|
+
broadcasts: { read: true, write: true },
|
|
176
|
+
},
|
|
165
177
|
})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Denied requests respond with **403** and `{ message: "Forbidden" }`.
|
|
181
|
+
|
|
182
|
+
## Using the adapter in your app
|
|
183
|
+
|
|
184
|
+
The plugin attaches your **`MarketingAdapter`** to **`config.custom.payloadPluginMarketing`** (server-only; not sent to the admin client bundle). Resolve it from **`payload`** anywhere you already have **`Payload`**:
|
|
166
185
|
|
|
167
|
-
|
|
168
|
-
|
|
186
|
+
```ts
|
|
187
|
+
import { getMarketingIntegration } from "payload-plugin-marketing"
|
|
188
|
+
|
|
189
|
+
const { adapter } = getMarketingIntegration(req.payload)
|
|
190
|
+
await adapter.audiences.create({ name: "Newsletter" })
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Subscribe an email to your first audience (pick a concrete **`audienceId`** if you prefer):
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const { adapter } = getMarketingIntegration(req.payload)
|
|
197
|
+
const audienceId = (await adapter.audiences.list())[0]?.id
|
|
198
|
+
if (!audienceId) {
|
|
199
|
+
throw new Error("No audience found. Create one in the admin first.")
|
|
200
|
+
}
|
|
201
|
+
await adapter.contacts.upsert({ audienceId, email: "person@example.com", subscribed: true })
|
|
169
202
|
```
|
|
170
203
|
|
|
171
204
|
## Broadcasts
|
|
172
205
|
|
|
173
|
-
|
|
174
|
-
return a boolean; `broadcastId` for send/delete comes from your provider (for example `adapter.broadcasts.list()` after create, or the provider dashboard).
|
|
206
|
+
Same adapter as **`marketingPlugin`**. **`broadcastId`** for send/delete comes from your provider (for example **`adapter.broadcasts.list()`** after create, or the provider dashboard).
|
|
175
207
|
|
|
176
208
|
### Resend (HTML or React)
|
|
177
209
|
|
|
178
210
|
`defaultSender` on `resendAdapter` is sent as `from`. **`templateId` is not supported** and will throw.
|
|
179
211
|
|
|
180
212
|
```ts
|
|
181
|
-
import {
|
|
213
|
+
import { resendAdapter } from "payload-plugin-marketing/adapters/resend"
|
|
182
214
|
|
|
183
215
|
const adapter = resendAdapter({
|
|
184
216
|
apiKey: process.env.RESEND_API_KEY!,
|
|
185
217
|
defaultSender: "Acme <newsletter@example.com>",
|
|
186
218
|
})
|
|
187
|
-
const actions = createMarketingActions({ adapter })
|
|
188
219
|
|
|
189
|
-
await
|
|
220
|
+
await adapter.broadcasts.create({
|
|
190
221
|
audienceId: "<segment-or-audience-id>",
|
|
191
222
|
name: "January update",
|
|
192
223
|
subject: "What we shipped",
|
|
@@ -198,25 +229,24 @@ await actions.createBroadcast({
|
|
|
198
229
|
const drafts = await adapter.broadcasts.list()
|
|
199
230
|
const id = drafts[0]?.id
|
|
200
231
|
if (id) {
|
|
201
|
-
await
|
|
232
|
+
await adapter.broadcasts.send({ broadcastId: id })
|
|
202
233
|
// optional ISO 8601 or natural language, depending on Resend SDK:
|
|
203
|
-
// await
|
|
234
|
+
// await adapter.broadcasts.send({ broadcastId: id, scheduledAt: "2026-12-01T15:00:00.000Z" })
|
|
204
235
|
}
|
|
205
236
|
```
|
|
206
237
|
|
|
207
238
|
### Mailchimp (HTML body)
|
|
208
239
|
|
|
209
240
|
```ts
|
|
210
|
-
import {
|
|
241
|
+
import { mailchimpAdapter } from "payload-plugin-marketing/adapters/mailchimp"
|
|
211
242
|
|
|
212
243
|
const adapter = mailchimpAdapter({
|
|
213
244
|
apiKey: process.env.MAILCHIMP_API_KEY!,
|
|
214
245
|
defaultSender: "newsletter@example.com",
|
|
215
246
|
siteName: "Acme",
|
|
216
247
|
})
|
|
217
|
-
const actions = createMarketingActions({ adapter })
|
|
218
248
|
|
|
219
|
-
await
|
|
249
|
+
await adapter.broadcasts.create({
|
|
220
250
|
audienceId: "<list-id>",
|
|
221
251
|
name: "January update",
|
|
222
252
|
subject: "What we shipped",
|
|
@@ -226,18 +256,18 @@ await actions.createBroadcast({
|
|
|
226
256
|
const campaigns = await adapter.broadcasts.list()
|
|
227
257
|
const id = campaigns[0]?.id
|
|
228
258
|
if (id) {
|
|
229
|
-
await
|
|
259
|
+
await adapter.broadcasts.send({ broadcastId: id })
|
|
230
260
|
// or schedule:
|
|
231
|
-
// await
|
|
261
|
+
// await adapter.broadcasts.send({ broadcastId: id, scheduledAt: "2026-12-01T15:00:00.000Z" })
|
|
232
262
|
}
|
|
233
263
|
```
|
|
234
264
|
|
|
235
265
|
### Mailchimp (saved template)
|
|
236
266
|
|
|
237
|
-
Use the numeric template id from your Mailchimp account as a string. Do not pass **`html`** in the same call.
|
|
267
|
+
Use the numeric template id from your Mailchimp account as a string. Do not pass **`html`** in the same call.
|
|
238
268
|
|
|
239
269
|
```ts
|
|
240
|
-
await
|
|
270
|
+
await adapter.broadcasts.create({
|
|
241
271
|
audienceId: "<list-id>",
|
|
242
272
|
name: "Monthly newsletter",
|
|
243
273
|
subject: "News from Acme",
|
|
@@ -248,5 +278,5 @@ await actions.createBroadcast({
|
|
|
248
278
|
### Delete a draft broadcast
|
|
249
279
|
|
|
250
280
|
```ts
|
|
251
|
-
await
|
|
281
|
+
await adapter.broadcasts.delete({ broadcastId: "<broadcast-or-campaign-id>" })
|
|
252
282
|
```
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var h=Object.create;var m=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,M=Object.prototype.hasOwnProperty;var A=(t,s)=>{for(var n in s)m(t,n,{get:s[n],enumerable:!0})},g=(t,s,n,c)=>{if(s&&typeof s=="object"||typeof s=="function")for(let e of y(s))!M.call(t,e)&&e!==n&&m(t,e,{get:()=>s[e],enumerable:!(c=b(s,e))||c.enumerable});return t};var I=(t,s,n)=>(n=t!=null?h(k(t)):{},g(s||!t||!t.__esModule?m(n,"default",{value:t,enumerable:!0}):n,t)),_=t=>g(m({},"__esModule",{value:!0}),t);var P={};A(P,{mailchimpAdapter:()=>N});module.exports=_(P);var w=require("crypto");function p(t){return(0,w.createHash)("md5").update(t.toLowerCase()).digest("hex")}function f(t){let s=t.includes("-")?t.split("-").pop():void 0;if(!s)throw new Error("MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).");return s}function L(t){let s=t?.tags;return s==null?[]:String(s).split(",").map(n=>n.trim()).filter(Boolean)}function d(t,s=""){return typeof t=="string"?t:typeof t=="number"&&Number.isFinite(t)?String(t):s}function N(t){let s=!1,n=async()=>{let e=t.client??(await import("@mailchimp/mailchimp_marketing")).default;return s||(e.setConfig({apiKey:t.apiKey,server:f(t.apiKey)}),s=!0),e},c=`https://${f(t.apiKey)}.admin.mailchimp.com`;return{provider:"mailchimp",label:"Mailchimp",urls:{audiences:`${c}/audience/`,broadcasts:`${c}/campaigns/`},audiences:{async create(e){await(await n()).lists.createList({name:e.name,permission_reminder:`You're receiving this email because you opted in via ${t.siteName}.`,email_type_option:!0,contact:{company:t.siteName,address1:"Address on file",city:"N/A",state:"N/A",zip:"00000",country:"US"},campaign_defaults:{from_name:t.siteName,from_email:t.defaultSender,subject:" ",language:"en"}})},async delete(e){await(await n()).lists.deleteList(e.audienceId)},async get(e){let i=await(await n()).lists.getList(e);return{id:i.id,name:i.name}},async list(){return((await(await n()).lists.getAllLists({count:500})).lists??[]).map(i=>({id:i.id,name:i.name}))}},contacts:{async delete(e){await(await n()).lists.deleteListMember(e.audienceId,e.contactId)},async list(e){return((await(await n()).lists.getListMembersInfo(e.audienceId)).members??[]).map(a=>{let r=a.merge_fields;return{createdAt:typeof a.timestamp_signup=="string"?a.timestamp_signup:void 0,email:d(a.email_address),firstName:typeof r?.FNAME=="string"?r.FNAME:null,id:d(a.id,d(a.email_address)),lastName:typeof r?.LNAME=="string"?r.LNAME:null,subscribed:a.status==="subscribed"}})},async upsert(e){let i=await n(),a=e.id??p(e.email),r=e.id?e.subscribed?"subscribed":"unsubscribed":e.subscribed?"subscribed":"pending";await i.lists.setListMember(e.audienceId,a,{email_address:e.email,status:r,merge_fields:{FNAME:e.firstName??"",LNAME:e.lastName??""}},{skipMergeValidation:!0});let l=L(e.properties);l.length>0&&await i.lists.updateListMemberTags(e.audienceId,p(e.email),{tags:l.map(o=>({name:o,status:"active"}))})}},broadcasts:{async create(e){let i=await n(),a=e.templateId!=null&&String(e.templateId).trim()!==""?String(e.templateId).trim():void 0,r;if(a!=null){let o=e.html;if(o!=null&&o!=="")throw new Error("Mailchimp broadcast: use either templateId (cloud template) or html, not both.");let u=Number.parseInt(a,10);if(!Number.isFinite(u))throw new Error(`Invalid Mailchimp template id: "${a}".`);r=u}let l=await i.campaigns.create({type:"regular",recipients:{list_id:e.audienceId},settings:{authenticate:!0,auto_footer:!1,from_email:t.defaultSender,from_name:t.siteName,inline_css:!1,reply_to:e.replyTo?.trim()||t.defaultSender,subject_line:e.subject,title:e.name,to_name:"*|FNAME|*"}});if(!l.id)throw new Error("Mailchimp did not return a campaign id.");r!=null?await i.campaigns.setContent(l.id,{template:{id:r}}):await i.campaigns.setContent(l.id,{html:e.html??""})},async delete(e){await(await n()).campaigns.remove(e.broadcastId)},async list(){return((await(await n()).campaigns.list({count:500})).campaigns??[]).map(i=>{let a=i.settings,r=typeof i.send_time=="string"?i.send_time:null;return{id:d(i.id),name:d(a?.title,d(i.id)),scheduledAt:r,sentAt:r,status:i.status==="save"?"draft":d(i.status,"draft")}})},async send(e){let i=await n(),a=e.scheduledAt?.trim();a?await i.campaigns.schedule(e.broadcastId,{schedule_time:a}):await i.campaigns.send(e.broadcastId)}}}}0&&(module.exports={mailchimpAdapter});
|
|
2
|
+
//# sourceMappingURL=mailchimp.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/mailchimp.ts"],"sourcesContent":["import { createHash } from \"node:crypto\"\n\nimport type { MarketingAdapter } from \"../types\"\n\ninterface MailchimpLike {\n campaigns: {\n create(input: unknown): Promise<{ id?: string }>\n list(input?: unknown): Promise<{ campaigns?: Array<Record<string, unknown>> }>\n remove(id: string): Promise<unknown>\n schedule(id: string, input: unknown): Promise<unknown>\n send(id: string): Promise<unknown>\n setContent(id: string, input: unknown): Promise<unknown>\n }\n lists: {\n createList(input: unknown): Promise<unknown>\n deleteList(id: string): Promise<unknown>\n deleteListMember(listId: string, contactId: string): Promise<unknown>\n getAllLists(input?: unknown): Promise<{ lists?: Array<{ id: string; name: string }> }>\n getList(id: string): Promise<{ id: string; name: string }>\n getListMembersInfo(input: string): Promise<{ members?: Array<Record<string, unknown>> }>\n setListMember(listId: string, hash: string, input: unknown, options?: unknown): Promise<unknown>\n updateListMemberTags(listId: string, hash: string, input: unknown): Promise<unknown>\n }\n setConfig(input: unknown): void\n}\n\nexport interface MailchimpAdapterOptions {\n apiKey: string\n client?: MailchimpLike\n defaultSender: string\n siteName: string\n}\n\nfunction subscriberHash(email: string): string {\n return createHash(\"md5\").update(email.toLowerCase()).digest(\"hex\")\n}\n\nfunction serverFromApiKey(apiKey: string): string {\n const server = apiKey.includes(\"-\") ? apiKey.split(\"-\").pop() : undefined\n if (!server) {\n throw new Error(\"MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).\")\n }\n return server\n}\n\nfunction tagNamesFromProperties(properties?: Record<string, string | number | null>): string[] {\n const raw = properties?.tags\n if (raw == null) {\n return []\n }\n return String(raw)\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean)\n}\n\nfunction stringValue(value: unknown, fallback = \"\"): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nexport function mailchimpAdapter(options: MailchimpAdapterOptions): MarketingAdapter {\n let configured = false\n const getClient = async (): Promise<MailchimpLike> => {\n const client =\n options.client ??\n ((await import(\"@mailchimp/mailchimp_marketing\")) as { default: MailchimpLike }).default\n if (!configured) {\n client.setConfig({ apiKey: options.apiKey, server: serverFromApiKey(options.apiKey) })\n configured = true\n }\n return client\n }\n const adminBase = `https://${serverFromApiKey(options.apiKey)}.admin.mailchimp.com`\n\n return {\n provider: \"mailchimp\",\n label: \"Mailchimp\",\n urls: {\n audiences: `${adminBase}/audience/`,\n broadcasts: `${adminBase}/campaigns/`,\n },\n audiences: {\n async create(input) {\n await (\n await getClient()\n ).lists.createList({\n name: input.name,\n permission_reminder: `You're receiving this email because you opted in via ${options.siteName}.`,\n email_type_option: true,\n contact: {\n company: options.siteName,\n address1: \"Address on file\",\n city: \"N/A\",\n state: \"N/A\",\n zip: \"00000\",\n country: \"US\",\n },\n campaign_defaults: {\n from_name: options.siteName,\n from_email: options.defaultSender,\n subject: \" \",\n language: \"en\",\n },\n })\n },\n async delete(input) {\n await (await getClient()).lists.deleteList(input.audienceId)\n },\n async get(id) {\n const list = await (await getClient()).lists.getList(id)\n return { id: list.id, name: list.name }\n },\n async list() {\n const result = await (await getClient()).lists.getAllLists({ count: 500 })\n return (result.lists ?? []).map((list) => ({ id: list.id, name: list.name }))\n },\n },\n contacts: {\n async delete(input) {\n await (await getClient()).lists.deleteListMember(input.audienceId, input.contactId)\n },\n async list(input) {\n const result = await (await getClient()).lists.getListMembersInfo(input.audienceId)\n return (result.members ?? []).map((member) => {\n const mergeFields = member.merge_fields as Record<string, unknown> | undefined\n return {\n createdAt:\n typeof member.timestamp_signup === \"string\" ? member.timestamp_signup : undefined,\n email: stringValue(member.email_address),\n firstName: typeof mergeFields?.FNAME === \"string\" ? mergeFields.FNAME : null,\n id: stringValue(member.id, stringValue(member.email_address)),\n lastName: typeof mergeFields?.LNAME === \"string\" ? mergeFields.LNAME : null,\n subscribed: member.status === \"subscribed\",\n }\n })\n },\n async upsert(input) {\n const client = await getClient()\n const hash = input.id ?? subscriberHash(input.email)\n const status = input.id\n ? input.subscribed\n ? \"subscribed\"\n : \"unsubscribed\"\n : input.subscribed\n ? \"subscribed\"\n : \"pending\"\n await client.lists.setListMember(\n input.audienceId,\n hash,\n {\n email_address: input.email,\n status,\n merge_fields: { FNAME: input.firstName ?? \"\", LNAME: input.lastName ?? \"\" },\n },\n { skipMergeValidation: true },\n )\n const tags = tagNamesFromProperties(input.properties)\n if (tags.length > 0) {\n await client.lists.updateListMemberTags(input.audienceId, subscriberHash(input.email), {\n tags: tags.map((name) => ({ name, status: \"active\" })),\n })\n }\n },\n },\n broadcasts: {\n async create(input) {\n const client = await getClient()\n const templateIdRaw =\n input.templateId != null && String(input.templateId).trim() !== \"\"\n ? String(input.templateId).trim()\n : undefined\n let templateIdParsed: number | undefined\n if (templateIdRaw != null) {\n const html = input.html\n if (html != null && html !== \"\") {\n throw new Error(\n \"Mailchimp broadcast: use either templateId (cloud template) or html, not both.\",\n )\n }\n const parsed = Number.parseInt(templateIdRaw, 10)\n if (!Number.isFinite(parsed)) {\n throw new Error(`Invalid Mailchimp template id: \"${templateIdRaw}\".`)\n }\n templateIdParsed = parsed\n }\n const campaign = await client.campaigns.create({\n type: \"regular\",\n recipients: { list_id: input.audienceId },\n settings: {\n authenticate: true,\n auto_footer: false,\n from_email: options.defaultSender,\n from_name: options.siteName,\n inline_css: false,\n reply_to: input.replyTo?.trim() || options.defaultSender,\n subject_line: input.subject,\n title: input.name,\n to_name: \"*|FNAME|*\",\n },\n })\n if (!campaign.id) {\n throw new Error(\"Mailchimp did not return a campaign id.\")\n }\n if (templateIdParsed != null) {\n await client.campaigns.setContent(campaign.id, {\n template: { id: templateIdParsed },\n })\n } else {\n await client.campaigns.setContent(campaign.id, { html: input.html ?? \"\" })\n }\n },\n async delete(input) {\n await (await getClient()).campaigns.remove(input.broadcastId)\n },\n async list() {\n const result = await (await getClient()).campaigns.list({ count: 500 })\n return (result.campaigns ?? []).map((campaign) => {\n const settings = campaign.settings as Record<string, unknown> | undefined\n const sentAt = typeof campaign.send_time === \"string\" ? campaign.send_time : null\n return {\n id: stringValue(campaign.id),\n name: stringValue(settings?.title, stringValue(campaign.id)),\n scheduledAt: sentAt,\n sentAt,\n status: campaign.status === \"save\" ? \"draft\" : stringValue(campaign.status, \"draft\"),\n }\n })\n },\n async send(input) {\n const client = await getClient()\n const scheduledAt = input.scheduledAt?.trim()\n if (scheduledAt) {\n await client.campaigns.schedule(input.broadcastId, { schedule_time: scheduledAt })\n } else {\n await client.campaigns.send(input.broadcastId)\n }\n },\n },\n }\n}\n"],"mappings":"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","names":["mailchimp_exports","__export","mailchimpAdapter","__toCommonJS","import_node_crypto","subscriberHash","email","serverFromApiKey","apiKey","server","tagNamesFromProperties","properties","raw","tag","stringValue","value","fallback","options","configured","getClient","client","adminBase","input","id","list","member","mergeFields","hash","status","tags","name","templateIdRaw","templateIdParsed","html","parsed","campaign","settings","sentAt","scheduledAt"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createHash as p}from"crypto";function u(t){return p("md5").update(t.toLowerCase()).digest("hex")}function g(t){let r=t.includes("-")?t.split("-").pop():void 0;if(!r)throw new Error("MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).");return r}function f(t){let r=t?.tags;return r==null?[]:String(r).split(",").map(n=>n.trim()).filter(Boolean)}function d(t,r=""){return typeof t=="string"?t:typeof t=="number"&&Number.isFinite(t)?String(t):r}function h(t){let r=!1,n=async()=>{let e=t.client??(await import("@mailchimp/mailchimp_marketing")).default;return r||(e.setConfig({apiKey:t.apiKey,server:g(t.apiKey)}),r=!0),e},o=`https://${g(t.apiKey)}.admin.mailchimp.com`;return{provider:"mailchimp",label:"Mailchimp",urls:{audiences:`${o}/audience/`,broadcasts:`${o}/campaigns/`},audiences:{async create(e){await(await n()).lists.createList({name:e.name,permission_reminder:`You're receiving this email because you opted in via ${t.siteName}.`,email_type_option:!0,contact:{company:t.siteName,address1:"Address on file",city:"N/A",state:"N/A",zip:"00000",country:"US"},campaign_defaults:{from_name:t.siteName,from_email:t.defaultSender,subject:" ",language:"en"}})},async delete(e){await(await n()).lists.deleteList(e.audienceId)},async get(e){let i=await(await n()).lists.getList(e);return{id:i.id,name:i.name}},async list(){return((await(await n()).lists.getAllLists({count:500})).lists??[]).map(i=>({id:i.id,name:i.name}))}},contacts:{async delete(e){await(await n()).lists.deleteListMember(e.audienceId,e.contactId)},async list(e){return((await(await n()).lists.getListMembersInfo(e.audienceId)).members??[]).map(s=>{let a=s.merge_fields;return{createdAt:typeof s.timestamp_signup=="string"?s.timestamp_signup:void 0,email:d(s.email_address),firstName:typeof a?.FNAME=="string"?a.FNAME:null,id:d(s.id,d(s.email_address)),lastName:typeof a?.LNAME=="string"?a.LNAME:null,subscribed:s.status==="subscribed"}})},async upsert(e){let i=await n(),s=e.id??u(e.email),a=e.id?e.subscribed?"subscribed":"unsubscribed":e.subscribed?"subscribed":"pending";await i.lists.setListMember(e.audienceId,s,{email_address:e.email,status:a,merge_fields:{FNAME:e.firstName??"",LNAME:e.lastName??""}},{skipMergeValidation:!0});let l=f(e.properties);l.length>0&&await i.lists.updateListMemberTags(e.audienceId,u(e.email),{tags:l.map(c=>({name:c,status:"active"}))})}},broadcasts:{async create(e){let i=await n(),s=e.templateId!=null&&String(e.templateId).trim()!==""?String(e.templateId).trim():void 0,a;if(s!=null){let c=e.html;if(c!=null&&c!=="")throw new Error("Mailchimp broadcast: use either templateId (cloud template) or html, not both.");let m=Number.parseInt(s,10);if(!Number.isFinite(m))throw new Error(`Invalid Mailchimp template id: "${s}".`);a=m}let l=await i.campaigns.create({type:"regular",recipients:{list_id:e.audienceId},settings:{authenticate:!0,auto_footer:!1,from_email:t.defaultSender,from_name:t.siteName,inline_css:!1,reply_to:e.replyTo?.trim()||t.defaultSender,subject_line:e.subject,title:e.name,to_name:"*|FNAME|*"}});if(!l.id)throw new Error("Mailchimp did not return a campaign id.");a!=null?await i.campaigns.setContent(l.id,{template:{id:a}}):await i.campaigns.setContent(l.id,{html:e.html??""})},async delete(e){await(await n()).campaigns.remove(e.broadcastId)},async list(){return((await(await n()).campaigns.list({count:500})).campaigns??[]).map(i=>{let s=i.settings,a=typeof i.send_time=="string"?i.send_time:null;return{id:d(i.id),name:d(s?.title,d(i.id)),scheduledAt:a,sentAt:a,status:i.status==="save"?"draft":d(i.status,"draft")}})},async send(e){let i=await n(),s=e.scheduledAt?.trim();s?await i.campaigns.schedule(e.broadcastId,{schedule_time:s}):await i.campaigns.send(e.broadcastId)}}}}export{h as mailchimpAdapter};
|
|
2
|
+
//# sourceMappingURL=mailchimp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/mailchimp.ts"],"sourcesContent":["import { createHash } from \"node:crypto\"\n\nimport type { MarketingAdapter } from \"../types\"\n\ninterface MailchimpLike {\n campaigns: {\n create(input: unknown): Promise<{ id?: string }>\n list(input?: unknown): Promise<{ campaigns?: Array<Record<string, unknown>> }>\n remove(id: string): Promise<unknown>\n schedule(id: string, input: unknown): Promise<unknown>\n send(id: string): Promise<unknown>\n setContent(id: string, input: unknown): Promise<unknown>\n }\n lists: {\n createList(input: unknown): Promise<unknown>\n deleteList(id: string): Promise<unknown>\n deleteListMember(listId: string, contactId: string): Promise<unknown>\n getAllLists(input?: unknown): Promise<{ lists?: Array<{ id: string; name: string }> }>\n getList(id: string): Promise<{ id: string; name: string }>\n getListMembersInfo(input: string): Promise<{ members?: Array<Record<string, unknown>> }>\n setListMember(listId: string, hash: string, input: unknown, options?: unknown): Promise<unknown>\n updateListMemberTags(listId: string, hash: string, input: unknown): Promise<unknown>\n }\n setConfig(input: unknown): void\n}\n\nexport interface MailchimpAdapterOptions {\n apiKey: string\n client?: MailchimpLike\n defaultSender: string\n siteName: string\n}\n\nfunction subscriberHash(email: string): string {\n return createHash(\"md5\").update(email.toLowerCase()).digest(\"hex\")\n}\n\nfunction serverFromApiKey(apiKey: string): string {\n const server = apiKey.includes(\"-\") ? apiKey.split(\"-\").pop() : undefined\n if (!server) {\n throw new Error(\"MAILCHIMP_API_KEY must include a datacenter suffix (e.g. key-us21).\")\n }\n return server\n}\n\nfunction tagNamesFromProperties(properties?: Record<string, string | number | null>): string[] {\n const raw = properties?.tags\n if (raw == null) {\n return []\n }\n return String(raw)\n .split(\",\")\n .map((tag) => tag.trim())\n .filter(Boolean)\n}\n\nfunction stringValue(value: unknown, fallback = \"\"): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nexport function mailchimpAdapter(options: MailchimpAdapterOptions): MarketingAdapter {\n let configured = false\n const getClient = async (): Promise<MailchimpLike> => {\n const client =\n options.client ??\n ((await import(\"@mailchimp/mailchimp_marketing\")) as { default: MailchimpLike }).default\n if (!configured) {\n client.setConfig({ apiKey: options.apiKey, server: serverFromApiKey(options.apiKey) })\n configured = true\n }\n return client\n }\n const adminBase = `https://${serverFromApiKey(options.apiKey)}.admin.mailchimp.com`\n\n return {\n provider: \"mailchimp\",\n label: \"Mailchimp\",\n urls: {\n audiences: `${adminBase}/audience/`,\n broadcasts: `${adminBase}/campaigns/`,\n },\n audiences: {\n async create(input) {\n await (\n await getClient()\n ).lists.createList({\n name: input.name,\n permission_reminder: `You're receiving this email because you opted in via ${options.siteName}.`,\n email_type_option: true,\n contact: {\n company: options.siteName,\n address1: \"Address on file\",\n city: \"N/A\",\n state: \"N/A\",\n zip: \"00000\",\n country: \"US\",\n },\n campaign_defaults: {\n from_name: options.siteName,\n from_email: options.defaultSender,\n subject: \" \",\n language: \"en\",\n },\n })\n },\n async delete(input) {\n await (await getClient()).lists.deleteList(input.audienceId)\n },\n async get(id) {\n const list = await (await getClient()).lists.getList(id)\n return { id: list.id, name: list.name }\n },\n async list() {\n const result = await (await getClient()).lists.getAllLists({ count: 500 })\n return (result.lists ?? []).map((list) => ({ id: list.id, name: list.name }))\n },\n },\n contacts: {\n async delete(input) {\n await (await getClient()).lists.deleteListMember(input.audienceId, input.contactId)\n },\n async list(input) {\n const result = await (await getClient()).lists.getListMembersInfo(input.audienceId)\n return (result.members ?? []).map((member) => {\n const mergeFields = member.merge_fields as Record<string, unknown> | undefined\n return {\n createdAt:\n typeof member.timestamp_signup === \"string\" ? member.timestamp_signup : undefined,\n email: stringValue(member.email_address),\n firstName: typeof mergeFields?.FNAME === \"string\" ? mergeFields.FNAME : null,\n id: stringValue(member.id, stringValue(member.email_address)),\n lastName: typeof mergeFields?.LNAME === \"string\" ? mergeFields.LNAME : null,\n subscribed: member.status === \"subscribed\",\n }\n })\n },\n async upsert(input) {\n const client = await getClient()\n const hash = input.id ?? subscriberHash(input.email)\n const status = input.id\n ? input.subscribed\n ? \"subscribed\"\n : \"unsubscribed\"\n : input.subscribed\n ? \"subscribed\"\n : \"pending\"\n await client.lists.setListMember(\n input.audienceId,\n hash,\n {\n email_address: input.email,\n status,\n merge_fields: { FNAME: input.firstName ?? \"\", LNAME: input.lastName ?? \"\" },\n },\n { skipMergeValidation: true },\n )\n const tags = tagNamesFromProperties(input.properties)\n if (tags.length > 0) {\n await client.lists.updateListMemberTags(input.audienceId, subscriberHash(input.email), {\n tags: tags.map((name) => ({ name, status: \"active\" })),\n })\n }\n },\n },\n broadcasts: {\n async create(input) {\n const client = await getClient()\n const templateIdRaw =\n input.templateId != null && String(input.templateId).trim() !== \"\"\n ? String(input.templateId).trim()\n : undefined\n let templateIdParsed: number | undefined\n if (templateIdRaw != null) {\n const html = input.html\n if (html != null && html !== \"\") {\n throw new Error(\n \"Mailchimp broadcast: use either templateId (cloud template) or html, not both.\",\n )\n }\n const parsed = Number.parseInt(templateIdRaw, 10)\n if (!Number.isFinite(parsed)) {\n throw new Error(`Invalid Mailchimp template id: \"${templateIdRaw}\".`)\n }\n templateIdParsed = parsed\n }\n const campaign = await client.campaigns.create({\n type: \"regular\",\n recipients: { list_id: input.audienceId },\n settings: {\n authenticate: true,\n auto_footer: false,\n from_email: options.defaultSender,\n from_name: options.siteName,\n inline_css: false,\n reply_to: input.replyTo?.trim() || options.defaultSender,\n subject_line: input.subject,\n title: input.name,\n to_name: \"*|FNAME|*\",\n },\n })\n if (!campaign.id) {\n throw new Error(\"Mailchimp did not return a campaign id.\")\n }\n if (templateIdParsed != null) {\n await client.campaigns.setContent(campaign.id, {\n template: { id: templateIdParsed },\n })\n } else {\n await client.campaigns.setContent(campaign.id, { html: input.html ?? \"\" })\n }\n },\n async delete(input) {\n await (await getClient()).campaigns.remove(input.broadcastId)\n },\n async list() {\n const result = await (await getClient()).campaigns.list({ count: 500 })\n return (result.campaigns ?? []).map((campaign) => {\n const settings = campaign.settings as Record<string, unknown> | undefined\n const sentAt = typeof campaign.send_time === \"string\" ? campaign.send_time : null\n return {\n id: stringValue(campaign.id),\n name: stringValue(settings?.title, stringValue(campaign.id)),\n scheduledAt: sentAt,\n sentAt,\n status: campaign.status === \"save\" ? \"draft\" : stringValue(campaign.status, \"draft\"),\n }\n })\n },\n async send(input) {\n const client = await getClient()\n const scheduledAt = input.scheduledAt?.trim()\n if (scheduledAt) {\n await client.campaigns.schedule(input.broadcastId, { schedule_time: scheduledAt })\n } else {\n await client.campaigns.send(input.broadcastId)\n }\n },\n },\n }\n}\n"],"mappings":"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","names":["createHash","subscriberHash","email","serverFromApiKey","apiKey","server","tagNamesFromProperties","properties","raw","tag","stringValue","value","fallback","mailchimpAdapter","options","configured","getClient","client","adminBase","input","id","list","member","mergeFields","hash","status","tags","name","templateIdRaw","templateIdParsed","html","parsed","campaign","settings","sentAt","scheduledAt"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var m=Object.create;var i=Object.defineProperty;var u=Object.getOwnPropertyDescriptor;var l=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var f=(t,a)=>{for(var e in a)i(t,e,{get:a[e],enumerable:!0})},o=(t,a,e,s)=>{if(a&&typeof a=="object"||typeof a=="function")for(let n of l(a))!w.call(t,n)&&n!==e&&i(t,n,{get:()=>a[n],enumerable:!(s=u(a,n))||s.enumerable});return t};var p=(t,a,e)=>(e=t!=null?m(g(t)):{},o(a||!t||!t.__esModule?i(e,"default",{value:t,enumerable:!0}):e,t)),y=t=>o(i({},"__esModule",{value:!0}),t);var h={};f(h,{resendAdapter:()=>b});module.exports=y(h);function r(t){let a=typeof t=="object"&&t&&"error"in t?t.error:void 0;if(a&&typeof a=="object"&&"message"in a)throw new Error(String(a.message))}function d(t,a){return typeof t=="string"?t:typeof t=="number"&&Number.isFinite(t)?String(t):a}function k(t){return{id:d(t.id,""),name:d(t.name,""),scheduledAt:typeof t.scheduled_at=="string"?t.scheduled_at:null,sentAt:typeof t.sent_at=="string"?t.sent_at:null,status:d(t.status,"draft")}}function b(t){let a=async()=>{if(t.client)return t.client;let e=await import("resend");return new e.Resend(t.apiKey)};return{provider:"resend",label:"Resend",urls:{audiences:"https://resend.com/audiences",audience:e=>`https://resend.com/audiences/${e}`,broadcasts:"https://resend.com/broadcasts",broadcast:e=>`https://resend.com/broadcasts/${e}`},audiences:{async create(e){r(await(await a()).segments.create({name:e.name}))},async delete(e){r(await(await a()).segments.remove(e.audienceId))},async get(e){let s=await(await a()).segments.get(e);return r(s),s.data?{id:s.data.id,name:s.data.name}:null},async list(){let e=await(await a()).segments.list();return r(e),e.data?.data??[]}},contacts:{async delete(e){r(await(await a()).contacts.remove({audienceId:e.audienceId,id:e.contactId}))},async list(e){let s=await(await a()).contacts.list({audienceId:e.audienceId});return r(s),(s.data?.data??[]).map(n=>({createdAt:typeof n.created_at=="string"?n.created_at:void 0,email:d(n.email,""),firstName:typeof n.first_name=="string"?n.first_name:null,id:String(n.id),lastName:typeof n.last_name=="string"?n.last_name:null,subscribed:n.unsubscribed===!1}))},async upsert(e){let s=await a(),n=!e.subscribed,c={audienceId:e.audienceId,email:e.email,firstName:e.firstName,lastName:e.lastName,unsubscribed:n};r(e.id?await s.contacts.update({...c,id:e.id}):await s.contacts.create(c))}},broadcasts:{async create(e){if(e.templateId!=null&&String(e.templateId).trim()!=="")throw new Error("Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.");r(await(await a()).broadcasts.create({audienceId:e.audienceId,from:t.defaultSender,html:e.html,name:e.name,react:e.react,replyTo:e.replyTo,subject:e.subject}))},async delete(e){r(await(await a()).broadcasts.remove(e.broadcastId))},async list(){let e=await(await a()).broadcasts.list();return r(e),(e.data?.data??[]).map(s=>k(s))},async send(e){r(await(await a()).broadcasts.send(e.broadcastId,{scheduledAt:e.scheduledAt}))}}}}0&&(module.exports={resendAdapter});
|
|
2
|
+
//# sourceMappingURL=resend.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/resend.ts"],"sourcesContent":["import type { MarketingAdapter, MarketingBroadcast } from \"../types\"\n\ninterface ResendLike {\n broadcasts: {\n create(input: unknown): Promise<unknown>\n list(): Promise<{\n data?: { data?: Array<Record<string, unknown>> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n send(id: string, input: unknown): Promise<unknown>\n }\n contacts: {\n create(input: unknown): Promise<{ data?: { id?: string }; error?: { message?: string } }>\n list(\n input: unknown,\n ): Promise<{ data?: { data?: Array<Record<string, unknown>> }; error?: { message?: string } }>\n remove(input: unknown): Promise<unknown>\n update(input: unknown): Promise<unknown>\n }\n segments: {\n create(input: unknown): Promise<unknown>\n get(id: string): Promise<{ data?: { id: string; name: string }; error?: { message?: string } }>\n list(): Promise<{\n data?: { data?: Array<{ id: string; name: string }> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n }\n}\n\nexport interface ResendAdapterOptions {\n apiKey?: string\n client?: ResendLike\n defaultSender?: string\n}\n\nfunction assertNoResendError(result: unknown) {\n const error = typeof result === \"object\" && result && \"error\" in result ? result.error : undefined\n if (error && typeof error === \"object\" && \"message\" in error) {\n throw new Error(String(error.message))\n }\n}\n\nfunction stringifyFromRecord(value: unknown, fallback: string): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nfunction mapBroadcast(row: Record<string, unknown>): MarketingBroadcast {\n return {\n id: stringifyFromRecord(row.id, \"\"),\n name: stringifyFromRecord(row.name, \"\"),\n scheduledAt: typeof row.scheduled_at === \"string\" ? row.scheduled_at : null,\n sentAt: typeof row.sent_at === \"string\" ? row.sent_at : null,\n status: stringifyFromRecord(row.status, \"draft\"),\n }\n}\n\nexport function resendAdapter(options: ResendAdapterOptions): MarketingAdapter {\n const getClient = async (): Promise<ResendLike> => {\n if (options.client) {\n return options.client\n }\n const resendModule = (await import(\"resend\")) as { Resend: new (key?: string) => unknown }\n return new resendModule.Resend(options.apiKey) as ResendLike\n }\n\n return {\n provider: \"resend\",\n label: \"Resend\",\n urls: {\n audiences: \"https://resend.com/audiences\",\n audience: (id) => `https://resend.com/audiences/${id}`,\n broadcasts: \"https://resend.com/broadcasts\",\n broadcast: (id) => `https://resend.com/broadcasts/${id}`,\n },\n audiences: {\n async create(input) {\n assertNoResendError(await (await getClient()).segments.create({ name: input.name }))\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).segments.remove(input.audienceId))\n },\n async get(id) {\n const result = await (await getClient()).segments.get(id)\n assertNoResendError(result)\n return result.data ? { id: result.data.id, name: result.data.name } : null\n },\n async list() {\n const result = await (await getClient()).segments.list()\n assertNoResendError(result)\n return result.data?.data ?? []\n },\n },\n contacts: {\n async delete(input) {\n assertNoResendError(\n await (\n await getClient()\n ).contacts.remove({ audienceId: input.audienceId, id: input.contactId }),\n )\n },\n async list(input) {\n const result = await (await getClient()).contacts.list({ audienceId: input.audienceId })\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => ({\n createdAt: typeof row.created_at === \"string\" ? row.created_at : undefined,\n email: stringifyFromRecord(row.email, \"\"),\n firstName: typeof row.first_name === \"string\" ? row.first_name : null,\n id: String(row.id),\n lastName: typeof row.last_name === \"string\" ? row.last_name : null,\n subscribed: row.unsubscribed === false,\n }))\n },\n async upsert(input) {\n const client = await getClient()\n const unsubscribed = !input.subscribed\n const payload = {\n audienceId: input.audienceId,\n email: input.email,\n firstName: input.firstName,\n lastName: input.lastName,\n unsubscribed,\n }\n assertNoResendError(\n input.id\n ? await client.contacts.update({ ...payload, id: input.id })\n : await client.contacts.create(payload),\n )\n },\n },\n broadcasts: {\n async create(input) {\n if (input.templateId != null && String(input.templateId).trim() !== \"\") {\n throw new Error(\n \"Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.\",\n )\n }\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.create({\n audienceId: input.audienceId,\n from: options.defaultSender,\n html: input.html,\n name: input.name,\n react: input.react,\n replyTo: input.replyTo,\n subject: input.subject,\n }),\n )\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).broadcasts.remove(input.broadcastId))\n },\n async list() {\n const result = await (await getClient()).broadcasts.list()\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => mapBroadcast(row))\n },\n async send(input) {\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.send(input.broadcastId, { scheduledAt: input.scheduledAt }),\n )\n },\n },\n }\n}\n"],"mappings":"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","names":["resend_exports","__export","resendAdapter","__toCommonJS","assertNoResendError","result","error","stringifyFromRecord","value","fallback","mapBroadcast","row","options","getClient","resendModule","id","input","client","unsubscribed","payload"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function r(t){let a=typeof t=="object"&&t&&"error"in t?t.error:void 0;if(a&&typeof a=="object"&&"message"in a)throw new Error(String(a.message))}function i(t,a){return typeof t=="string"?t:typeof t=="number"&&Number.isFinite(t)?String(t):a}function c(t){return{id:i(t.id,""),name:i(t.name,""),scheduledAt:typeof t.scheduled_at=="string"?t.scheduled_at:null,sentAt:typeof t.sent_at=="string"?t.sent_at:null,status:i(t.status,"draft")}}function o(t){let a=async()=>{if(t.client)return t.client;let e=await import("resend");return new e.Resend(t.apiKey)};return{provider:"resend",label:"Resend",urls:{audiences:"https://resend.com/audiences",audience:e=>`https://resend.com/audiences/${e}`,broadcasts:"https://resend.com/broadcasts",broadcast:e=>`https://resend.com/broadcasts/${e}`},audiences:{async create(e){r(await(await a()).segments.create({name:e.name}))},async delete(e){r(await(await a()).segments.remove(e.audienceId))},async get(e){let n=await(await a()).segments.get(e);return r(n),n.data?{id:n.data.id,name:n.data.name}:null},async list(){let e=await(await a()).segments.list();return r(e),e.data?.data??[]}},contacts:{async delete(e){r(await(await a()).contacts.remove({audienceId:e.audienceId,id:e.contactId}))},async list(e){let n=await(await a()).contacts.list({audienceId:e.audienceId});return r(n),(n.data?.data??[]).map(s=>({createdAt:typeof s.created_at=="string"?s.created_at:void 0,email:i(s.email,""),firstName:typeof s.first_name=="string"?s.first_name:null,id:String(s.id),lastName:typeof s.last_name=="string"?s.last_name:null,subscribed:s.unsubscribed===!1}))},async upsert(e){let n=await a(),s=!e.subscribed,d={audienceId:e.audienceId,email:e.email,firstName:e.firstName,lastName:e.lastName,unsubscribed:s};r(e.id?await n.contacts.update({...d,id:e.id}):await n.contacts.create(d))}},broadcasts:{async create(e){if(e.templateId!=null&&String(e.templateId).trim()!=="")throw new Error("Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.");r(await(await a()).broadcasts.create({audienceId:e.audienceId,from:t.defaultSender,html:e.html,name:e.name,react:e.react,replyTo:e.replyTo,subject:e.subject}))},async delete(e){r(await(await a()).broadcasts.remove(e.broadcastId))},async list(){let e=await(await a()).broadcasts.list();return r(e),(e.data?.data??[]).map(n=>c(n))},async send(e){r(await(await a()).broadcasts.send(e.broadcastId,{scheduledAt:e.scheduledAt}))}}}}export{o as resendAdapter};
|
|
2
|
+
//# sourceMappingURL=resend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/resend.ts"],"sourcesContent":["import type { MarketingAdapter, MarketingBroadcast } from \"../types\"\n\ninterface ResendLike {\n broadcasts: {\n create(input: unknown): Promise<unknown>\n list(): Promise<{\n data?: { data?: Array<Record<string, unknown>> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n send(id: string, input: unknown): Promise<unknown>\n }\n contacts: {\n create(input: unknown): Promise<{ data?: { id?: string }; error?: { message?: string } }>\n list(\n input: unknown,\n ): Promise<{ data?: { data?: Array<Record<string, unknown>> }; error?: { message?: string } }>\n remove(input: unknown): Promise<unknown>\n update(input: unknown): Promise<unknown>\n }\n segments: {\n create(input: unknown): Promise<unknown>\n get(id: string): Promise<{ data?: { id: string; name: string }; error?: { message?: string } }>\n list(): Promise<{\n data?: { data?: Array<{ id: string; name: string }> }\n error?: { message?: string }\n }>\n remove(id: string): Promise<unknown>\n }\n}\n\nexport interface ResendAdapterOptions {\n apiKey?: string\n client?: ResendLike\n defaultSender?: string\n}\n\nfunction assertNoResendError(result: unknown) {\n const error = typeof result === \"object\" && result && \"error\" in result ? result.error : undefined\n if (error && typeof error === \"object\" && \"message\" in error) {\n throw new Error(String(error.message))\n }\n}\n\nfunction stringifyFromRecord(value: unknown, fallback: string): string {\n if (typeof value === \"string\") {\n return value\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value)\n }\n return fallback\n}\n\nfunction mapBroadcast(row: Record<string, unknown>): MarketingBroadcast {\n return {\n id: stringifyFromRecord(row.id, \"\"),\n name: stringifyFromRecord(row.name, \"\"),\n scheduledAt: typeof row.scheduled_at === \"string\" ? row.scheduled_at : null,\n sentAt: typeof row.sent_at === \"string\" ? row.sent_at : null,\n status: stringifyFromRecord(row.status, \"draft\"),\n }\n}\n\nexport function resendAdapter(options: ResendAdapterOptions): MarketingAdapter {\n const getClient = async (): Promise<ResendLike> => {\n if (options.client) {\n return options.client\n }\n const resendModule = (await import(\"resend\")) as { Resend: new (key?: string) => unknown }\n return new resendModule.Resend(options.apiKey) as ResendLike\n }\n\n return {\n provider: \"resend\",\n label: \"Resend\",\n urls: {\n audiences: \"https://resend.com/audiences\",\n audience: (id) => `https://resend.com/audiences/${id}`,\n broadcasts: \"https://resend.com/broadcasts\",\n broadcast: (id) => `https://resend.com/broadcasts/${id}`,\n },\n audiences: {\n async create(input) {\n assertNoResendError(await (await getClient()).segments.create({ name: input.name }))\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).segments.remove(input.audienceId))\n },\n async get(id) {\n const result = await (await getClient()).segments.get(id)\n assertNoResendError(result)\n return result.data ? { id: result.data.id, name: result.data.name } : null\n },\n async list() {\n const result = await (await getClient()).segments.list()\n assertNoResendError(result)\n return result.data?.data ?? []\n },\n },\n contacts: {\n async delete(input) {\n assertNoResendError(\n await (\n await getClient()\n ).contacts.remove({ audienceId: input.audienceId, id: input.contactId }),\n )\n },\n async list(input) {\n const result = await (await getClient()).contacts.list({ audienceId: input.audienceId })\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => ({\n createdAt: typeof row.created_at === \"string\" ? row.created_at : undefined,\n email: stringifyFromRecord(row.email, \"\"),\n firstName: typeof row.first_name === \"string\" ? row.first_name : null,\n id: String(row.id),\n lastName: typeof row.last_name === \"string\" ? row.last_name : null,\n subscribed: row.unsubscribed === false,\n }))\n },\n async upsert(input) {\n const client = await getClient()\n const unsubscribed = !input.subscribed\n const payload = {\n audienceId: input.audienceId,\n email: input.email,\n firstName: input.firstName,\n lastName: input.lastName,\n unsubscribed,\n }\n assertNoResendError(\n input.id\n ? await client.contacts.update({ ...payload, id: input.id })\n : await client.contacts.create(payload),\n )\n },\n },\n broadcasts: {\n async create(input) {\n if (input.templateId != null && String(input.templateId).trim() !== \"\") {\n throw new Error(\n \"Resend broadcasts do not support templateId; use html or react, or use the Mailchimp adapter for cloud templates.\",\n )\n }\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.create({\n audienceId: input.audienceId,\n from: options.defaultSender,\n html: input.html,\n name: input.name,\n react: input.react,\n replyTo: input.replyTo,\n subject: input.subject,\n }),\n )\n },\n async delete(input) {\n assertNoResendError(await (await getClient()).broadcasts.remove(input.broadcastId))\n },\n async list() {\n const result = await (await getClient()).broadcasts.list()\n assertNoResendError(result)\n return (result.data?.data ?? []).map((row) => mapBroadcast(row))\n },\n async send(input) {\n assertNoResendError(\n await (\n await getClient()\n ).broadcasts.send(input.broadcastId, { scheduledAt: input.scheduledAt }),\n )\n },\n },\n }\n}\n"],"mappings":"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","names":["assertNoResendError","result","error","stringifyFromRecord","value","fallback","mapBroadcast","row","resendAdapter","options","getClient","resendModule","id","input","client","unsubscribed","payload"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function CreateAudienceButton(): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function DeleteAudienceButton({ audienceId, audienceName, }: {
|
|
3
|
+
audienceId: string;
|
|
4
|
+
audienceName: string;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
//# sourceMappingURL=audience-buttons.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audience-buttons.d.ts","sourceRoot":"","sources":["../../src/admin/audience-buttons.tsx"],"names":[],"mappings":"AA4BA,wBAAgB,oBAAoB,4CAYnC;AA6DD,wBAAgB,oBAAoB,CAAC,EACnC,UAAU,EACV,YAAY,GACb,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;CACrB,2CA4CA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MarketingBroadcast } from "../types";
|
|
2
|
+
export interface MarketingBroadcastRow extends MarketingBroadcast {
|
|
3
|
+
externalDashboardUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
interface BroadcastsTableProps {
|
|
6
|
+
broadcasts: MarketingBroadcastRow[];
|
|
7
|
+
}
|
|
8
|
+
export declare function BroadcastsTable({ broadcasts }: BroadcastsTableProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function SendBroadcastButton({ broadcastId, broadcastName, }: {
|
|
10
|
+
broadcastId: string;
|
|
11
|
+
broadcastName: string;
|
|
12
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=broadcasts-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broadcasts-table.d.ts","sourceRoot":"","sources":["../../src/admin/broadcasts-table.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAGlD,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,oBAAoB,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED,UAAU,oBAAoB;IAC5B,UAAU,EAAE,qBAAqB,EAAE,CAAA;CACpC;AAED,wBAAgB,eAAe,CAAC,EAAE,UAAU,EAAE,EAAE,oBAAoB,2CAgFnE;AAsED,wBAAgB,mBAAmB,CAAC,EAClC,WAAW,EACX,aAAa,GACd,EAAE;IACD,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;CACtB,2CAkEA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import type { TextFieldClientComponent } from "payload";
|
|
2
|
+
export declare const AudienceSelect: TextFieldClientComponent;
|
|
2
3
|
export declare function MarketingMenu({ basePath }: {
|
|
3
4
|
basePath?: string;
|
|
4
5
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/admin/components.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/admin/components.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAA;AAiBvD,eAAO,MAAM,cAAc,EAAE,wBA6C5B,CAAA;AAOD,wBAAgB,aAAa,CAAC,EAAE,QAAa,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,2CAWrE;AAED,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,2CAY9F;AAED,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,2CAY7F;AAED,wBAAgB,eAAe,CAAC,EAC9B,UAAU,GACX,EAAE;IACD,UAAU,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChD,2CAYA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MarketingContact } from "../types";
|
|
2
|
+
interface ContactsTableProps {
|
|
3
|
+
audienceId: string;
|
|
4
|
+
contacts: MarketingContact[];
|
|
5
|
+
}
|
|
6
|
+
export declare function ContactsTable({ audienceId, contacts }: ContactsTableProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare function EditContactButton({ audienceId, contact, }: {
|
|
8
|
+
audienceId: string;
|
|
9
|
+
contact: MarketingContact | null;
|
|
10
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=contacts-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contacts-table.d.ts","sourceRoot":"","sources":["../../src/admin/contacts-table.tsx"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAIhD,UAAU,kBAAkB;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,gBAAgB,EAAE,CAAA;CAC7B;AAED,wBAAgB,aAAa,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,kBAAkB,2CAgFzE;AAwDD,wBAAgB,iBAAiB,CAAC,EAChC,UAAU,EACV,OAAO,GACR,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAA;CACjC,2CAgBA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MarketingAudience } from "../types";
|
|
2
|
+
export declare function CreateBroadcastButton({ audiences, provider, }: {
|
|
3
|
+
audiences: MarketingAudience[];
|
|
4
|
+
provider: string;
|
|
5
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
//# sourceMappingURL=create-broadcast-button.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-broadcast-button.d.ts","sourceRoot":"","sources":["../../src/admin/create-broadcast-button.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAMjD,wBAAgB,qBAAqB,CAAC,EACpC,SAAS,EACT,QAAQ,GACT,EAAE;IACD,SAAS,EAAE,iBAAiB,EAAE,CAAA;IAC9B,QAAQ,EAAE,MAAM,CAAA;CACjB,2CAYA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date-format.d.ts","sourceRoot":"","sources":["../../src/admin/date-format.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAM/D"}
|
package/dist/admin/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var R=Object.create;var p=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var q=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var S=(e,t)=>{for(var r in t)p(e,r,{get:t[r],enumerable:!0})},b=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of N(t))!E.call(e,i)&&i!==r&&p(e,i,{get:()=>t[i],enumerable:!(o=$(t,i))||o.enumerable});return e};var _=(e,t,r)=>(r=e!=null?R(q(e)):{},b(t||!e||!e.__esModule?p(r,"default",{value:e,enumerable:!0}):r,e)),F=e=>b(p({},"__esModule",{value:!0}),e);var I={};S(I,{AudienceDetail:()=>T,AudienceList:()=>L,AudienceSelect:()=>h,AudienceTable:()=>M,BroadcastList:()=>B,BroadcastsTable:()=>C,ContactsTable:()=>w,MarketingMenu:()=>x,defaultAdminComponentPath:()=>D});module.exports=F(I);var f=_(require("react"),1),c=require("@payloadcms/ui");var A=require("@payloadcms/ui"),m=require("react");function k(){let e=(0,A.useConfig)(),t=(0,m.useMemo)(()=>`${e.serverURL??""}${e.routes?.api??"/api"}`,[e.routes?.api,e.serverURL]),r=(0,m.useCallback)(async(o,i)=>{let{headers:l,...s}=i??{},u=new Headers(i?.headers);s.body!==void 0&&s.body!==""&&s.body!==null&&(u.has("Content-Type")||u.set("Content-Type","application/json"));let a=await fetch(`${t}${o}`,{...s,credentials:"include",headers:u});if(!a.ok){let d=`${a.status} ${a.statusText}`;try{let y=await a.json();typeof y.message=="string"&&(d=y.message)}catch{}throw new Error(d)}if(a.status!==204)try{return await a.json()}catch{return}},[t]);return{base:t,requestJson:r}}var n=require("react/jsx-runtime");function j(e){if(!Array.isArray(e))return[];let t=[];for(let r of e){if(!r||typeof r!="object")continue;let o=r,i=o.id,l=o.name;typeof i=="string"&&typeof l=="string"&&t.push({id:i,name:l})}return t}var h=({field:e,path:t,readOnly:r})=>{let{requestJson:o}=k(),[i,l]=f.default.useState([]),[s,u]=f.default.useState(null);return f.default.useEffect(()=>{let a=!1;return(async()=>{try{let d=await o("/marketing/audiences");a||(l(j(d)),u(null))}catch(d){a||u(d instanceof Error?d.message:"Failed to load audiences")}})(),()=>{a=!0}},[o]),(0,n.jsxs)("div",{className:"field-type relative",children:[s?(0,n.jsx)("p",{className:"text-red-500",role:"alert",children:s}):null,(0,n.jsx)(c.SelectField,{field:{label:typeof e.label=="string"?e.label:"Audience",name:e.name,options:i.map(a=>({label:a.name,value:a.id})),required:e.required===!0,type:"select"},path:t,readOnly:r})]})};function v(e,t){return["/admin",e?.replace(/^\/+|\/+$/g,""),t].filter(Boolean).join("/")}function x({basePath:e=""}){return(0,n.jsxs)(c.NavGroup,{isOpen:!0,label:"Marketing",children:[(0,n.jsx)(c.Link,{className:"nav__link",href:v(e,"audience"),children:"Audience"}),(0,n.jsx)(c.Link,{className:"nav__link",href:v(e,"broadcast"),children:"Broadcast"})]})}function M({audiences:e}){return(0,n.jsx)("table",{children:(0,n.jsx)("tbody",{children:e.map(t=>(0,n.jsx)("tr",{children:(0,n.jsx)("td",{children:t.name})},t.id))})})}function w({contacts:e}){return(0,n.jsx)("table",{children:(0,n.jsx)("tbody",{children:e.map(t=>(0,n.jsx)("tr",{children:(0,n.jsx)("td",{children:t.email})},t.id))})})}function C({broadcasts:e}){return(0,n.jsx)("table",{children:(0,n.jsx)("tbody",{children:e.map(t=>(0,n.jsx)("tr",{children:(0,n.jsx)("td",{children:t.name})},t.id))})})}var g=require("react/jsx-runtime");function L(){return(0,g.jsx)("div",{children:"Audience"})}function T(){return(0,g.jsx)("div",{children:"Audience Detail"})}function B(){return(0,g.jsx)("div",{children:"Broadcasts"})}var D="payload-plugin-marketing/admin";0&&(module.exports={AudienceDetail,AudienceList,AudienceSelect,AudienceTable,BroadcastList,BroadcastsTable,ContactsTable,MarketingMenu,defaultAdminComponentPath});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/admin/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/index.ts","../../src/admin/components.tsx","../../src/admin/views.tsx"],"sourcesContent":["export const defaultAdminComponentPath = \"payload-plugin-marketing/admin\"\n\nexport {\n AudienceSelect,\n AudienceTable,\n BroadcastsTable,\n ContactsTable,\n MarketingMenu,\n} from \"./components\"\nexport { AudienceDetail, AudienceList, BroadcastList } from \"./views\"\n","\"use client\"\n\nimport React from \"react\"\n\nexport function AudienceSelect() {\n return null\n}\n\nfunction adminHref(basePath: string | undefined, segment: string): string {\n const normalized = basePath?.replace(/^\\/+|\\/+$/g, \"\")\n return [\"/admin\", normalized, segment].filter(Boolean).join(\"/\")\n}\n\nexport function MarketingMenu({ basePath = \"\" }: { basePath?: string }) {\n return (\n <nav>\n <a href={adminHref(basePath, \"audience\")}>Audience</a>\n <a href={adminHref(basePath, \"broadcast\")}>Broadcasts</a>\n </nav>\n )\n}\n\nexport function AudienceTable({ audiences }: { audiences: Array<{ id: string; name: string }> }) {\n return (\n <table>\n <tbody>\n {audiences.map((audience) => (\n <tr key={audience.id}>\n <td>{audience.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function ContactsTable({ contacts }: { contacts: Array<{ email: string; id: string }> }) {\n return (\n <table>\n <tbody>\n {contacts.map((contact) => (\n <tr key={contact.id}>\n <td>{contact.email}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function BroadcastsTable({\n broadcasts,\n}: {\n broadcasts: Array<{ id: string; name: string }>\n}) {\n return (\n <table>\n <tbody>\n {broadcasts.map((broadcast) => (\n <tr key={broadcast.id}>\n <td>{broadcast.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n","import React from \"react\"\n\nexport function AudienceList() {\n return <div>Audience</div>\n}\n\nexport function AudienceDetail() {\n return <div>Audience Detail</div>\n}\n\nexport function BroadcastList() {\n return <div>Broadcasts</div>\n}\n"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,oBAAAE,EAAA,iBAAAC,EAAA,mBAAAC,EAAA,kBAAAC,EAAA,kBAAAC,EAAA,oBAAAC,EAAA,kBAAAC,EAAA,kBAAAC,EAAA,8BAAAC,IAAA,eAAAC,EAAAX,GCeI,IAAAY,EAAA,6BAXG,SAASC,GAAiB,CAC/B,OAAO,IACT,CAEA,SAASC,EAAUC,EAA8BC,EAAyB,CAExE,MAAO,CAAC,SADWD,GAAU,QAAQ,aAAc,EAAE,EACvBC,CAAO,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,CACjE,CAEO,SAASC,EAAc,CAAE,SAAAF,EAAW,EAAG,EAA0B,CACtE,SACE,QAAC,OACC,oBAAC,KAAE,KAAMD,EAAUC,EAAU,UAAU,EAAG,oBAAQ,KAClD,OAAC,KAAE,KAAMD,EAAUC,EAAU,WAAW,EAAG,sBAAU,GACvD,CAEJ,CAEO,SAASG,EAAc,CAAE,UAAAC,CAAU,EAAuD,CAC/F,SACE,OAAC,SACC,mBAAC,SACE,SAAAA,EAAU,IAAKC,MACd,OAAC,MACC,mBAAC,MAAI,SAAAA,EAAS,KAAK,GADZA,EAAS,EAElB,CACD,EACH,EACF,CAEJ,CAEO,SAASC,EAAc,CAAE,SAAAC,CAAS,EAAuD,CAC9F,SACE,OAAC,SACC,mBAAC,SACE,SAAAA,EAAS,IAAKC,MACb,OAAC,MACC,mBAAC,MAAI,SAAAA,EAAQ,MAAM,GADZA,EAAQ,EAEjB,CACD,EACH,EACF,CAEJ,CAEO,SAASC,EAAgB,CAC9B,WAAAC,CACF,EAEG,CACD,SACE,OAAC,SACC,mBAAC,SACE,SAAAA,EAAW,IAAKC,MACf,OAAC,MACC,mBAAC,MAAI,SAAAA,EAAU,KAAK,GADbA,EAAU,EAEnB,CACD,EACH,EACF,CAEJ,CC/DS,IAAAC,EAAA,6BADF,SAASC,GAAe,CAC7B,SAAO,OAAC,OAAI,oBAAQ,CACtB,CAEO,SAASC,GAAiB,CAC/B,SAAO,OAAC,OAAI,2BAAe,CAC7B,CAEO,SAASC,GAAgB,CAC9B,SAAO,OAAC,OAAI,sBAAU,CACxB,CFZO,IAAMC,EAA4B","names":["admin_exports","__export","AudienceDetail","AudienceList","AudienceSelect","AudienceTable","BroadcastList","BroadcastsTable","ContactsTable","MarketingMenu","defaultAdminComponentPath","__toCommonJS","import_jsx_runtime","AudienceSelect","adminHref","basePath","segment","MarketingMenu","AudienceTable","audiences","audience","ContactsTable","contacts","contact","BroadcastsTable","broadcasts","broadcast","import_jsx_runtime","AudienceList","AudienceDetail","BroadcastList","defaultAdminComponentPath"]}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/index.ts","../../src/admin/components.tsx","../../src/admin/use-marketing-api.ts","../../src/admin/views.tsx"],"sourcesContent":["export const defaultAdminComponentPath = \"payload-plugin-marketing/admin\"\n\nexport {\n AudienceSelect,\n AudienceTable,\n BroadcastsTable,\n ContactsTable,\n MarketingMenu,\n} from \"./components\"\nexport { AudienceDetail, AudienceList, BroadcastList } from \"./views\"\n","\"use client\"\n\nimport React from \"react\"\nimport { Link, NavGroup, SelectField } from \"@payloadcms/ui\"\n\nimport { useMarketingApi } from \"./use-marketing-api\"\n\nimport type { MarketingAudience } from \"../types\"\nimport type { TextFieldClientComponent } from \"payload\"\n\nfunction parseAudiences(payload: unknown): MarketingAudience[] {\n if (!Array.isArray(payload)) return []\n const out: MarketingAudience[] = []\n for (const item of payload) {\n if (!item || typeof item !== \"object\") continue\n const rec = item as Record<string, unknown>\n const id = rec.id\n const name = rec.name\n if (typeof id === \"string\" && typeof name === \"string\") {\n out.push({ id, name })\n }\n }\n return out\n}\n\nexport const AudienceSelect: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { requestJson } = useMarketingApi()\n const [audiences, setAudiences] = React.useState<MarketingAudience[]>([])\n const [loadError, setLoadError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n void (async () => {\n try {\n const data = await requestJson(\"/marketing/audiences\")\n if (!cancelled) {\n setAudiences(parseAudiences(data))\n setLoadError(null)\n }\n } catch (err) {\n if (!cancelled) {\n setLoadError(err instanceof Error ? err.message : \"Failed to load audiences\")\n }\n }\n })()\n return () => {\n cancelled = true\n }\n }, [requestJson])\n\n return (\n <div className=\"field-type relative\">\n {loadError ? (\n <p className=\"text-red-500\" role=\"alert\">\n {loadError}\n </p>\n ) : null}\n <SelectField\n field={{\n label: typeof field.label === \"string\" ? field.label : \"Audience\",\n name: field.name,\n options: audiences.map((a) => ({ label: a.name, value: a.id })),\n required: field.required === true,\n type: \"select\",\n }}\n path={path}\n readOnly={readOnly}\n />\n </div>\n )\n}\n\nfunction adminHref(basePath: string | undefined, segment: string): string {\n const normalized = basePath?.replace(/^\\/+|\\/+$/g, \"\")\n return [\"/admin\", normalized, segment].filter(Boolean).join(\"/\")\n}\n\nexport function MarketingMenu({ basePath = \"\" }: { basePath?: string }) {\n return (\n <NavGroup isOpen label=\"Marketing\">\n <Link className=\"nav__link\" href={adminHref(basePath, \"audience\")}>\n Audience\n </Link>\n <Link className=\"nav__link\" href={adminHref(basePath, \"broadcast\")}>\n Broadcast\n </Link>\n </NavGroup>\n )\n}\n\nexport function AudienceTable({ audiences }: { audiences: Array<{ id: string; name: string }> }) {\n return (\n <table>\n <tbody>\n {audiences.map((audience) => (\n <tr key={audience.id}>\n <td>{audience.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function ContactsTable({ contacts }: { contacts: Array<{ email: string; id: string }> }) {\n return (\n <table>\n <tbody>\n {contacts.map((contact) => (\n <tr key={contact.id}>\n <td>{contact.email}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function BroadcastsTable({\n broadcasts,\n}: {\n broadcasts: Array<{ id: string; name: string }>\n}) {\n return (\n <table>\n <tbody>\n {broadcasts.map((broadcast) => (\n <tr key={broadcast.id}>\n <td>{broadcast.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n","\"use client\"\n\nimport { useConfig } from \"@payloadcms/ui\"\nimport { useCallback, useMemo } from \"react\"\n\nexport function useMarketingApi() {\n const context = useConfig() as unknown as {\n routes?: { api?: string }\n serverURL?: string\n }\n\n const base = useMemo(() => `${context.serverURL ?? \"\"}${context.routes?.api ?? \"/api\"}`, [\n context.routes?.api,\n context.serverURL,\n ])\n\n const requestJson = useCallback(\n async (pathSegment: string, init?: RequestInit): Promise<unknown> => {\n const { headers: _headersIgnored, ...restInit } = init ?? {}\n const headers = new Headers(init?.headers)\n if (\n restInit.body !== undefined &&\n restInit.body !== \"\" &&\n restInit.body !== null\n ) {\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\")\n }\n }\n\n const res = await fetch(`${base}${pathSegment}`, {\n ...restInit,\n credentials: \"include\",\n headers,\n })\n\n if (!res.ok) {\n let detail = `${res.status} ${res.statusText}`\n try {\n const parsed = (await res.json()) as { message?: string }\n if (typeof parsed.message === \"string\") detail = parsed.message\n } catch {\n //\n }\n throw new Error(detail)\n }\n\n if (res.status === 204) {\n return undefined\n }\n\n try {\n return await res.json()\n } catch {\n return undefined\n }\n },\n [base],\n )\n\n return { base, requestJson }\n}\n","import React from \"react\"\n\nexport function AudienceList() {\n return <div>Audience</div>\n}\n\nexport function AudienceDetail() {\n return <div>Audience Detail</div>\n}\n\nexport function BroadcastList() {\n return <div>Broadcasts</div>\n}\n"],"mappings":"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","names":["admin_exports","__export","AudienceDetail","AudienceList","AudienceSelect","AudienceTable","BroadcastList","BroadcastsTable","ContactsTable","MarketingMenu","defaultAdminComponentPath","__toCommonJS","import_react","import_ui","import_ui","import_react","useMarketingApi","context","base","requestJson","pathSegment","init","_headersIgnored","restInit","headers","res","detail","parsed","import_jsx_runtime","parseAudiences","payload","out","item","rec","id","name","AudienceSelect","field","path","readOnly","requestJson","useMarketingApi","audiences","setAudiences","React","loadError","setLoadError","cancelled","data","err","adminHref","basePath","segment","MarketingMenu","AudienceTable","audience","ContactsTable","contacts","contact","BroadcastsTable","broadcasts","broadcast","import_jsx_runtime","AudienceList","AudienceDetail","BroadcastList","defaultAdminComponentPath"]}
|
package/dist/admin/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import l from"react";import{Link as g,NavGroup as h,SelectField as x}from"@payloadcms/ui";import{useConfig as A}from"@payloadcms/ui";import{useCallback as k,useMemo as v}from"react";function f(){let e=A(),t=v(()=>`${e.serverURL??""}${e.routes?.api??"/api"}`,[e.routes?.api,e.serverURL]),i=k(async(a,o)=>{let{headers:u,...s}=o??{},c=new Headers(o?.headers);s.body!==void 0&&s.body!==""&&s.body!==null&&(c.has("Content-Type")||c.set("Content-Type","application/json"));let r=await fetch(`${t}${a}`,{...s,credentials:"include",headers:c});if(!r.ok){let d=`${r.status} ${r.statusText}`;try{let m=await r.json();typeof m.message=="string"&&(d=m.message)}catch{}throw new Error(d)}if(r.status!==204)try{return await r.json()}catch{return}},[t]);return{base:t,requestJson:i}}import{jsx as n,jsxs as b}from"react/jsx-runtime";function M(e){if(!Array.isArray(e))return[];let t=[];for(let i of e){if(!i||typeof i!="object")continue;let a=i,o=a.id,u=a.name;typeof o=="string"&&typeof u=="string"&&t.push({id:o,name:u})}return t}var w=({field:e,path:t,readOnly:i})=>{let{requestJson:a}=f(),[o,u]=l.useState([]),[s,c]=l.useState(null);return l.useEffect(()=>{let r=!1;return(async()=>{try{let d=await a("/marketing/audiences");r||(u(M(d)),c(null))}catch(d){r||c(d instanceof Error?d.message:"Failed to load audiences")}})(),()=>{r=!0}},[a]),b("div",{className:"field-type relative",children:[s?n("p",{className:"text-red-500",role:"alert",children:s}):null,n(x,{field:{label:typeof e.label=="string"?e.label:"Audience",name:e.name,options:o.map(r=>({label:r.name,value:r.id})),required:e.required===!0,type:"select"},path:t,readOnly:i})]})};function y(e,t){return["/admin",e?.replace(/^\/+|\/+$/g,""),t].filter(Boolean).join("/")}function C({basePath:e=""}){return b(h,{isOpen:!0,label:"Marketing",children:[n(g,{className:"nav__link",href:y(e,"audience"),children:"Audience"}),n(g,{className:"nav__link",href:y(e,"broadcast"),children:"Broadcast"})]})}function L({audiences:e}){return n("table",{children:n("tbody",{children:e.map(t=>n("tr",{children:n("td",{children:t.name})},t.id))})})}function T({contacts:e}){return n("table",{children:n("tbody",{children:e.map(t=>n("tr",{children:n("td",{children:t.email})},t.id))})})}function B({broadcasts:e}){return n("table",{children:n("tbody",{children:e.map(t=>n("tr",{children:n("td",{children:t.name})},t.id))})})}import{jsx as p}from"react/jsx-runtime";function R(){return p("div",{children:"Audience"})}function $(){return p("div",{children:"Audience Detail"})}function N(){return p("div",{children:"Broadcasts"})}var G="payload-plugin-marketing/admin";export{$ as AudienceDetail,R as AudienceList,w as AudienceSelect,L as AudienceTable,N as BroadcastList,B as BroadcastsTable,T as ContactsTable,C as MarketingMenu,G as defaultAdminComponentPath};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/admin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/components.tsx","../../src/admin/views.tsx","../../src/admin/index.ts"],"sourcesContent":["\"use client\"\n\nimport React from \"react\"\n\nexport
|
|
1
|
+
{"version":3,"sources":["../../src/admin/components.tsx","../../src/admin/use-marketing-api.ts","../../src/admin/views.tsx","../../src/admin/index.ts"],"sourcesContent":["\"use client\"\n\nimport React from \"react\"\nimport { Link, NavGroup, SelectField } from \"@payloadcms/ui\"\n\nimport { useMarketingApi } from \"./use-marketing-api\"\n\nimport type { MarketingAudience } from \"../types\"\nimport type { TextFieldClientComponent } from \"payload\"\n\nfunction parseAudiences(payload: unknown): MarketingAudience[] {\n if (!Array.isArray(payload)) return []\n const out: MarketingAudience[] = []\n for (const item of payload) {\n if (!item || typeof item !== \"object\") continue\n const rec = item as Record<string, unknown>\n const id = rec.id\n const name = rec.name\n if (typeof id === \"string\" && typeof name === \"string\") {\n out.push({ id, name })\n }\n }\n return out\n}\n\nexport const AudienceSelect: TextFieldClientComponent = ({ field, path, readOnly }) => {\n const { requestJson } = useMarketingApi()\n const [audiences, setAudiences] = React.useState<MarketingAudience[]>([])\n const [loadError, setLoadError] = React.useState<string | null>(null)\n\n React.useEffect(() => {\n let cancelled = false\n void (async () => {\n try {\n const data = await requestJson(\"/marketing/audiences\")\n if (!cancelled) {\n setAudiences(parseAudiences(data))\n setLoadError(null)\n }\n } catch (err) {\n if (!cancelled) {\n setLoadError(err instanceof Error ? err.message : \"Failed to load audiences\")\n }\n }\n })()\n return () => {\n cancelled = true\n }\n }, [requestJson])\n\n return (\n <div className=\"field-type relative\">\n {loadError ? (\n <p className=\"text-red-500\" role=\"alert\">\n {loadError}\n </p>\n ) : null}\n <SelectField\n field={{\n label: typeof field.label === \"string\" ? field.label : \"Audience\",\n name: field.name,\n options: audiences.map((a) => ({ label: a.name, value: a.id })),\n required: field.required === true,\n type: \"select\",\n }}\n path={path}\n readOnly={readOnly}\n />\n </div>\n )\n}\n\nfunction adminHref(basePath: string | undefined, segment: string): string {\n const normalized = basePath?.replace(/^\\/+|\\/+$/g, \"\")\n return [\"/admin\", normalized, segment].filter(Boolean).join(\"/\")\n}\n\nexport function MarketingMenu({ basePath = \"\" }: { basePath?: string }) {\n return (\n <NavGroup isOpen label=\"Marketing\">\n <Link className=\"nav__link\" href={adminHref(basePath, \"audience\")}>\n Audience\n </Link>\n <Link className=\"nav__link\" href={adminHref(basePath, \"broadcast\")}>\n Broadcast\n </Link>\n </NavGroup>\n )\n}\n\nexport function AudienceTable({ audiences }: { audiences: Array<{ id: string; name: string }> }) {\n return (\n <table>\n <tbody>\n {audiences.map((audience) => (\n <tr key={audience.id}>\n <td>{audience.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function ContactsTable({ contacts }: { contacts: Array<{ email: string; id: string }> }) {\n return (\n <table>\n <tbody>\n {contacts.map((contact) => (\n <tr key={contact.id}>\n <td>{contact.email}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n\nexport function BroadcastsTable({\n broadcasts,\n}: {\n broadcasts: Array<{ id: string; name: string }>\n}) {\n return (\n <table>\n <tbody>\n {broadcasts.map((broadcast) => (\n <tr key={broadcast.id}>\n <td>{broadcast.name}</td>\n </tr>\n ))}\n </tbody>\n </table>\n )\n}\n","\"use client\"\n\nimport { useConfig } from \"@payloadcms/ui\"\nimport { useCallback, useMemo } from \"react\"\n\nexport function useMarketingApi() {\n const context = useConfig() as unknown as {\n routes?: { api?: string }\n serverURL?: string\n }\n\n const base = useMemo(() => `${context.serverURL ?? \"\"}${context.routes?.api ?? \"/api\"}`, [\n context.routes?.api,\n context.serverURL,\n ])\n\n const requestJson = useCallback(\n async (pathSegment: string, init?: RequestInit): Promise<unknown> => {\n const { headers: _headersIgnored, ...restInit } = init ?? {}\n const headers = new Headers(init?.headers)\n if (\n restInit.body !== undefined &&\n restInit.body !== \"\" &&\n restInit.body !== null\n ) {\n if (!headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\")\n }\n }\n\n const res = await fetch(`${base}${pathSegment}`, {\n ...restInit,\n credentials: \"include\",\n headers,\n })\n\n if (!res.ok) {\n let detail = `${res.status} ${res.statusText}`\n try {\n const parsed = (await res.json()) as { message?: string }\n if (typeof parsed.message === \"string\") detail = parsed.message\n } catch {\n //\n }\n throw new Error(detail)\n }\n\n if (res.status === 204) {\n return undefined\n }\n\n try {\n return await res.json()\n } catch {\n return undefined\n }\n },\n [base],\n )\n\n return { base, requestJson }\n}\n","import React from \"react\"\n\nexport function AudienceList() {\n return <div>Audience</div>\n}\n\nexport function AudienceDetail() {\n return <div>Audience Detail</div>\n}\n\nexport function BroadcastList() {\n return <div>Broadcasts</div>\n}\n","export const defaultAdminComponentPath = \"payload-plugin-marketing/admin\"\n\nexport {\n AudienceSelect,\n AudienceTable,\n BroadcastsTable,\n ContactsTable,\n MarketingMenu,\n} from \"./components\"\nexport { AudienceDetail, AudienceList, BroadcastList } from \"./views\"\n"],"mappings":"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","names":["React","Link","NavGroup","SelectField","useConfig","useCallback","useMemo","useMarketingApi","context","base","requestJson","pathSegment","init","_headersIgnored","restInit","headers","res","detail","parsed","jsx","jsxs","parseAudiences","payload","out","item","rec","id","name","AudienceSelect","field","path","readOnly","requestJson","useMarketingApi","audiences","setAudiences","React","loadError","setLoadError","cancelled","data","err","SelectField","a","adminHref","basePath","segment","MarketingMenu","NavGroup","Link","AudienceTable","audience","ContactsTable","contacts","contact","BroadcastsTable","broadcasts","broadcast","jsx","AudienceList","AudienceDetail","BroadcastList","defaultAdminComponentPath"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/admin/paths.ts"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CASnF"}
|