@lunora/payment 1.0.0-alpha.106 → 1.0.0-alpha.108

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-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};
1
+ import{createAdapterRegistry as r}from"./packem_shared/createAdapterRegistry-DyCsry1Q.mjs";import{lunoraDatabaseToPaymentDatabase as a,paymentsFromContext as n}from"./packem_shared/lunoraDatabaseToPaymentDatabase-CZmZ5LeG.mjs";import{createPayment as y,webhookResponse as i}from"./packem_shared/createPayment-Cmyk1BcJ.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
+ import{toErrorBody as P}from"@lunora/errors";import{usagePeriodStart as b,resolveEntitlements as A,featureNames as N,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 k}from"./idempotencyKey-DBL6bpmj.mjs";import{subtractMoney as E,addMoney as K,compareMoney as R,isZeroMoney as B}from"./addMoney-B4ufWAnD.mjs";import{n as T}from"./observability-BteZ2dJS.mjs";import C 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 F=()=>{const o=Date.now();return h=o>h?o:h+1,h},S=o=>o?`${o.currency}:${String(o.minorUnits)}`:"full",q=o=>o&&"referenceId"in o?Object.fromEntries(Object.entries(o).filter(([n])=>n!=="referenceId")):o,W=o=>y({applied:o.applied},o.status),G=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}},O=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)}},p=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},g=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 p(e),a=t?.idempotencyKey??k("cancel_payment",n.identifier,e),i=await n.cancelPayment(e,{...t,idempotencyKey:a});return g(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??k("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 p(e.sessionId),r=e.idempotencyKey??await v("capture_payment",n.identifier,e.sessionId,S(e.amount)),a=await n.capturePayment({...e,idempotencyKey:r});return g(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("VALIDATION_ERROR","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("VALIDATION_ERROR","check() requires a featureId or priceId");if(!o.entitlements)throw new f("CONFIG_INVALID","check() requires `entitlements` to be configured");const r=A(o.entitlements,t);return O(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}=P(a);return y({error:i.message},d)}return y({error:"webhook error"},400)}const r=await C(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=A(o.entitlements,t),a=N(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 p(e.sessionId),r=e.amount??E(t.capturedAmount,t.refundedAmount),a=K(t.refundedAmount,r);if(R(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(B(r))return t;const i=e.amount??(R(r,t.capturedAmount)===0?void 0:r),d=e.idempotencyKey??await v("refund_payment",n.identifier,e.sessionId,S(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 g(t,{refundedAmount:a,state:R(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,b(i));if(a?t===d:t===0)return{recorded:!1,reportedToProvider:!1};const c=a?t-d:t;if(!await s.recordUsage({createdAt:F(),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 T(o.observability,{featureId:e.featureId,provider:n.identifier,referenceId:e.referenceId,type:"usage.report_failed"}),{recorded:!0,reportedToProvider:!1}}}}};export{G as createPayment,W as webhookResponse};
@@ -1 +1 @@
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
+ import{createPayment as i}from"./createPayment-Cmyk1BcJ.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{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};
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}},D=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}},O=(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=n==="subscription.paused"?"paused":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=>D(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 O(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};
@@ -1 +1 @@
1
- import{LunoraPaymentError as E}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as K}from"../packem_shared/idempotencyKey-DBL6bpmj.mjs";import{a as m,r as a,d as v,b as o}from"../packem_shared/json-BJJPJVYj.mjs";import{compareMoney as P,money as y,zeroMoney as f}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{assertWebhookSecret as T}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{s as q}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const M={canceled:"canceled",processing:"authorized",requires_action:"authorized",requires_capture:"authorized",requires_confirmation:"initiated",requires_payment_method:"initiated",succeeded:"captured"},S={active:"active",canceled:"canceled",incomplete:"past_due",incomplete_expired:"canceled",past_due:"past_due",paused:"paused",trialing:"trialing",unpaid:"past_due"},c=s=>a(m(s.metadata),"referenceId")??a(s,"client_reference_id"),I=s=>{const n=m(s.items),t=Array.isArray(n.data)?n.data:[];return m(t[0])},w=s=>a(m(I(s).price),"id"),g=s=>o(I(s),"quantity"),h=s=>{const n=o(I(s),"current_period_end")??o(s,"current_period_end");return n===void 0?void 0:n*1e3},A=s=>{const n=o(I(s),"current_period_start")??o(s,"current_period_start");return n===void 0?void 0:n*1e3},_=s=>{const n=m(s),t=a(n,"currency")??"usd",e=o(n,"amount")??0,r=y(BigInt(Math.round(e)),t),i=M[a(n,"status")??""]??"initiated",d=Date.now();return{amount:r,capturedAmount:i==="captured"?y(BigInt(Math.round(o(n,"amount_received")??e)),t):f(t),createdAt:d,id:a(n,"id")??"",provider:"stripe",referenceId:c(n)??"",refundedAmount:f(t),state:i,updatedAt:d}},l=s=>{const n=m(s),t=Date.now();return{cancelAtPeriodEnd:v(n,"cancel_at_period_end")??!1,createdAt:t,currentPeriodEnd:h(n),currentPeriodStart:A(n),id:a(n,"id")??"",priceId:w(n)??"",provider:"stripe",quantity:g(n)??1,referenceId:c(n)??"",state:S[a(n,"status")??""]??"past_due",updatedAt:t}},B=(s,n,t)=>{const e={eventId:s,provider:"stripe",raw:{object:t,type:n}},r=a(t,"currency")??"usd";switch(n){case"charge.refunded":return{...e,amount:y(BigInt(Math.round(o(t,"amount_refunded")??0)),r),amountKind:"absolute",referenceId:c(t),sessionId:a(t,"payment_intent")??a(t,"id"),type:"payment.refunded"};case"checkout.session.completed":{if(a(t,"mode")==="subscription"){const u=a(t,"payment_status"),p=u==="paid"||u==="no_payment_required";return{...e,customerId:a(t,"customer"),referenceId:c(t),subscriptionId:a(t,"subscription"),type:p?"subscription.active":"subscription.updated"}}const i=a(t,"payment_intent");if(i===void 0&&a(t,"payment_status")!=="no_payment_required")return{...e,type:"unhandled"};const d=o(t,"amount_total");return{...e,amount:d===void 0?void 0:y(BigInt(Math.round(d)),r),customerId:a(t,"customer"),referenceId:c(t),sessionId:i??a(t,"id"),type:"payment.captured"}}case"customer.subscription.created":case"customer.subscription.updated":return{...e,cancelAtPeriodEnd:v(t,"cancel_at_period_end"),currentPeriodEnd:h(t),currentPeriodStart:A(t),customerId:a(t,"customer"),priceId:w(t),quantity:g(t),referenceId:c(t),subscriptionId:a(t,"id"),type:q(S[a(t,"status")??""]??"past_due")};case"customer.subscription.deleted":return{...e,referenceId:c(t),subscriptionId:a(t,"id"),type:"subscription.canceled"};case"payment_intent.amount_capturable_updated":return{...e,amount:y(BigInt(Math.round(o(t,"amount")??0)),r),referenceId:c(t),sessionId:a(t,"id"),type:"payment.authorized"};case"payment_intent.payment_failed":return{...e,referenceId:c(t),sessionId:a(t,"id"),type:"payment.failed"};case"payment_intent.succeeded":return{...e,amount:y(BigInt(Math.round(o(t,"amount_received")??o(t,"amount")??0)),r),customerId:a(t,"customer"),referenceId:c(t),sessionId:a(t,"id"),type:"payment.captured"};default:return{...e,type:"unhandled"}}},C=s=>{const{webhookSecret:n}=s,t=s.client;return{cancelPayment:async(e,r)=>{const i=await t.paymentIntents.cancel(e,void 0,{idempotencyKey:r?.idempotencyKey});return _(i)},cancelSubscription:async(e,r)=>{const i=r?.atPeriodEnd?await t.subscriptions.update(e,{cancel_at_period_end:!0},{idempotencyKey:r.idempotencyKey}):await t.subscriptions.cancel(e,void 0,{idempotencyKey:r?.idempotencyKey});return l(i)},capabilities:{merchantOfRecord:!1,portal:!0,usageMetering:!0},capturePayment:async e=>{const r=await t.paymentIntents.capture(e.sessionId,e.amount?{amount_to_capture:Number(e.amount.minorUnits)}:void 0,{idempotencyKey:e.idempotencyKey});return _(r)},createCheckout:async e=>{const r=await t.checkout.sessions.create({cancel_url:e.cancelUrl,client_reference_id:e.referenceId,customer:e.customerId,line_items:[{price:e.priceId,quantity:e.quantity??1}],metadata:{...e.metadata,referenceId:e.referenceId},mode:e.mode,subscription_data:e.mode==="subscription"?{metadata:{referenceId:e.referenceId}}:void 0,success_url:e.successUrl},{idempotencyKey:e.idempotencyKey});return{id:r.id,provider:"stripe",url:r.url??""}},createPortalSession:async e=>({url:(await t.billingPortal.sessions.create({customer:e.customerId,return_url:e.returnUrl})).url}),getOrCreateCustomer:async e=>{const r=await t.customers.create({email:e.email,metadata:{...e.metadata,referenceId:e.referenceId}},{idempotencyKey:K("customer","stripe",e.referenceId)});return{createdAt:Date.now(),email:r.email??void 0,id:r.id,provider:"stripe",referenceId:e.referenceId}},getPaymentStatus:async e=>_(await t.paymentIntents.retrieve(e)),getSubscriptionStatus:async e=>l(await t.subscriptions.retrieve(e)),identifier:"stripe",parseWebhook:async({headers:e,payload:r})=>{T(n);const i=e.get("stripe-signature")??"";let d;try{d=await t.webhooks.constructEventAsync(r,i,n,s.webhookToleranceSeconds)}catch(p){throw new E("WEBHOOK_SIGNATURE_INVALID",p instanceof Error?p.message:"invalid webhook signature")}const u=m(m(d.data).object);return B(d.id,d.type,u)},refundPayment:async e=>{const r=await t.refunds.create({amount:e.amount?Number(e.amount.minorUnits):void 0,payment_intent:e.sessionId,reason:e.reason},{idempotencyKey:e.idempotencyKey}),i=await t.paymentIntents.retrieve(e.sessionId),d=_(i),u=e.amount??d.capturedAmount,p=e.amount!==void 0&&P(e.amount,d.capturedAmount)<0;return{...d,refundedAmount:u,refundId:r.id,state:p?"partially_refunded":"refunded"}},reportUsage:async e=>{await t.billing.meterEvents.create({event_name:e.featureId,identifier:e.idempotencyKey,payload:{stripe_customer_id:e.customerId??"",value:String(e.quantity)},timestamp:e.timestamp===void 0?void 0:Math.floor(e.timestamp/1e3)},{idempotencyKey:e.idempotencyKey})},resumeSubscription:async e=>{const r=await t.subscriptions.update(e,{cancel_at_period_end:!1});return l(r)},updateSubscription:async(e,r)=>{const i={};if(r.priceId!==void 0||r.quantity!==void 0){const u=await t.subscriptions.retrieve(e);i.items=[{id:u.items.data[0]?.id,price:r.priceId,quantity:r.quantity}]}const d=await t.subscriptions.update(e,i);return l(d)}}};export{C as createStripeAdapter};
1
+ import{LunoraPaymentError as E}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as K}from"../packem_shared/idempotencyKey-DBL6bpmj.mjs";import{a as u,r as a,d as v,b as c}from"../packem_shared/json-BJJPJVYj.mjs";import{compareMoney as P,money as m,zeroMoney as f}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{assertWebhookSecret as T}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{s as q}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const M={canceled:"canceled",processing:"authorized",requires_action:"authorized",requires_capture:"authorized",requires_confirmation:"initiated",requires_payment_method:"initiated",succeeded:"captured"},h={active:"active",canceled:"canceled",incomplete:"past_due",incomplete_expired:"canceled",past_due:"past_due",paused:"paused",trialing:"trialing",unpaid:"past_due"},o=s=>a(u(s.metadata),"referenceId")??a(s,"client_reference_id"),I=s=>{const n=u(s.items),e=Array.isArray(n.data)?n.data:[];return u(e[0])},S=s=>a(u(I(s).price),"id"),w=s=>c(I(s),"quantity"),g=s=>{const n=c(I(s),"current_period_end")??c(s,"current_period_end");return n===void 0?void 0:n*1e3},A=s=>{const n=c(I(s),"current_period_start")??c(s,"current_period_start");return n===void 0?void 0:n*1e3},_=s=>{const n=u(s),e=a(n,"currency")??"usd",t=c(n,"amount")??0,r=m(BigInt(Math.round(t)),e),i=M[a(n,"status")??""]??"initiated",d=Date.now();return{amount:r,capturedAmount:i==="captured"?m(BigInt(Math.round(c(n,"amount_received")??t)),e):f(e),createdAt:d,id:a(n,"id")??"",provider:"stripe",referenceId:o(n)??"",refundedAmount:f(e),state:i,updatedAt:d}},l=s=>{const n=u(s),e=Date.now();return{cancelAtPeriodEnd:v(n,"cancel_at_period_end")??!1,createdAt:e,currentPeriodEnd:g(n),currentPeriodStart:A(n),id:a(n,"id")??"",priceId:S(n)??"",provider:"stripe",quantity:w(n)??1,referenceId:o(n)??"",state:h[a(n,"status")??""]??"past_due",updatedAt:e}},k=({base:s,currency:n,object:e})=>{const t=a(e,"payment_status"),r=t==="paid"||t==="no_payment_required";if(a(e,"mode")==="subscription")return{...s,customerId:a(e,"customer"),referenceId:o(e),subscriptionId:a(e,"subscription"),type:r?"subscription.active":"subscription.updated"};const i=a(e,"payment_intent");if(i===void 0&&t!=="no_payment_required")return{...s,type:"unhandled"};const d=c(e,"amount_total");return{...s,amount:d===void 0?void 0:m(BigInt(Math.round(d)),n),customerId:a(e,"customer"),referenceId:o(e),sessionId:i??a(e,"id"),type:r?"payment.captured":"payment.authorized"}},B=({base:s,currency:n,object:e})=>a(e,"status")!=="lost"?{...s,type:"unhandled"}:{...s,amount:m(BigInt(Math.round(c(e,"amount")??0)),n),referenceId:o(e),refundId:a(e,"id"),sessionId:a(e,"payment_intent"),type:"payment.refunded"},U=(s,n,e)=>{const t={eventId:s,provider:"stripe",raw:{object:e,type:n}},r=a(e,"currency")??"usd",i={base:t,currency:r,object:e};switch(n){case"charge.dispute.closed":return B(i);case"charge.refunded":return{...t,amount:m(BigInt(Math.round(c(e,"amount_refunded")??0)),r),amountKind:"absolute",referenceId:o(e),sessionId:a(e,"payment_intent")??a(e,"id"),type:"payment.refunded"};case"checkout.session.async_payment_failed":return a(e,"mode")==="subscription"?{...t,customerId:a(e,"customer"),referenceId:o(e),subscriptionId:a(e,"subscription"),type:"subscription.past_due"}:{...t,referenceId:o(e),sessionId:a(e,"payment_intent")??a(e,"id"),type:"payment.failed"};case"checkout.session.async_payment_succeeded":case"checkout.session.completed":return k(i);case"customer.subscription.created":case"customer.subscription.updated":return{...t,cancelAtPeriodEnd:v(e,"cancel_at_period_end"),currentPeriodEnd:g(e),currentPeriodStart:A(e),customerId:a(e,"customer"),priceId:S(e),quantity:w(e),referenceId:o(e),subscriptionId:a(e,"id"),type:q(h[a(e,"status")??""]??"past_due")};case"customer.subscription.deleted":return{...t,referenceId:o(e),subscriptionId:a(e,"id"),type:"subscription.canceled"};case"payment_intent.amount_capturable_updated":return{...t,amount:m(BigInt(Math.round(c(e,"amount")??0)),r),referenceId:o(e),sessionId:a(e,"id"),type:"payment.authorized"};case"payment_intent.payment_failed":return{...t,referenceId:o(e),sessionId:a(e,"id"),type:"payment.failed"};case"payment_intent.succeeded":return{...t,amount:m(BigInt(Math.round(c(e,"amount_received")??c(e,"amount")??0)),r),customerId:a(e,"customer"),referenceId:o(e),sessionId:a(e,"id"),type:"payment.captured"};default:return{...t,type:"unhandled"}}},W=s=>{const{webhookSecret:n}=s,e=s.client;return{cancelPayment:async(t,r)=>{const i=await e.paymentIntents.cancel(t,void 0,{idempotencyKey:r?.idempotencyKey});return _(i)},cancelSubscription:async(t,r)=>{const i=r?.atPeriodEnd?await e.subscriptions.update(t,{cancel_at_period_end:!0},{idempotencyKey:r.idempotencyKey}):await e.subscriptions.cancel(t,void 0,{idempotencyKey:r?.idempotencyKey});return l(i)},capabilities:{merchantOfRecord:!1,portal:!0,usageMetering:!0},capturePayment:async t=>{const r=await e.paymentIntents.capture(t.sessionId,t.amount?{amount_to_capture:Number(t.amount.minorUnits)}:void 0,{idempotencyKey:t.idempotencyKey});return _(r)},createCheckout:async t=>{const r=await e.checkout.sessions.create({cancel_url:t.cancelUrl,client_reference_id:t.referenceId,customer:t.customerId,line_items:[{price:t.priceId,quantity:t.quantity??1}],metadata:{...t.metadata,referenceId:t.referenceId},mode:t.mode,subscription_data:t.mode==="subscription"?{metadata:{referenceId:t.referenceId}}:void 0,success_url:t.successUrl},{idempotencyKey:t.idempotencyKey});return{id:r.id,provider:"stripe",url:r.url??""}},createPortalSession:async t=>({url:(await e.billingPortal.sessions.create({customer:t.customerId,return_url:t.returnUrl})).url}),getOrCreateCustomer:async t=>{const r=await e.customers.create({email:t.email,metadata:{...t.metadata,referenceId:t.referenceId}},{idempotencyKey:K("customer","stripe",t.referenceId)});return{createdAt:Date.now(),email:r.email??void 0,id:r.id,provider:"stripe",referenceId:t.referenceId}},getPaymentStatus:async t=>_(await e.paymentIntents.retrieve(t)),getSubscriptionStatus:async t=>l(await e.subscriptions.retrieve(t)),identifier:"stripe",parseWebhook:async({headers:t,payload:r})=>{T(n);const i=t.get("stripe-signature")??"";let d;try{d=await e.webhooks.constructEventAsync(r,i,n,s.webhookToleranceSeconds)}catch(y){throw new E("WEBHOOK_SIGNATURE_INVALID",y instanceof Error?y.message:"invalid webhook signature")}const p=u(u(d.data).object);return U(d.id,d.type,p)},refundPayment:async t=>{const r=await e.refunds.create({amount:t.amount?Number(t.amount.minorUnits):void 0,payment_intent:t.sessionId,reason:t.reason},{idempotencyKey:t.idempotencyKey}),i=await e.paymentIntents.retrieve(t.sessionId),d=_(i),p=t.amount??d.capturedAmount,y=t.amount!==void 0&&P(t.amount,d.capturedAmount)<0;return{...d,refundedAmount:p,refundId:r.id,state:y?"partially_refunded":"refunded"}},reportUsage:async t=>{await e.billing.meterEvents.create({event_name:t.featureId,identifier:t.idempotencyKey,payload:{stripe_customer_id:t.customerId??"",value:String(t.quantity)},timestamp:t.timestamp===void 0?void 0:Math.floor(t.timestamp/1e3)},{idempotencyKey:t.idempotencyKey})},resumeSubscription:async t=>{const r=await e.subscriptions.update(t,{cancel_at_period_end:!1});return l(r)},updateSubscription:async(t,r)=>{const i={};if(r.priceId!==void 0||r.quantity!==void 0){const p=await e.subscriptions.retrieve(t);i.items=[{id:p.items.data[0]?.id,price:r.priceId,quantity:r.quantity}]}const d=await e.subscriptions.update(t,i);return l(d)}}};export{W as createStripeAdapter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/payment",
3
- "version": "1.0.0-alpha.106",
3
+ "version": "1.0.0-alpha.108",
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.32",
75
- "@lunora/server": "1.0.0-alpha.104",
76
- "@lunora/values": "1.0.0-alpha.40",
74
+ "@lunora/errors": "1.0.0-alpha.34",
75
+ "@lunora/server": "1.0.0-alpha.106",
76
+ "@lunora/values": "1.0.0-alpha.42",
77
77
  "dinero.js": "2.0.2"
78
78
  },
79
79
  "peerDependencies": {
@@ -1 +0,0 @@
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};