@stacksjs/newsletter 0.70.84 → 0.70.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1 -1
  2. package/package.json +6 -5
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- var H=import.meta.require;function K(x){return x.toLowerCase().trim().replace(/[^\w\s-]+/g,"").replace(/\s+/g,"-").replace(/-+/g,"-")}var J={async create(x){let{EmailList:z}=await import("@stacksjs/orm"),D=x.slug??K(x.name);return z.create({name:x.name,slug:D,description:x.description??null,status:"active",isPublic:x.isPublic===!1?0:1,doubleOptIn:x.doubleOptIn===!1?0:1,subscriberCount:0,activeCount:0,unsubscribedCount:0,bouncedCount:0})},async find(x){let{EmailList:z}=await import("@stacksjs/orm");if(typeof x==="number")return z.find(x);return z.where("slug",x).first()},async all(){let{EmailList:x}=await import("@stacksjs/orm");return x.where("status","active").get()},async archive(x){let z=await J.find(x);if(!z)throw Error(`[newsletter] List '${String(x)}' not found`);return z.update({status:"archived"})}};async function P(x){if(x.emailListId)return x.emailListId;if(x.emailListSlug){let z=await J.find(x.emailListSlug);if(!z)throw Error(`[newsletter] List '${x.emailListSlug}' not found`);return z.id}throw Error("[newsletter] Campaign requires emailListId or emailListSlug")}var W={async create(x){let{Campaign:z}=await import("@stacksjs/orm"),D=await P(x),F=x.scheduledAt?"scheduled":"draft";return z.create({name:x.name,description:x.description??null,type:"email",status:F,subject:x.subject,template:x.template,text:x.text??null,from_name:x.fromName??null,from_address:x.fromAddress??null,email_list_id:D,scheduled_at:x.scheduledAt??null,sentCount:0})},async find(x){let{Campaign:z}=await import("@stacksjs/orm");return z.find(x)},async update(x,z){let D=await W.find(x);if(!D)throw Error(`[newsletter] Campaign ${x} not found`);if(D.status!=="draft"&&D.status!=="scheduled")throw Error(`[newsletter] Cannot edit campaign in status '${D.status}'`);return D.update(z)},async sendNow(x,z={}){let D=await W.find(x);if(!D)throw Error(`[newsletter] Campaign ${x} not found`);if(D.status==="sending"||D.status==="sent")throw Error(`[newsletter] Campaign ${x} already ${D.status}`);await D.update({status:"sending"});let{job:F}=await import("@stacksjs/queue");return await F("SendCampaign",{campaignId:x,chunkSize:z.chunkSize??50,dryRun:z.dryRun??!1}).onQueue("campaigns").dispatch(),{ok:!0,campaignId:x}},async schedule(x,z,D={}){let F=await W.find(x);if(!F)throw Error(`[newsletter] Campaign ${x} not found`);let G=z instanceof Date?z:new Date(z),M=Math.max(0,Math.floor((G.getTime()-Date.now())/1000));await F.update({status:M===0?"sending":"scheduled",scheduled_at:G.toISOString()});let{job:V}=await import("@stacksjs/queue");return await V("SendCampaign",{campaignId:x,chunkSize:D.chunkSize??50,dryRun:D.dryRun??!1}).onQueue("campaigns").delay(M).dispatch(),{ok:!0,campaignId:x,scheduledAt:G.toISOString()}},async cancel(x){let z=await W.find(x);if(!z)throw Error(`[newsletter] Campaign ${x} not found`);if(z.status==="sent")throw Error(`[newsletter] Campaign ${x} already sent \u2014 cannot cancel`);return z.update({status:"cancelled"})}};function U(x){if(!x.url||!/^https?:\/\//i.test(x.url))throw Error("[newsletter] List-Unsubscribe URL must be absolute (http/https)");let z=[];if(x.mailto)z.push(`<mailto:${x.mailto}>`);return z.push(`<${x.url}>`),{"List-Unsubscribe":z.join(", "),"List-Unsubscribe-Post":"List-Unsubscribe=One-Click"}}async function Q(x){if(x==null){let D=await J.find("default");if(!D)D=await J.create({name:"Default",slug:"default"});return D.id}let z=await J.find(x);if(!z)throw Error(`[newsletter] List '${String(x)}' not found`);return z.id}async function Y(x,z={}){if(!x||!x.includes("@"))throw Error("[newsletter] subscribe() requires a valid email address");let{Subscriber:D,EmailListSubscriber:F}=await import("@stacksjs/orm"),G=await Q(z.list),M=z.source??"api",V=await D.where("email",x).first();if(!V)V=await D.create({email:x,status:"subscribed",source:M});let X=await F.where("subscriber_id",V.id).where("email_list_id",G).first();if(X){if(X.status==="unsubscribed")await X.update({status:"subscribed",unsubscribed_at:null});return{created:!1,email:x,listId:G,token:X.uuid}}let B=await F.create({subscriber_id:V.id,email_list_id:G,status:"subscribed",source:M});return{created:!0,email:x,listId:G,token:B.uuid}}async function Z(x){if(!x)return{ok:!1};let{EmailListSubscriber:z,Subscriber:D}=await import("@stacksjs/orm"),F=await z.where("uuid",x).first();if(!F)return{ok:!1};if(F.status==="unsubscribed")return{ok:!0,alreadyUnsubscribed:!0,email:(await D.find(F.subscriber_id))?.email,listId:F.email_list_id};return await F.update({status:"unsubscribed",unsubscribed_at:new Date().toISOString()}),{ok:!0,email:(await D.find(F.subscriber_id))?.email,listId:F.email_list_id}}async function $(x){let{Subscriber:z,EmailListSubscriber:D}=await import("@stacksjs/orm"),F=await z.where("email",x).first();if(!F)return 0;let G=await D.where("subscriber_id",F.id).where("status","subscribed").get();for(let M of G)await M.update({status:"unsubscribed",unsubscribed_at:new Date().toISOString()});return G.length}var f={lists:J,campaigns:W,subscribe:Y,unsubscribe:Z,unsubscribeAll:$};export{$ as unsubscribeAll,Z as unsubscribe,Y as subscribe,f as newsletter,J as lists,W as campaigns,U as buildUnsubscribeHeaders};
2
+ var H=import.meta.require;function B(x){return x.toLowerCase().trim().replace(/[^\w\s-]+/g,"").replace(/\s+/g,"-").replace(/-+/g,"-")}var J={async create(x){let{EmailList:z}=await import("@stacksjs/orm"),D=x.slug??B(x.name);return z.create({name:x.name,slug:D,description:x.description??null,status:"active",isPublic:x.isPublic===!1?0:1,doubleOptIn:x.doubleOptIn===!1?0:1,subscriberCount:0,activeCount:0,unsubscribedCount:0,bouncedCount:0})},async find(x){let{EmailList:z}=await import("@stacksjs/orm");if(typeof x==="number")return z.find(x);return z.where("slug",x).first()},async all(){let{EmailList:x}=await import("@stacksjs/orm");return x.where("status","active").get()},async archive(x){let z=await J.find(x);if(!z)throw Error(`[newsletter] List '${String(x)}' not found`);return z.update({status:"archived"})}};async function K(x){if(x.emailListId)return x.emailListId;if(x.emailListSlug){let z=await J.find(x.emailListSlug);if(!z)throw Error(`[newsletter] List '${x.emailListSlug}' not found`);return z.id}throw Error("[newsletter] Campaign requires emailListId or emailListSlug")}var V={async create(x){let{Campaign:z}=await import("@stacksjs/orm"),D=await K(x),F=x.scheduledAt?"scheduled":"draft";return z.create({name:x.name,description:x.description??null,type:"email",status:F,subject:x.subject,template:x.template,text:x.text??null,from_name:x.fromName??null,from_address:x.fromAddress??null,email_list_id:D,scheduled_at:x.scheduledAt??null,sentCount:0})},async find(x){let{Campaign:z}=await import("@stacksjs/orm");return z.find(x)},async update(x,z){let D=await V.find(x);if(!D)throw Error(`[newsletter] Campaign ${x} not found`);if(D.status!=="draft"&&D.status!=="scheduled")throw Error(`[newsletter] Cannot edit campaign in status '${D.status}'`);return D.update(z)},async sendNow(x,z={}){let D=await V.find(x);if(!D)throw Error(`[newsletter] Campaign ${x} not found`);if(D.status==="sending"||D.status==="sent")throw Error(`[newsletter] Campaign ${x} already ${D.status}`);await D.update({status:"sending"});let{job:F}=await import("@stacksjs/queue");return await F("SendCampaign",{campaignId:x,chunkSize:z.chunkSize??50,dryRun:z.dryRun??!1}).onQueue("campaigns").dispatch(),{ok:!0,campaignId:x}},async schedule(x,z,D={}){let F=await V.find(x);if(!F)throw Error(`[newsletter] Campaign ${x} not found`);let G=z instanceof Date?z:new Date(z),M=Math.max(0,Math.floor((G.getTime()-Date.now())/1000));await F.update({status:M===0?"sending":"scheduled",scheduled_at:G.toISOString()});let{job:Q}=await import("@stacksjs/queue");return await Q("SendCampaign",{campaignId:x,chunkSize:D.chunkSize??50,dryRun:D.dryRun??!1}).onQueue("campaigns").delay(M).dispatch(),{ok:!0,campaignId:x,scheduledAt:G.toISOString()}},async cancel(x){let z=await V.find(x);if(!z)throw Error(`[newsletter] Campaign ${x} not found`);if(z.status==="sent")throw Error(`[newsletter] Campaign ${x} already sent \u2014 cannot cancel`);return z.update({status:"cancelled"})}};function U(x){if(!x.url||!/^https?:\/\//i.test(x.url))throw Error("[newsletter] List-Unsubscribe URL must be absolute (http/https)");let z=[];if(x.mailto)z.push(`<mailto:${x.mailto}>`);return z.push(`<${x.url}>`),{"List-Unsubscribe":z.join(", "),"List-Unsubscribe-Post":"List-Unsubscribe=One-Click"}}async function P(x){if(x==null){let D=await J.find("default");if(!D)D=await J.create({name:"Default",slug:"default"});return D.id}let z=await J.find(x);if(!z)throw Error(`[newsletter] List '${String(x)}' not found`);return z.id}async function X(x,z={}){if(!x||!x.includes("@"))throw Error("[newsletter] subscribe() requires a valid email address");let{Subscriber:D,EmailListSubscriber:F}=await import("@stacksjs/orm"),G=await P(z.list),M=z.source??"api",Q=await D.where("email",x).first();if(!Q)Q=await D.create({email:x,status:"subscribed",source:M});let W=await F.where("subscriber_id",Q.id).where("email_list_id",G).first();if(W){if(W.status==="unsubscribed")await W.update({status:"subscribed",unsubscribed_at:null});return{created:!1,email:x,listId:G,token:W.uuid}}let $=await F.create({subscriber_id:Q.id,email_list_id:G,status:"subscribed",source:M});return{created:!0,email:x,listId:G,token:$.uuid}}async function Y(x){if(!x)return{ok:!1};let{EmailListSubscriber:z,Subscriber:D}=await import("@stacksjs/orm"),F=await z.where("uuid",x).first();if(!F)return{ok:!1};if(F.status==="unsubscribed")return{ok:!0,alreadyUnsubscribed:!0,email:(await D.find(F.subscriber_id))?.email,listId:F.email_list_id};return await F.update({status:"unsubscribed",unsubscribed_at:new Date().toISOString()}),{ok:!0,email:(await D.find(F.subscriber_id))?.email,listId:F.email_list_id}}async function Z(x){let{Subscriber:z,EmailListSubscriber:D}=await import("@stacksjs/orm"),F=await z.where("email",x).first();if(!F)return 0;let G=await D.where("subscriber_id",F.id).where("status","subscribed").get();for(let M of G)await M.update({status:"unsubscribed",unsubscribed_at:new Date().toISOString()});return G.length}var I={lists:J,campaigns:V,subscribe:X,unsubscribe:Y,unsubscribeAll:Z};export{Z as unsubscribeAll,Y as unsubscribe,X as subscribe,I as newsletter,J as lists,V as campaigns,U as buildUnsubscribeHeaders};
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@stacksjs/newsletter",
3
3
  "type": "module",
4
- "version": "0.70.84",
4
+ "sideEffects": false,
5
+ "version": "0.70.86",
5
6
  "description": "Promotional email & newsletter primitives for Stacks. Lists, campaigns, subscribers, and one-click unsubscribe — sent through @stacksjs/email.",
6
7
  "author": "Chris Breuer",
7
8
  "contributors": [
@@ -55,10 +56,10 @@
55
56
  "prepublishOnly": "bun run build"
56
57
  },
57
58
  "devDependencies": {
58
- "@stacksjs/cli": "0.70.84",
59
- "@stacksjs/config": "0.70.84",
59
+ "@stacksjs/cli": "0.70.86",
60
+ "@stacksjs/config": "0.70.86",
60
61
  "better-dx": "^0.2.16",
61
- "@stacksjs/error-handling": "0.70.84",
62
- "@stacksjs/types": "0.70.84"
62
+ "@stacksjs/error-handling": "0.70.86",
63
+ "@stacksjs/types": "0.70.86"
63
64
  }
64
65
  }