@lunora/payment 1.0.0-alpha.102 → 1.0.0-alpha.104

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/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{createAdapterRegistry as r}from"./packem_shared/createAdapterRegistry-DyCsry1Q.mjs";import{lunoraDatabaseToPaymentDatabase as a,paymentsFromContext as n}from"./packem_shared/lunoraDatabaseToPaymentDatabase-BJkDz3DL.mjs";import{createPayment as y,webhookResponse as i}from"./packem_shared/createPayment-uEUXhWny.mjs";import{createDatabasePaymentStore as s}from"./packem_shared/createDatabasePaymentStore-DWe1Vz4V.mjs";import{entitlementsForReference as c,featureNames as x,hasActivePrice as S,resolveEntitlements as l,usagePeriodStart as M}from"./packem_shared/entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as u}from"./packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as b}from"./packem_shared/idempotencyKey-DBL6bpmj.mjs";import{addMoney as A,allocateMoney as E,compareMoney as N,formatMoney as h,fromMoneyJSON as R,isZeroDecimalCurrency as v,isZeroMoney as C,money as D,subtractMoney as I,toMoneyJSON as _,zeroMoney as g}from"./packem_shared/addMoney-B4ufWAnD.mjs";import{reconcile as L}from"./packem_shared/reconcile-Cm45pURT.mjs";import{default as F}from"./packem_shared/paymentTables-Be-_11ux.mjs";import{PAYMENT_TERMINAL_STATES as W,SUBSCRIPTION_TERMINAL_STATES as Z,canTransitionPayment as q,canTransitionSubscription as w,nextPaymentState as z,nextSubscriptionState as B}from"./packem_shared/PAYMENT_TERMINAL_STATES-tA4tF4im.mjs";import{MemoryPaymentStore as K}from"./packem_shared/MemoryPaymentStore-CZbrrEb1.mjs";import{default as Y}from"./packem_shared/applyWebhookAction-DMAgu_yP.mjs";import{constantTimeEqual as G,hmacSha256Hex as Q,verifyCreemSignature as V,verifyStandardWebhook as X}from"./packem_shared/constantTimeEqual-ggrwGvRa.mjs";export{u as LunoraPaymentError,K as MemoryPaymentStore,W as PAYMENT_TERMINAL_STATES,Z as SUBSCRIPTION_TERMINAL_STATES,A as addMoney,E as allocateMoney,Y as applyWebhookAction,q as canTransitionPayment,w as canTransitionSubscription,N as compareMoney,G as constantTimeEqual,r as createAdapterRegistry,s as createDatabasePaymentStore,y as createPayment,c as entitlementsForReference,x as featureNames,h as formatMoney,R as fromMoneyJSON,S as hasActivePrice,Q as hmacSha256Hex,b as idempotencyKey,v as isZeroDecimalCurrency,C as isZeroMoney,a as lunoraDatabaseToPaymentDatabase,D as money,z as nextPaymentState,B as nextSubscriptionState,F as paymentTables,n as paymentsFromContext,L as reconcile,l as resolveEntitlements,I as subtractMoney,_ as toMoneyJSON,M as usagePeriodStart,V as verifyCreemSignature,X as verifyStandardWebhook,i as webhookResponse,g as zeroMoney};
1
+ import{createAdapterRegistry as r}from"./packem_shared/createAdapterRegistry-DyCsry1Q.mjs";import{lunoraDatabaseToPaymentDatabase as a,paymentsFromContext as n}from"./packem_shared/lunoraDatabaseToPaymentDatabase-B0_5M2Jh.mjs";import{createPayment as y,webhookResponse as i}from"./packem_shared/createPayment-Bdso09vN.mjs";import{createDatabasePaymentStore as s}from"./packem_shared/createDatabasePaymentStore-DWe1Vz4V.mjs";import{entitlementsForReference as c,featureNames as x,hasActivePrice as S,resolveEntitlements as l,usagePeriodStart as M}from"./packem_shared/entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as u}from"./packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as b}from"./packem_shared/idempotencyKey-DBL6bpmj.mjs";import{addMoney as A,allocateMoney as E,compareMoney as N,formatMoney as h,fromMoneyJSON as R,isZeroDecimalCurrency as v,isZeroMoney as C,money as D,subtractMoney as I,toMoneyJSON as _,zeroMoney as g}from"./packem_shared/addMoney-B4ufWAnD.mjs";import{reconcile as L}from"./packem_shared/reconcile-Cm45pURT.mjs";import{default as F}from"./packem_shared/paymentTables-Be-_11ux.mjs";import{PAYMENT_TERMINAL_STATES as W,SUBSCRIPTION_TERMINAL_STATES as Z,canTransitionPayment as q,canTransitionSubscription as w,nextPaymentState as z,nextSubscriptionState as B}from"./packem_shared/PAYMENT_TERMINAL_STATES-Dxxpk_br.mjs";import{MemoryPaymentStore as K}from"./packem_shared/MemoryPaymentStore-CZbrrEb1.mjs";import{default as Y}from"./packem_shared/applyWebhookAction-DqM4qNr3.mjs";import{constantTimeEqual as G,hmacSha256Hex as Q,verifyCreemSignature as V,verifyStandardWebhook as X}from"./packem_shared/constantTimeEqual-ggrwGvRa.mjs";export{u as LunoraPaymentError,K as MemoryPaymentStore,W as PAYMENT_TERMINAL_STATES,Z as SUBSCRIPTION_TERMINAL_STATES,A as addMoney,E as allocateMoney,Y as applyWebhookAction,q as canTransitionPayment,w as canTransitionSubscription,N as compareMoney,G as constantTimeEqual,r as createAdapterRegistry,s as createDatabasePaymentStore,y as createPayment,c as entitlementsForReference,x as featureNames,h as formatMoney,R as fromMoneyJSON,S as hasActivePrice,Q as hmacSha256Hex,b as idempotencyKey,v as isZeroDecimalCurrency,C as isZeroMoney,a as lunoraDatabaseToPaymentDatabase,D as money,z as nextPaymentState,B as nextSubscriptionState,F as paymentTables,n as paymentsFromContext,L as reconcile,l as resolveEntitlements,I as subtractMoney,_ as toMoneyJSON,M as usagePeriodStart,V as verifyCreemSignature,X as verifyStandardWebhook,i as webhookResponse,g as zeroMoney};
@@ -0,0 +1 @@
1
+ const c={authorized:{cancel:"canceled",capture:"captured",fail:"failed"},canceled:{},captured:{partial_refund:"partially_refunded",refund:"refunded"},failed:{authorize:"authorized",capture:"captured",fail:"failed"},initiated:{authorize:"authorized",cancel:"canceled",capture:"captured",fail:"failed"},partially_refunded:{partial_refund:"partially_refunded",refund:"refunded"},refunded:{refund:"refunded"}},t={active:{cancel:"canceled",mark_past_due:"past_due",pause:"paused",renew:"active"},canceled:{},past_due:{activate:"active",cancel:"canceled",pause:"paused",renew:"active"},paused:{cancel:"canceled",resume:"active"},trialing:{activate:"active",cancel:"canceled",mark_past_due:"past_due"}},r=new Set(["canceled","refunded"]),i=new Set(["canceled"]),n=(e,a)=>c[e][a],u=(e,a)=>n(e,a)!==void 0,d=(e,a)=>t[e][a],l=(e,a)=>d(e,a)!==void 0;export{r as PAYMENT_TERMINAL_STATES,i as SUBSCRIPTION_TERMINAL_STATES,u as canTransitionPayment,l as canTransitionSubscription,n as nextPaymentState,d as nextSubscriptionState};
@@ -1 +1 @@
1
- import{LunoraPaymentError as P}from"./LunoraPaymentError-BSxyhWgu.mjs";import{localRefundKey as A,LOCAL_REFUND_CLAIM_TYPE as E}from"./idempotencyKey-DBL6bpmj.mjs";import{zeroMoney as o,compareMoney as l,addMoney as _}from"./addMoney-B4ufWAnD.mjs";import{n as i}from"./observability-BteZ2dJS.mjs";import{nextPaymentState as S,nextSubscriptionState as w}from"./PAYMENT_TERMINAL_STATES-tA4tF4im.mjs";const b={"payment.authorized":"authorize","payment.captured":"capture","payment.failed":"fail","payment.refunded":"refund"},h={"subscription.active":"active","subscription.canceled":"canceled","subscription.past_due":"past_due","subscription.paused":"paused"},T="orphan-retry:",R="marker.orphan_retry",k={"subscription.active":"activate","subscription.canceled":"cancel","subscription.past_due":"mark_past_due","subscription.paused":"pause"},O=(t,e)=>l(t,e)>0?t:e,Y=new Set(["authorized","initiated"]),N=async(t,e,r)=>{if(!r||!e.sessionId||!e.amount||e.amountKind==="absolute")return e;const n=A(e.sessionId,e.refundId,e.amount),d=await t.markEventProcessed(e.provider,n,E);return await t.releaseEvent(e.provider,n),d?e:{...e,amount:o(e.amount.currency)}},I=(t,e)=>{if(!e.amount||t.refundedAmount.currency!==e.amount.currency||t.capturedAmount.currency!==e.amount.currency)return;const r=e.amountKind==="absolute"?O(e.amount,t.refundedAmount):_(t.refundedAmount,e.amount);if(!(l(r,t.capturedAmount)>0))return r},M=(t,e)=>{if(!t)return"refund";const r=I(t,e);return r&&l(r,t.capturedAmount)<0?"partial_refund":"refund"},q=async(t,e,r)=>{if(!e.sessionId)return{applied:!1,reason:"unhandled"};const n=await t.getPaymentSession(e.provider,e.sessionId),d=n?.state??"initiated",u=Date.now(),s=e.amount?.currency??n?.amount.currency??"USD",c=r==="refund"?await N(t,e,n):e,a=r==="refund"?M(n,c):r,m=S(d,a);if(!m)return{applied:!1,reason:r==="refund"&&Y.has(d)?"orphaned":"illegal_transition"};const p=n??{amount:e.amount??o(s),capturedAmount:o(s),createdAt:u,id:e.sessionId,provider:e.provider,referenceId:e.referenceId??"",refundedAmount:o(s),state:d,updatedAt:u};let{capturedAmount:y,refundedAmount:v}=p;if(a==="capture"&&e.amount&&(y=e.amount),(a==="partial_refund"||a==="refund")&&c.amount){const f=I(p,c);if(!f)return{applied:!1,reason:"invalid_refund_amount"};v=f}return await t.upsertPaymentSession({...p,capturedAmount:y,referenceId:e.referenceId??p.referenceId,refundedAmount:v,state:m,updatedAt:u}),{applied:!0,reason:"ok"}},C=(t,e,r)=>{if(e==="active"){if(t==="active")return"renew";if(t==="paused")return"resume"}return k[r]},g=async(t,e)=>{if(!e.subscriptionId)return{applied:!1,reason:"unhandled"};const r=await t.getSubscription(e.provider,e.subscriptionId),n=Date.now();if(e.type==="subscription.updated")return r?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,quantity:e.quantity??r.quantity,updatedAt:n}),{applied:!0,reason:"ok"}):{applied:!1,reason:"orphaned"};const d=h[e.type];if(!d)return{applied:!1,reason:"unhandled"};if(!r)return await t.upsertSubscription({cancelAtPeriodEnd:e.cancelAtPeriodEnd??!1,createdAt:n,currentPeriodEnd:e.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??n,id:e.subscriptionId,priceId:e.priceId??"",provider:e.provider,quantity:e.quantity??1,referenceId:e.referenceId??"",state:d,updatedAt:n}),{applied:!0,reason:"ok"};const u=C(r.state,d,e.type),s=u?w(r.state,u):void 0;return s?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,quantity:e.quantity??r.quantity,state:s,updatedAt:n}),{applied:!0,reason:"ok"}):{applied:!1,reason:"illegal_transition"}},U=async(t,e,r)=>{if(e.type==="unhandled")return{applied:!1,reason:"unhandled"};if(!e.eventId?.trim())throw new P("WEBHOOK_EVENT_ID_MISSING",`webhook event id is missing or blank for provider "${e.provider}"`);if(!await t.markEventProcessed(e.provider,e.eventId,e.type))return i(r,{eventId:e.eventId,provider:e.provider,type:"webhook.duplicate"}),{applied:!1,reason:"duplicate"};const d=b[e.type];let u;try{u=d?await q(t,e,d):await g(t,e)}catch(s){throw await t.releaseEvent(e.provider,e.eventId),s}return u.reason==="orphaned"&&(await t.markEventProcessed(e.provider,`${T}${e.eventId}`,R)?await t.releaseEvent(e.provider,e.eventId):u={applied:!1,reason:"unhandled"}),i(r,{action:e.type,eventId:e.eventId,provider:e.provider,reason:u.reason,type:"webhook.applied"}),e.type==="payment.failed"?i(r,{provider:e.provider,referenceId:e.referenceId,sessionId:e.sessionId,type:"payment.failed"}):e.type==="subscription.past_due"&&i(r,{provider:e.provider,referenceId:e.referenceId,subscriptionId:e.subscriptionId,type:"subscription.past_due"}),u};export{U as default};
1
+ import{LunoraPaymentError as P}from"./LunoraPaymentError-BSxyhWgu.mjs";import{localRefundKey as A,LOCAL_REFUND_CLAIM_TYPE as E}from"./idempotencyKey-DBL6bpmj.mjs";import{zeroMoney as o,compareMoney as l,addMoney as _}from"./addMoney-B4ufWAnD.mjs";import{n as i}from"./observability-BteZ2dJS.mjs";import{nextPaymentState as S,nextSubscriptionState as w}from"./PAYMENT_TERMINAL_STATES-Dxxpk_br.mjs";const b={"payment.authorized":"authorize","payment.captured":"capture","payment.failed":"fail","payment.refunded":"refund"},h={"subscription.active":"active","subscription.canceled":"canceled","subscription.past_due":"past_due","subscription.paused":"paused"},T="orphan-retry:",R="marker.orphan_retry",k={"subscription.active":"activate","subscription.canceled":"cancel","subscription.past_due":"mark_past_due","subscription.paused":"pause"},O=(t,e)=>l(t,e)>0?t:e,Y=new Set(["authorized","initiated"]),N=async(t,e,r)=>{if(!r||!e.sessionId||!e.amount||e.amountKind==="absolute")return e;const n=A(e.sessionId,e.refundId,e.amount),d=await t.markEventProcessed(e.provider,n,E);return await t.releaseEvent(e.provider,n),d?e:{...e,amount:o(e.amount.currency)}},I=(t,e)=>{if(!e.amount||t.refundedAmount.currency!==e.amount.currency||t.capturedAmount.currency!==e.amount.currency)return;const r=e.amountKind==="absolute"?O(e.amount,t.refundedAmount):_(t.refundedAmount,e.amount);if(!(l(r,t.capturedAmount)>0))return r},M=(t,e)=>{if(!t)return"refund";const r=I(t,e);return r&&l(r,t.capturedAmount)<0?"partial_refund":"refund"},q=async(t,e,r)=>{if(!e.sessionId)return{applied:!1,reason:"unhandled"};const n=await t.getPaymentSession(e.provider,e.sessionId),d=n?.state??"initiated",u=Date.now(),s=e.amount?.currency??n?.amount.currency??"USD",c=r==="refund"?await N(t,e,n):e,a=r==="refund"?M(n,c):r,m=S(d,a);if(!m)return{applied:!1,reason:r==="refund"&&Y.has(d)?"orphaned":"illegal_transition"};const p=n??{amount:e.amount??o(s),capturedAmount:o(s),createdAt:u,id:e.sessionId,provider:e.provider,referenceId:e.referenceId??"",refundedAmount:o(s),state:d,updatedAt:u};let{capturedAmount:y,refundedAmount:v}=p;if(a==="capture"&&e.amount&&(y=e.amount),(a==="partial_refund"||a==="refund")&&c.amount){const f=I(p,c);if(!f)return{applied:!1,reason:"invalid_refund_amount"};v=f}return await t.upsertPaymentSession({...p,capturedAmount:y,referenceId:e.referenceId??p.referenceId,refundedAmount:v,state:m,updatedAt:u}),{applied:!0,reason:"ok"}},C=(t,e,r)=>{if(e==="active"){if(t==="active")return"renew";if(t==="paused")return"resume"}return k[r]},g=async(t,e)=>{if(!e.subscriptionId)return{applied:!1,reason:"unhandled"};const r=await t.getSubscription(e.provider,e.subscriptionId),n=Date.now();if(e.type==="subscription.updated")return r?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,quantity:e.quantity??r.quantity,updatedAt:n}),{applied:!0,reason:"ok"}):{applied:!1,reason:"orphaned"};const d=h[e.type];if(!d)return{applied:!1,reason:"unhandled"};if(!r)return await t.upsertSubscription({cancelAtPeriodEnd:e.cancelAtPeriodEnd??!1,createdAt:n,currentPeriodEnd:e.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??n,id:e.subscriptionId,priceId:e.priceId??"",provider:e.provider,quantity:e.quantity??1,referenceId:e.referenceId??"",state:d,updatedAt:n}),{applied:!0,reason:"ok"};const u=C(r.state,d,e.type),s=u?w(r.state,u):void 0;return s?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,quantity:e.quantity??r.quantity,state:s,updatedAt:n}),{applied:!0,reason:"ok"}):{applied:!1,reason:"illegal_transition"}},U=async(t,e,r)=>{if(e.type==="unhandled")return{applied:!1,reason:"unhandled"};if(!e.eventId?.trim())throw new P("WEBHOOK_EVENT_ID_MISSING",`webhook event id is missing or blank for provider "${e.provider}"`);if(!await t.markEventProcessed(e.provider,e.eventId,e.type))return i(r,{eventId:e.eventId,provider:e.provider,type:"webhook.duplicate"}),{applied:!1,reason:"duplicate"};const d=b[e.type];let u;try{u=d?await q(t,e,d):await g(t,e)}catch(s){throw await t.releaseEvent(e.provider,e.eventId),s}return u.reason==="orphaned"&&(await t.markEventProcessed(e.provider,`${T}${e.eventId}`,R)?await t.releaseEvent(e.provider,e.eventId):u={applied:!1,reason:"unhandled"}),i(r,{action:e.type,eventId:e.eventId,provider:e.provider,reason:u.reason,type:"webhook.applied"}),e.type==="payment.failed"?i(r,{provider:e.provider,referenceId:e.referenceId,sessionId:e.sessionId,type:"payment.failed"}):e.type==="subscription.past_due"&&i(r,{provider:e.provider,referenceId:e.referenceId,subscriptionId:e.subscriptionId,type:"subscription.past_due"}),u};export{U as default};
@@ -0,0 +1 @@
1
+ import{toErrorBody as R}from"@lunora/errors";import{usagePeriodStart as b,resolveEntitlements as S,featureNames as O,hasActivePrice as U}from"./entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as f}from"./LunoraPaymentError-BSxyhWgu.mjs";import{derivedIdempotencyKey as v,localRefundKey as _,LOCAL_REFUND_CLAIM_TYPE as D,idempotencyKey as A}from"./idempotencyKey-DBL6bpmj.mjs";import{subtractMoney as K,addMoney as B,compareMoney as k,isZeroMoney as C}from"./addMoney-B4ufWAnD.mjs";import{n as E}from"./observability-BteZ2dJS.mjs";import F from"./applyWebhookAction-DqM4qNr3.mjs";const y=(o,n=200,s)=>{const m=new Headers({"content-type":"application/json"});for(const[l,w]of Object.entries({}))m.set(l,w);return Response.json(o,{headers:m,status:n})};let h=0;const T=()=>{const o=Date.now();return h=o>h?o:h+1,h},P=o=>o?`${o.currency}:${String(o.minorUnits)}`:"full",q=o=>o&&"referenceId"in o?Object.fromEntries(Object.entries(o).filter(([n])=>n!=="referenceId")):o,G=o=>y({applied:o.applied},o.status),W=o=>{const{adapter:n,store:s}=o,m=async e=>{if(!o.authorize)return;let t;try{t=await o.authorize(e)}catch{throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)}if(t!==!0)throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)},l=async e=>{await m(e.referenceId);const t=q(e.metadata);let r;const a=await s.getCustomerByReference(n.identifier,e.referenceId);if(a)r=a.id;else{const d=await n.getOrCreateCustomer({email:e.email,referenceId:e.referenceId});r=d.id,await s.upsertCustomer(d)}const i=e.idempotencyKey??await v("checkout",n.identifier,e.referenceId,e.priceId,e.mode,String(e.quantity??1),e.successUrl,e.cancelUrl,t?JSON.stringify(t):"");return n.createCheckout({...e,customerId:r,idempotencyKey:i,metadata:t})},w=(e,t,r)=>{const a=e-t;return{allowed:a>=r,balance:a,limit:e,unlimited:!1,used:t}},N=async(e,t,r,a,i)=>{const d=e.limit(a);if(d!==void 0){const c=await s.sumUsage(r,a,b(t));return w(d,c,i)}return{allowed:e.has(a),unlimited:e.has(a)}},I=async e=>{const t=()=>new f("NOT_FOUND",`payment session "${e}" not found`);let r=await s.getPaymentSession(n.identifier,e);if(!r)try{r=await n.getPaymentStatus(e)}catch{throw t()}if(!r.referenceId)throw t();try{await m(r.referenceId)}catch{throw t()}return r},p=async(e,t)=>{const r={...e,...t,updatedAt:Date.now()};return await s.upsertPaymentSession(r),r};return{adapter:n,attach:async e=>l({...e,mode:e.mode??"subscription"}),cancelPayment:async(e,t)=>{const r=await I(e),a=t?.idempotencyKey??A("cancel_payment",n.identifier,e),i=await n.cancelPayment(e,{...t,idempotencyKey:a});return p(r,{state:i.state})},cancelSubscription:async(e,t)=>{const r=await s.getSubscription(n.identifier,e);if(!r)throw new f("NOT_FOUND",`subscription "${e}" not found`);try{await m(r.referenceId)}catch{throw new f("NOT_FOUND",`subscription "${e}" not found`)}const a=t?.idempotencyKey??A("cancel_subscription",n.identifier,e),i=await n.cancelSubscription(e,{...t,idempotencyKey:a});return await s.upsertSubscription(i),i},capturePayment:async e=>{const t=await I(e.sessionId),r=e.idempotencyKey??await v("capture_payment",n.identifier,e.sessionId,P(e.amount)),a=await n.capturePayment({...e,idempotencyKey:r});return p(t,{capturedAmount:a.capturedAmount,state:a.state})},check:async e=>{if(await m(e.referenceId),e.featureId===void 0&&e.priceId===void 0)throw new f("CONFIG_INVALID","check() requires a featureId or priceId");if(n.checkEntitlement)return n.checkEntitlement(e);const t=await s.listSubscriptionsByReference(e.referenceId);if(e.priceId!==void 0)return{allowed:U(t,e.priceId),unlimited:!1};if(e.featureId===void 0)throw new f("CONFIG_INVALID","check() requires a featureId or priceId");if(!o.entitlements)throw new f("CONFIG_INVALID","check() requires `entitlements` to be configured");const r=S(o.entitlements,t);return N(r,t,e.referenceId,e.featureId,e.quantity??1)},createCheckout:async e=>l(e),createPortalSession:async(e,t)=>{await m(e);const r=await s.getCustomerByReference(n.identifier,e);if(!r)throw new f("NOT_FOUND",`no customer for reference "${e}"`);return n.createPortalSession({customerId:r.id,returnUrl:t})},handleWebhook:async e=>{let t;try{const a=await e.text();t=await n.parseWebhook({headers:e.headers,payload:a})}catch(a){if(a instanceof f){const{body:i,status:d}=R(a);return y({error:i.message},d)}return y({error:"webhook error"},400)}const r=await F(s,t,o.observability);return r.reason==="orphaned"?y({applied:r.applied,reason:r.reason},500):y({applied:r.applied,reason:r.reason},200)},listBalances:async e=>{if(await m(e),n.getBalances)return n.getBalances(e);if(!o.entitlements)throw new f("CONFIG_INVALID","listBalances() requires `entitlements` to be configured");const t=await s.listSubscriptionsByReference(e),r=S(o.entitlements,t),a=O(o.entitlements),i=a.filter(c=>r.limit(c)!==void 0),d=i.length===0?new Map:await s.sumUsageByFeature(e,i,b(t));return a.map(c=>{const u=r.limit(c);return u!==void 0?{featureId:c,...w(u,d.get(c)??0,1)}:{featureId:c,allowed:r.has(c),unlimited:r.has(c)}})},listSubscriptions:async e=>(await m(e),s.listSubscriptionsByReference(e)),refundPayment:async e=>{const t=await I(e.sessionId),r=e.amount??K(t.capturedAmount,t.refundedAmount),a=B(t.refundedAmount,r);if(k(a,t.capturedAmount)>0)throw new f("VALIDATION_ERROR",`refundPayment(): refunding ${String(e.amount?.minorUnits)} would exceed the captured amount on session "${e.sessionId}"`);if(C(r))return t;const i=e.amount??(k(r,t.capturedAmount)===0?void 0:r),d=e.idempotencyKey??await v("refund_payment",n.identifier,e.sessionId,P(i),e.reason??""),c=await n.refundPayment({...e,amount:i,idempotencyKey:d});if(c.pending)return t;const u=_(e.sessionId,c.refundId,r);await s.markEventProcessed(n.identifier,u,D);try{return await p(t,{refundedAmount:a,state:k(a,t.capturedAmount)<0?"partially_refunded":"refunded"})}catch(g){throw await s.releaseEvent(n.identifier,u),g}},store:s,track:async e=>{await m(e.referenceId);const t=e.quantity===void 0?1:e.quantity;if(!Number.isSafeInteger(t)||t<0)throw new f("VALIDATION_ERROR",`track(): \`quantity\` must be a non-negative safe integer (got ${String(e.quantity)})`);const r=e.idempotencyKey??crypto.randomUUID(),a=e.mode==="set",i=a?await s.listSubscriptionsByReference(e.referenceId):void 0,d=i===void 0?0:await s.sumUsage(e.referenceId,e.featureId,b(i));if(a?t===d:t===0)return{recorded:!1,reportedToProvider:!1};const c=a?t-d:t;if(!await s.recordUsage({createdAt:T(),featureId:e.featureId,idempotencyKey:r,...a?{mode:"set"}:{},provider:n.identifier,quantity:t,referenceId:e.referenceId,reportedToProvider:!1}))return{recorded:!1,reportedToProvider:!1};if(c<=0||!n.capabilities.usageMetering||!n.reportUsage)return{recorded:!0,reportedToProvider:!1};try{const g=await s.getCustomerByReference(n.identifier,e.referenceId);return await n.reportUsage({customerId:g?.id,featureId:e.featureId,idempotencyKey:r,quantity:c,referenceId:e.referenceId}),await s.markUsageReported(n.identifier,r),{recorded:!0,reportedToProvider:!0}}catch{return E(o.observability,{featureId:e.featureId,provider:n.identifier,referenceId:e.referenceId,type:"usage.report_failed"}),{recorded:!0,reportedToProvider:!1}}}}};export{W as createPayment,G as webhookResponse};
@@ -1 +1 @@
1
- import{createPayment as i}from"./createPayment-uEUXhWny.mjs";import{createDatabasePaymentStore as s}from"./createDatabasePaymentStore-DWe1Vz4V.mjs";const o=r=>({delete:async t=>r.delete(t),findFirst:async(t,e)=>await r.findFirst(t,{where:e}),findMany:async(t,e,a)=>{const n=await r.findMany(t,{...a,where:e});return{cursor:n.continueCursor??void 0,rows:n.page}},insert:async(t,e)=>r.insert(t,e),patch:async(t,e)=>r.patch(t,e)}),y=(r,t)=>{const e=r.auth?.userId??void 0;return i({adapter:t.adapter,authorize:t.authorize??(a=>a.trim()!==""&&e!==void 0&&a===e),entitlements:t.entitlements,observability:t.observability,store:s(o(r.db))})};export{o as lunoraDatabaseToPaymentDatabase,y as paymentsFromContext};
1
+ import{createPayment as i}from"./createPayment-Bdso09vN.mjs";import{createDatabasePaymentStore as s}from"./createDatabasePaymentStore-DWe1Vz4V.mjs";const o=r=>({delete:async t=>r.delete(t),findFirst:async(t,e)=>await r.findFirst(t,{where:e}),findMany:async(t,e,a)=>{const n=await r.findMany(t,{...a,where:e});return{cursor:n.continueCursor??void 0,rows:n.page}},insert:async(t,e)=>r.insert(t,e),patch:async(t,e)=>r.patch(t,e)}),y=(r,t)=>{const e=r.auth?.userId??void 0;return i({adapter:t.adapter,authorize:t.authorize??(a=>a.trim()!==""&&e!==void 0&&a===e),entitlements:t.entitlements,observability:t.observability,store:s(o(r.db))})};export{o as lunoraDatabaseToPaymentDatabase,y as paymentsFromContext};
@@ -1 +1 @@
1
- import{a as o,c as u,f as m,r as c,b as p,p as f,d as v,e as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as I,zeroMoney as g}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyCreemSignature as A}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as E}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const k=/already exists/iu,C={canceled:"canceled",completed:"captured",expired:"canceled",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded"},h={active:"active",canceled:"canceled",cancelled:"canceled",expired:"canceled",incomplete:"past_due",paid:"active",past_due:"past_due",paused:"paused",scheduled_cancel:"active",trialing:"trialing",unpaid:"past_due"},_=E("creem (merchant-of-record)"),i=a=>typeof a=="string"?a:c(o(a),"id"),T=a=>u(a,"checkout_url","checkoutUrl")??"",S=a=>u(a,"canceled_at","canceledAt")!==void 0||c(a,"status")==="scheduled_cancel",b=a=>{if(!(a instanceof Error))return!1;const{statusCode:t}=a;return typeof t=="number"&&t!==400&&t!==409?!1:k.test(a.message)},l=a=>{const t=o(a),r=Date.now(),e=c(t,"status")??"";return{cancelAtPeriodEnd:S(t),createdAt:r,currentPeriodEnd:f(u(t,"current_period_end_date","currentPeriodEndDate")),currentPeriodStart:f(u(t,"current_period_start_date","currentPeriodStartDate")),id:c(t,"id")??"",priceId:i(t.product)??"",provider:"creem",quantity:p(t,"units")??1,referenceId:m(t)??i(t.customer)??"",state:h[e]??"past_due",updatedAt:r}},B=a=>{const t=o(a),r=Date.now(),e=o(t.order),n=c(e,"currency")??c(t,"currency")??"usd",s=I(BigInt(Math.round(p(e,"amount")??p(t,"amount")??0)),n),d=C[c(e,"status")??c(t,"status")??""]??"initiated";return{amount:s,capturedAmount:d==="captured"||d==="partially_refunded"||d==="refunded"?s:g(n),createdAt:r,id:c(t,"id")??"",provider:"creem",referenceId:m(t)??"",refundedAmount:d==="refunded"?s:g(n),state:d,updatedAt:r}},D=(a,t,r)=>{const e={eventId:a,provider:"creem",raw:{object:r,type:t}},n=o(r.order),s=c(n,"currency")??c(r,"currency")??"usd";switch(t){case"checkout.completed":{const d=p(n,"amount")??p(r,"amount");return{...e,amount:d===void 0?void 0:I(BigInt(Math.round(d)),s),customerId:i(r.customer),referenceId:m(r),sessionId:c(r,"id"),subscriptionId:i(r.subscription),type:"payment.captured"}}case"refund.created":{const d=w(r,"refund_amount","refundAmount","amount")??p(n,"amount"),y=u(r,"refund_currency","refundCurrency")??s;return{...e,amount:d===void 0?void 0:I(BigInt(Math.round(d)),y),referenceId:m(r),refundId:c(r,"id"),sessionId:i(r.transaction)??i(r.subscription)??i(r.order)??i(r.checkout)??c(r,"id"),type:"payment.refunded"}}case"subscription.active":case"subscription.canceled":case"subscription.expired":case"subscription.paid":case"subscription.past_due":case"subscription.paused":case"subscription.scheduled_cancel":case"subscription.trialing":case"subscription.unpaid":case"subscription.update":{const d=t==="subscription.scheduled_cancel"?"scheduled_cancel":c(r,"status");return{...e,cancelAtPeriodEnd:v(r,"cancel_at_period_end")??S(r),currentPeriodEnd:f(u(r,"current_period_end_date","currentPeriodEndDate")),currentPeriodStart:f(u(r,"current_period_start_date","currentPeriodStartDate")),customerId:i(r.customer),priceId:i(r.product),referenceId:m(r)??i(r.customer),subscriptionId:c(r,"id"),type:P(h[d??""]??"past_due")}}default:return{...e,type:"unhandled"}}},O=a=>{const{webhookSecret:t}=a,r=a.client;return{cancelPayment:()=>_("manual payment cancellation"),cancelSubscription:async(e,n)=>l(await r.subscriptions.cancel(e,{mode:n?.atPeriodEnd===!0?"scheduled":"immediate"})),capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!1},capturePayment:e=>_("manual capture"),createCheckout:async e=>{const n=await r.checkouts.create({customer:e.customerId?{id:e.customerId}:void 0,metadata:{...e.metadata,referenceId:e.referenceId},productId:e.priceId,requestId:e.idempotencyKey,successUrl:e.successUrl,units:e.quantity});return{id:c(n,"id")??"",provider:"creem",url:T(n)}},createPortalSession:async e=>{const n=await r.customers.generateBillingLinks({customerId:e.customerId});return{url:u(n,"customer_portal_link","customerPortalLink")??""}},getOrCreateCustomer:async e=>{const n=s=>({createdAt:Date.now(),email:c(s,"email")??e.email,id:c(s,"id")??"",provider:"creem",referenceId:e.referenceId});try{return n(o(await r.customers.create({email:e.email??"",metadata:{...e.metadata,referenceId:e.referenceId},name:e.metadata?.name??e.referenceId})))}catch(s){if(e.email!==void 0&&b(s)){const d=o(await r.customers.retrieve(void 0,e.email));if(m(d)!==e.referenceId)throw new Error(`Creem customer for email "${e.email}" already belongs to a different reference; refusing to bind it to "${e.referenceId}".`,{cause:s});return n(d)}throw s}},getPaymentStatus:async e=>B(await r.checkouts.retrieve(e)),getSubscriptionStatus:async e=>l(await r.subscriptions.get(e)),identifier:"creem",parseWebhook:async({headers:e,payload:n})=>{await A({payload:n,secret:t,signature:e.get("creem-signature")??""});const s=o(JSON.parse(n));return D(u(s,"id","event_id","eventId")??"",u(s,"eventType","type")??"",o(s.object))},refundPayment:()=>_("programmatic refunds"),resumeSubscription:async e=>l(await r.subscriptions.resume(e)),updateSubscription:async(e,n)=>n.priceId?l(await r.subscriptions.upgrade(e,{productId:n.priceId,updateBehavior:"proration-charge-immediately"})):l(await r.subscriptions.get(e))}};export{O as createCreemAdapter};
1
+ import{a as o,c as u,f as m,r as c,b as p,p as f,d as v,e as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as I,zeroMoney as g}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyCreemSignature as A}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as E}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const k=/already exists/iu,C={canceled:"canceled",completed:"captured",expired:"canceled",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded"},h={active:"active",canceled:"canceled",cancelled:"canceled",expired:"canceled",incomplete:"past_due",paid:"active",past_due:"past_due",paused:"paused",scheduled_cancel:"active",trialing:"trialing",unpaid:"past_due"},_=E("creem (merchant-of-record)"),i=a=>typeof a=="string"?a:c(o(a),"id"),T=a=>u(a,"checkout_url","checkoutUrl")??"",S=a=>u(a,"canceled_at","canceledAt")!==void 0||c(a,"status")==="scheduled_cancel",b=a=>{if(!(a instanceof Error))return!1;const{statusCode:t}=a;return typeof t=="number"&&t!==400&&t!==409?!1:k.test(a.message)},l=a=>{const t=o(a),r=Date.now(),e=c(t,"status")??"";return{cancelAtPeriodEnd:S(t),createdAt:r,currentPeriodEnd:f(u(t,"current_period_end_date","currentPeriodEndDate")),currentPeriodStart:f(u(t,"current_period_start_date","currentPeriodStartDate")),id:c(t,"id")??"",priceId:i(t.product)??"",provider:"creem",quantity:p(t,"units")??1,referenceId:m(t)??i(t.customer)??"",state:h[e]??"past_due",updatedAt:r}},B=a=>{const t=o(a),r=Date.now(),e=o(t.order),n=c(e,"currency")??c(t,"currency")??"usd",s=I(BigInt(Math.round(p(e,"amount")??p(t,"amount")??0)),n),d=C[c(e,"status")??c(t,"status")??""]??"initiated";return{amount:s,capturedAmount:d==="captured"||d==="partially_refunded"||d==="refunded"?s:g(n),createdAt:r,id:c(t,"id")??"",provider:"creem",referenceId:m(t)??"",refundedAmount:d==="refunded"?s:g(n),state:d,updatedAt:r}},D=(a,t,r)=>{const e={eventId:a,provider:"creem",raw:{object:r,type:t}},n=o(r.order),s=c(n,"currency")??c(r,"currency")??"usd";switch(t){case"checkout.completed":{const d=p(n,"amount")??p(r,"amount");return{...e,amount:d===void 0?void 0:I(BigInt(Math.round(d)),s),customerId:i(r.customer),referenceId:m(r),sessionId:c(r,"id"),subscriptionId:i(r.subscription),type:"payment.captured"}}case"refund.created":{const d=w(r,"refund_amount","refundAmount","amount")??p(n,"amount"),y=u(r,"refund_currency","refundCurrency")??s;return{...e,amount:d===void 0?void 0:I(BigInt(Math.round(d)),y),referenceId:m(r),refundId:c(r,"id"),sessionId:i(r.checkout)??i(r.transaction)??i(r.subscription)??i(r.order)??c(r,"id"),type:"payment.refunded"}}case"subscription.active":case"subscription.canceled":case"subscription.expired":case"subscription.paid":case"subscription.past_due":case"subscription.paused":case"subscription.scheduled_cancel":case"subscription.trialing":case"subscription.unpaid":case"subscription.update":{const d=t==="subscription.scheduled_cancel"?"scheduled_cancel":c(r,"status");return{...e,cancelAtPeriodEnd:v(r,"cancel_at_period_end")??S(r),currentPeriodEnd:f(u(r,"current_period_end_date","currentPeriodEndDate")),currentPeriodStart:f(u(r,"current_period_start_date","currentPeriodStartDate")),customerId:i(r.customer),priceId:i(r.product),referenceId:m(r)??i(r.customer),subscriptionId:c(r,"id"),type:P(h[d??""]??"past_due")}}default:return{...e,type:"unhandled"}}},O=a=>{const{webhookSecret:t}=a,r=a.client;return{cancelPayment:()=>_("manual payment cancellation"),cancelSubscription:async(e,n)=>l(await r.subscriptions.cancel(e,{mode:n?.atPeriodEnd===!0?"scheduled":"immediate"})),capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!1},capturePayment:e=>_("manual capture"),createCheckout:async e=>{const n=await r.checkouts.create({customer:e.customerId?{id:e.customerId}:void 0,metadata:{...e.metadata,referenceId:e.referenceId},productId:e.priceId,requestId:e.idempotencyKey,successUrl:e.successUrl,units:e.quantity});return{id:c(n,"id")??"",provider:"creem",url:T(n)}},createPortalSession:async e=>{const n=await r.customers.generateBillingLinks({customerId:e.customerId});return{url:u(n,"customer_portal_link","customerPortalLink")??""}},getOrCreateCustomer:async e=>{const n=s=>({createdAt:Date.now(),email:c(s,"email")??e.email,id:c(s,"id")??"",provider:"creem",referenceId:e.referenceId});try{return n(o(await r.customers.create({email:e.email??"",metadata:{...e.metadata,referenceId:e.referenceId},name:e.metadata?.name??e.referenceId})))}catch(s){if(e.email!==void 0&&b(s)){const d=o(await r.customers.retrieve(void 0,e.email));if(m(d)!==e.referenceId)throw new Error(`Creem customer for email "${e.email}" already belongs to a different reference; refusing to bind it to "${e.referenceId}".`,{cause:s});return n(d)}throw s}},getPaymentStatus:async e=>B(await r.checkouts.retrieve(e)),getSubscriptionStatus:async e=>l(await r.subscriptions.get(e)),identifier:"creem",parseWebhook:async({headers:e,payload:n})=>{await A({payload:n,secret:t,signature:e.get("creem-signature")??""});const s=o(JSON.parse(n));return D(u(s,"id","event_id","eventId")??"",u(s,"eventType","type")??"",o(s.object))},refundPayment:()=>_("programmatic refunds"),resumeSubscription:async e=>l(await r.subscriptions.resume(e)),updateSubscription:async(e,n)=>n.priceId?l(await r.subscriptions.upgrade(e,{productId:n.priceId,updateBehavior:"proration-charge-immediately"})):l(await r.subscriptions.get(e))}};export{O as createCreemAdapter};
@@ -1 +1 @@
1
- import{LunoraPaymentError as S}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as b}from"../packem_shared/idempotencyKey-DBL6bpmj.mjs";import{a as i,b as o,r as a,f as u,p as l,d as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as _,zeroMoney as f}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as h}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as A}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const q={cancelled:"canceled",failed:"failed",partially_captured:"captured",partially_captured_and_capturable:"captured",processing:"initiated",requires_capture:"authorized",requires_confirmation:"initiated",requires_customer_action:"authorized",requires_merchant_action:"authorized",requires_payment_method:"initiated",succeeded:"captured"},g={active:"active",cancelled:"canceled",expired:"canceled",failed:"past_due",on_hold:"past_due",paused:"paused",pending:"past_due"},I=A("dodopayments (merchant-of-record)"),m=d=>a(i(d.customer),"customer_id")??a(d,"customer_id"),p=d=>{const n=i(d),t=Date.now(),e=a(n,"status")??"";return{cancelAtPeriodEnd:w(n,"cancel_at_next_billing_date")??!1,createdAt:t,currentPeriodEnd:l(a(n,"next_billing_date")),currentPeriodStart:l(a(n,"previous_billing_date")),id:a(n,"subscription_id")??"",priceId:a(n,"product_id")??"",provider:"dodopayments",quantity:o(n,"quantity")??1,referenceId:u(n)??m(n)??"",state:g[e]??"past_due",updatedAt:t}},k=d=>{const n=i(d),t=Date.now(),e=a(n,"currency")??"usd",r=_(BigInt(Math.round(o(n,"total_amount")??0)),e),s=q[a(n,"status")??""]??"initiated";return{amount:r,capturedAmount:s==="captured"?r:f(e),createdAt:t,id:a(n,"payment_id")??"",provider:"dodopayments",referenceId:u(n)??"",refundedAmount:f(e),state:s,updatedAt:t}},D=(d,n,t)=>{const e={eventId:d,provider:"dodopayments",raw:{object:t,type:n}},r=a(t,"currency")??"usd";switch(n){case"dispute.lost":case"refund.succeeded":return{...e,amount:_(BigInt(Math.round(o(t,"amount")??0)),r),referenceId:u(t),refundId:a(t,"refund_id")??a(t,"dispute_id"),sessionId:a(t,"payment_id"),type:"payment.refunded"};case"payment.cancelled":case"payment.failed":return{...e,referenceId:u(t),sessionId:a(t,"payment_id"),type:"payment.failed"};case"payment.succeeded":return{...e,amount:_(BigInt(Math.round(o(t,"total_amount")??0)),r),customerId:m(t),referenceId:u(t),sessionId:a(t,"payment_id"),subscriptionId:a(t,"subscription_id"),type:"payment.captured"};case"subscription.active":case"subscription.cancelled":case"subscription.expired":case"subscription.failed":case"subscription.on_hold":case"subscription.paused":case"subscription.plan_changed":case"subscription.renewed":case"subscription.updated":{const s=a(t,"status");return{...e,cancelAtPeriodEnd:w(t,"cancel_at_next_billing_date"),currentPeriodEnd:l(a(t,"next_billing_date")),currentPeriodStart:l(a(t,"previous_billing_date")),customerId:m(t),priceId:a(t,"product_id"),quantity:o(t,"quantity"),referenceId:u(t)??m(t),subscriptionId:a(t,"subscription_id"),type:P(g[s??""]??"past_due")}}default:return{...e,type:"unhandled"}}},U=d=>{const{webhookSecret:n}=d,t=d.client;return{cancelPayment:()=>I("manual payment cancellation"),cancelSubscription:async(e,r)=>{const s=r?.atPeriodEnd?{cancel_at_next_billing_date:!0}:{status:"cancelled"};return p(await t.subscriptions.update(e,s))},capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!0},capturePayment:e=>I("manual capture"),createCheckout:async e=>{const r=i(await t.checkoutSessions.create({customer:e.customerId?{customer_id:e.customerId}:void 0,metadata:{...e.metadata,referenceId:e.referenceId},product_cart:[{product_id:e.priceId,quantity:e.quantity??1}],return_url:e.successUrl}));return{id:a(r,"session_id")??"",provider:"dodopayments",url:a(r,"checkout_url")??""}},createPortalSession:async e=>{const r=i(await t.customers.customerPortal.create(e.customerId,{return_url:e.returnUrl}));return{url:a(r,"link")??a(r,"url")??""}},getOrCreateCustomer:async e=>{const r=i(await t.customers.create({email:e.email??"",name:e.metadata?.name??e.referenceId},{idempotencyKey:b("customer","dodopayments",e.referenceId)}));return{createdAt:Date.now(),email:a(r,"email")??e.email,id:a(r,"customer_id")??"",provider:"dodopayments",referenceId:e.referenceId}},getPaymentStatus:async e=>k(await t.payments.retrieve(e)),getSubscriptionStatus:async e=>p(await t.subscriptions.retrieve(e)),identifier:"dodopayments",parseWebhook:async({headers:e,payload:r})=>{const s=e.get("webhook-id")??"";await h({payload:r,secret:n,toleranceSeconds:d.webhookToleranceSeconds,webhookId:s,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const c=i(JSON.parse(r));return D(s,a(c,"type")??"",i(c.data))},refundPayment:async e=>{if(e.amount!==void 0)throw new S("PROVIDER_ERROR","dodopayments refunds a payment in full; partial refunds require line items and aren't supported here");const r=i(await t.refunds.create({payment_id:e.sessionId,reason:e.reason})),s=a(r,"currency")??"usd",c=_(BigInt(Math.round(o(r,"amount")??0)),s),y=a(r,"status")==="succeeded",v=y?"refunded":"captured";return{amount:c,capturedAmount:c,createdAt:Date.now(),id:e.sessionId,pending:!y,provider:"dodopayments",referenceId:"",refundedAmount:c,refundId:a(r,"refund_id"),state:v,updatedAt:Date.now()}},reportUsage:async e=>{await t.usageEvents.ingest({events:[{customer_id:e.customerId??e.referenceId,event_id:e.idempotencyKey,event_name:e.featureId,metadata:{value:e.quantity},timestamp:e.timestamp===void 0?void 0:new Date(e.timestamp).toISOString()}]})},resumeSubscription:async e=>{const r=await t.subscriptions.update(e,{cancel_at_next_billing_date:!1});return p(r)},updateSubscription:async(e,r)=>{if(r.priceId!==void 0||r.quantity!==void 0){const s=i(r.priceId!==void 0&&r.quantity!==void 0?void 0:await t.subscriptions.retrieve(e));await t.subscriptions.changePlan(e,{product_id:r.priceId??a(s,"product_id")??"",proration_billing_mode:"prorated_immediately",quantity:r.quantity??o(s,"quantity")??1})}return p(await t.subscriptions.retrieve(e))}}};export{U as createDodoPaymentsAdapter};
1
+ import{LunoraPaymentError as S}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as b}from"../packem_shared/idempotencyKey-DBL6bpmj.mjs";import{a as i,b as u,r as a,f as c,p as l,d as v}from"../packem_shared/json-BJJPJVYj.mjs";import{money as _,zeroMoney as f}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as h}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as A}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const q={cancelled:"canceled",failed:"failed",partially_captured:"captured",partially_captured_and_capturable:"captured",processing:"initiated",requires_capture:"authorized",requires_confirmation:"initiated",requires_customer_action:"authorized",requires_merchant_action:"authorized",requires_payment_method:"initiated",succeeded:"captured"},g={active:"active",cancelled:"canceled",expired:"canceled",failed:"past_due",on_hold:"past_due",paused:"paused",pending:"past_due"},I=A("dodopayments (merchant-of-record)"),k=/^-?\d+$/,E=(d,n)=>{const t=d[n];return typeof t=="number"?Number.isFinite(t)?BigInt(Math.round(t)):void 0:typeof t=="string"&&k.test(t)?BigInt(t):void 0},m=d=>a(i(d.customer),"customer_id")??a(d,"customer_id"),p=d=>{const n=i(d),t=Date.now(),e=a(n,"status")??"";return{cancelAtPeriodEnd:v(n,"cancel_at_next_billing_date")??!1,createdAt:t,currentPeriodEnd:l(a(n,"next_billing_date")),currentPeriodStart:l(a(n,"previous_billing_date")),id:a(n,"subscription_id")??"",priceId:a(n,"product_id")??"",provider:"dodopayments",quantity:u(n,"quantity")??1,referenceId:c(n)??m(n)??"",state:g[e]??"past_due",updatedAt:t}},T=d=>{const n=i(d),t=Date.now(),e=a(n,"currency")??"usd",r=_(BigInt(Math.round(u(n,"total_amount")??0)),e),s=q[a(n,"status")??""]??"initiated";return{amount:r,capturedAmount:s==="captured"?r:f(e),createdAt:t,id:a(n,"payment_id")??"",provider:"dodopayments",referenceId:c(n)??"",refundedAmount:f(e),state:s,updatedAt:t}},D=(d,n,t)=>{const e={eventId:d,provider:"dodopayments",raw:{object:t,type:n}},r=a(t,"currency")??"usd";switch(n){case"dispute.lost":case"refund.succeeded":{const s=E(t,"amount");return{...e,amount:s===void 0?void 0:_(s,r),referenceId:c(t),refundId:a(t,"refund_id")??a(t,"dispute_id"),sessionId:a(t,"payment_id"),type:"payment.refunded"}}case"payment.cancelled":case"payment.failed":return{...e,referenceId:c(t),sessionId:a(t,"payment_id"),type:"payment.failed"};case"payment.succeeded":return{...e,amount:_(BigInt(Math.round(u(t,"total_amount")??0)),r),customerId:m(t),referenceId:c(t),sessionId:a(t,"payment_id"),subscriptionId:a(t,"subscription_id"),type:"payment.captured"};case"subscription.active":case"subscription.cancelled":case"subscription.expired":case"subscription.failed":case"subscription.on_hold":case"subscription.paused":case"subscription.plan_changed":case"subscription.renewed":case"subscription.updated":{const s=a(t,"status");return{...e,cancelAtPeriodEnd:v(t,"cancel_at_next_billing_date"),currentPeriodEnd:l(a(t,"next_billing_date")),currentPeriodStart:l(a(t,"previous_billing_date")),customerId:m(t),priceId:a(t,"product_id"),quantity:u(t,"quantity"),referenceId:c(t)??m(t),subscriptionId:a(t,"subscription_id"),type:P(g[s??""]??"past_due")}}default:return{...e,type:"unhandled"}}},z=d=>{const{webhookSecret:n}=d,t=d.client;return{cancelPayment:()=>I("manual payment cancellation"),cancelSubscription:async(e,r)=>{const s=r?.atPeriodEnd?{cancel_at_next_billing_date:!0}:{status:"cancelled"};return p(await t.subscriptions.update(e,s))},capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!0},capturePayment:e=>I("manual capture"),createCheckout:async e=>{const r=i(await t.checkoutSessions.create({customer:e.customerId?{customer_id:e.customerId}:void 0,metadata:{...e.metadata,referenceId:e.referenceId},product_cart:[{product_id:e.priceId,quantity:e.quantity??1}],return_url:e.successUrl}));return{id:a(r,"session_id")??"",provider:"dodopayments",url:a(r,"checkout_url")??""}},createPortalSession:async e=>{const r=i(await t.customers.customerPortal.create(e.customerId,{return_url:e.returnUrl}));return{url:a(r,"link")??a(r,"url")??""}},getOrCreateCustomer:async e=>{const r=i(await t.customers.create({email:e.email??"",name:e.metadata?.name??e.referenceId},{idempotencyKey:b("customer","dodopayments",e.referenceId)}));return{createdAt:Date.now(),email:a(r,"email")??e.email,id:a(r,"customer_id")??"",provider:"dodopayments",referenceId:e.referenceId}},getPaymentStatus:async e=>T(await t.payments.retrieve(e)),getSubscriptionStatus:async e=>p(await t.subscriptions.retrieve(e)),identifier:"dodopayments",parseWebhook:async({headers:e,payload:r})=>{const s=e.get("webhook-id")??"";await h({payload:r,secret:n,toleranceSeconds:d.webhookToleranceSeconds,webhookId:s,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const o=i(JSON.parse(r));return D(s,a(o,"type")??"",i(o.data))},refundPayment:async e=>{if(e.amount!==void 0)throw new S("PROVIDER_ERROR","dodopayments refunds a payment in full; partial refunds require line items and aren't supported here");const r=i(await t.refunds.create({payment_id:e.sessionId,reason:e.reason})),s=a(r,"currency")??"usd",o=_(BigInt(Math.round(u(r,"amount")??0)),s),y=a(r,"status")==="succeeded",w=y?"refunded":"captured";return{amount:o,capturedAmount:o,createdAt:Date.now(),id:e.sessionId,pending:!y,provider:"dodopayments",referenceId:"",refundedAmount:o,refundId:a(r,"refund_id"),state:w,updatedAt:Date.now()}},reportUsage:async e=>{await t.usageEvents.ingest({events:[{customer_id:e.customerId??e.referenceId,event_id:e.idempotencyKey,event_name:e.featureId,metadata:{value:e.quantity},timestamp:e.timestamp===void 0?void 0:new Date(e.timestamp).toISOString()}]})},resumeSubscription:async e=>{const r=await t.subscriptions.update(e,{cancel_at_next_billing_date:!1});return p(r)},updateSubscription:async(e,r)=>{if(r.priceId!==void 0||r.quantity!==void 0){const s=i(r.priceId!==void 0&&r.quantity!==void 0?void 0:await t.subscriptions.retrieve(e));await t.subscriptions.changePlan(e,{product_id:r.priceId??a(s,"product_id")??"",proration_billing_mode:"prorated_immediately",quantity:r.quantity??u(s,"quantity")??1})}return p(await t.subscriptions.retrieve(e))}}};export{z as createDodoPaymentsAdapter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/payment",
3
- "version": "1.0.0-alpha.102",
3
+ "version": "1.0.0-alpha.104",
4
4
  "description": "Provider-agnostic payments for Lunora: Stripe-first adapter, webhook sync, and subscription/payment state machine",
5
5
  "keywords": [
6
6
  "billing",
@@ -71,9 +71,9 @@
71
71
  "access": "public"
72
72
  },
73
73
  "dependencies": {
74
- "@lunora/errors": "1.0.0-alpha.30",
75
- "@lunora/server": "1.0.0-alpha.100",
76
- "@lunora/values": "1.0.0-alpha.38",
74
+ "@lunora/errors": "1.0.0-alpha.31",
75
+ "@lunora/server": "1.0.0-alpha.102",
76
+ "@lunora/values": "1.0.0-alpha.39",
77
77
  "dinero.js": "2.0.2"
78
78
  },
79
79
  "peerDependencies": {
@@ -1 +0,0 @@
1
- const c={authorized:{cancel:"canceled",capture:"captured",fail:"failed"},canceled:{},captured:{partial_refund:"partially_refunded",refund:"refunded"},failed:{},initiated:{authorize:"authorized",cancel:"canceled",capture:"captured",fail:"failed"},partially_refunded:{partial_refund:"partially_refunded",refund:"refunded"},refunded:{refund:"refunded"}},n={active:{cancel:"canceled",mark_past_due:"past_due",pause:"paused",renew:"active"},canceled:{},past_due:{activate:"active",cancel:"canceled",pause:"paused",renew:"active"},paused:{cancel:"canceled",resume:"active"},trialing:{activate:"active",cancel:"canceled",mark_past_due:"past_due"}},i=new Set(["canceled","failed","refunded"]),r=new Set(["canceled"]),t=(e,a)=>c[e][a],u=(e,a)=>t(e,a)!==void 0,d=(e,a)=>n[e][a],l=(e,a)=>d(e,a)!==void 0;export{i as PAYMENT_TERMINAL_STATES,r as SUBSCRIPTION_TERMINAL_STATES,u as canTransitionPayment,l as canTransitionSubscription,t as nextPaymentState,d as nextSubscriptionState};
@@ -1 +0,0 @@
1
- import{toErrorBody as R}from"@lunora/errors";import{usagePeriodStart as p,resolveEntitlements as S,featureNames as O,hasActivePrice as U}from"./entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as f}from"./LunoraPaymentError-BSxyhWgu.mjs";import{derivedIdempotencyKey as g,localRefundKey as _,LOCAL_REFUND_CLAIM_TYPE as D,idempotencyKey as A}from"./idempotencyKey-DBL6bpmj.mjs";import{subtractMoney as K,addMoney as B,compareMoney as b,isZeroMoney as C}from"./addMoney-B4ufWAnD.mjs";import{n as E}from"./observability-BteZ2dJS.mjs";import F from"./applyWebhookAction-DMAgu_yP.mjs";const y=(o,n=200,s)=>Response.json(o,{headers:{"content-type":"application/json",...s},status:n});let l=0;const T=()=>{const o=Date.now();return l=o>l?o:l+1,l},P=o=>o?`${o.currency}:${String(o.minorUnits)}`:"full",q=o=>o&&"referenceId"in o?Object.fromEntries(Object.entries(o).filter(([n])=>n!=="referenceId")):o,G=o=>y({applied:o.applied},o.status),W=o=>{const{adapter:n,store:s}=o,m=async e=>{if(!o.authorize)return;let t;try{t=await o.authorize(e)}catch{throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)}if(t!==!0)throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)},v=async e=>{await m(e.referenceId);const t=q(e.metadata);let r;const a=await s.getCustomerByReference(n.identifier,e.referenceId);if(a)r=a.id;else{const d=await n.getOrCreateCustomer({email:e.email,referenceId:e.referenceId});r=d.id,await s.upsertCustomer(d)}const i=e.idempotencyKey??await g("checkout",n.identifier,e.referenceId,e.priceId,e.mode,String(e.quantity??1),e.successUrl,e.cancelUrl,t?JSON.stringify(t):"");return n.createCheckout({...e,customerId:r,idempotencyKey:i,metadata:t})},k=(e,t,r)=>{const a=e-t;return{allowed:a>=r,balance:a,limit:e,unlimited:!1,used:t}},N=async(e,t,r,a,i)=>{const d=e.limit(a);if(d!==void 0){const c=await s.sumUsage(r,a,p(t));return k(d,c,i)}return{allowed:e.has(a),unlimited:e.has(a)}},w=async e=>{const t=()=>new f("NOT_FOUND",`payment session "${e}" not found`);let r=await s.getPaymentSession(n.identifier,e);if(!r)try{r=await n.getPaymentStatus(e)}catch{throw t()}if(!r.referenceId)throw t();try{await m(r.referenceId)}catch{throw t()}return r},h=async(e,t)=>{const r={...e,...t,updatedAt:Date.now()};return await s.upsertPaymentSession(r),r};return{adapter:n,attach:async e=>v({...e,mode:e.mode??"subscription"}),cancelPayment:async(e,t)=>{const r=await w(e),a=t?.idempotencyKey??A("cancel_payment",n.identifier,e),i=await n.cancelPayment(e,{...t,idempotencyKey:a});return h(r,{state:i.state})},cancelSubscription:async(e,t)=>{const r=await s.getSubscription(n.identifier,e);if(!r)throw new f("NOT_FOUND",`subscription "${e}" not found`);try{await m(r.referenceId)}catch{throw new f("NOT_FOUND",`subscription "${e}" not found`)}const a=t?.idempotencyKey??A("cancel_subscription",n.identifier,e),i=await n.cancelSubscription(e,{...t,idempotencyKey:a});return await s.upsertSubscription(i),i},capturePayment:async e=>{const t=await w(e.sessionId),r=e.idempotencyKey??await g("capture_payment",n.identifier,e.sessionId,P(e.amount)),a=await n.capturePayment({...e,idempotencyKey:r});return h(t,{capturedAmount:a.capturedAmount,state:a.state})},check:async e=>{if(await m(e.referenceId),e.featureId===void 0&&e.priceId===void 0)throw new f("CONFIG_INVALID","check() requires a featureId or priceId");if(n.checkEntitlement)return n.checkEntitlement(e);const t=await s.listSubscriptionsByReference(e.referenceId);if(e.priceId!==void 0)return{allowed:U(t,e.priceId),unlimited:!1};if(e.featureId===void 0)throw new f("CONFIG_INVALID","check() requires a featureId or priceId");if(!o.entitlements)throw new f("CONFIG_INVALID","check() requires `entitlements` to be configured");const r=S(o.entitlements,t);return N(r,t,e.referenceId,e.featureId,e.quantity??1)},createCheckout:async e=>v(e),createPortalSession:async(e,t)=>{await m(e);const r=await s.getCustomerByReference(n.identifier,e);if(!r)throw new f("NOT_FOUND",`no customer for reference "${e}"`);return n.createPortalSession({customerId:r.id,returnUrl:t})},handleWebhook:async e=>{let t;try{const a=await e.text();t=await n.parseWebhook({headers:e.headers,payload:a})}catch(a){if(a instanceof f){const{body:i,status:d}=R(a);return y({error:i.message},d)}return y({error:"webhook error"},400)}const r=await F(s,t,o.observability);return r.reason==="orphaned"?y({applied:r.applied,reason:r.reason},500):y({applied:r.applied,reason:r.reason},200)},listBalances:async e=>{if(await m(e),n.getBalances)return n.getBalances(e);if(!o.entitlements)throw new f("CONFIG_INVALID","listBalances() requires `entitlements` to be configured");const t=await s.listSubscriptionsByReference(e),r=S(o.entitlements,t),a=O(o.entitlements),i=a.filter(c=>r.limit(c)!==void 0),d=i.length===0?new Map:await s.sumUsageByFeature(e,i,p(t));return a.map(c=>{const u=r.limit(c);return u!==void 0?{featureId:c,...k(u,d.get(c)??0,1)}:{featureId:c,allowed:r.has(c),unlimited:r.has(c)}})},listSubscriptions:async e=>(await m(e),s.listSubscriptionsByReference(e)),refundPayment:async e=>{const t=await w(e.sessionId),r=e.amount??K(t.capturedAmount,t.refundedAmount),a=B(t.refundedAmount,r);if(b(a,t.capturedAmount)>0)throw new f("VALIDATION_ERROR",`refundPayment(): refunding ${String(e.amount?.minorUnits)} would exceed the captured amount on session "${e.sessionId}"`);if(C(r))return t;const i=e.amount??(b(r,t.capturedAmount)===0?void 0:r),d=e.idempotencyKey??await g("refund_payment",n.identifier,e.sessionId,P(i),e.reason??""),c=await n.refundPayment({...e,amount:i,idempotencyKey:d});if(c.pending)return t;const u=_(e.sessionId,c.refundId,r);await s.markEventProcessed(n.identifier,u,D);try{return await h(t,{refundedAmount:a,state:b(a,t.capturedAmount)<0?"partially_refunded":"refunded"})}catch(I){throw await s.releaseEvent(n.identifier,u),I}},store:s,track:async e=>{await m(e.referenceId);const t=e.quantity===void 0?1:e.quantity;if(!Number.isSafeInteger(t)||t<0)throw new f("VALIDATION_ERROR",`track(): \`quantity\` must be a non-negative safe integer (got ${String(e.quantity)})`);const r=e.idempotencyKey??crypto.randomUUID(),a=e.mode==="set",i=a?await s.listSubscriptionsByReference(e.referenceId):void 0,d=i===void 0?0:await s.sumUsage(e.referenceId,e.featureId,p(i));if(a?t===d:t===0)return{recorded:!1,reportedToProvider:!1};const c=a?t-d:t;if(!await s.recordUsage({createdAt:T(),featureId:e.featureId,idempotencyKey:r,...a?{mode:"set"}:{},provider:n.identifier,quantity:t,referenceId:e.referenceId,reportedToProvider:!1}))return{recorded:!1,reportedToProvider:!1};if(c<=0||!n.capabilities.usageMetering||!n.reportUsage)return{recorded:!0,reportedToProvider:!1};try{const I=await s.getCustomerByReference(n.identifier,e.referenceId);return await n.reportUsage({customerId:I?.id,featureId:e.featureId,idempotencyKey:r,quantity:c,referenceId:e.referenceId}),await s.markUsageReported(n.identifier,r),{recorded:!0,reportedToProvider:!0}}catch{return E(o.observability,{featureId:e.featureId,provider:n.identifier,referenceId:e.referenceId,type:"usage.report_failed"}),{recorded:!0,reportedToProvider:!1}}}}};export{W as createPayment,G as webhookResponse};