pesafy 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/utils.mjs ADDED
@@ -0,0 +1,32 @@
1
+ import { formatSafaricomPhone } from "./phone.mjs";
2
+
3
+ //#region src/mpesa/stk-push/utils.ts
4
+ /**
5
+ * Generates the STK Push password.
6
+ * Formula: Base64( Shortcode + Passkey + Timestamp )
7
+ *
8
+ * Uses btoa() — works in Node.js ≥18, Bun, browsers, and edge runtimes.
9
+ */
10
+ function getStkPushPassword(shortCode, passKey, timestamp) {
11
+ return btoa(`${shortCode}${passKey}${timestamp}`);
12
+ }
13
+ /**
14
+ * Returns a Daraja-compatible timestamp: YYYYMMDDHHmmss
15
+ *
16
+ * Call this ONCE per request and reuse the result.
17
+ */
18
+ function getTimestamp() {
19
+ const now = /* @__PURE__ */ new Date();
20
+ const pad = (n) => n.toString().padStart(2, "0");
21
+ return [
22
+ now.getFullYear(),
23
+ pad(now.getMonth() + 1),
24
+ pad(now.getDate()),
25
+ pad(now.getHours()),
26
+ pad(now.getMinutes()),
27
+ pad(now.getSeconds())
28
+ ].join("");
29
+ }
30
+
31
+ //#endregion
32
+ export { getStkPushPassword, getTimestamp };
@@ -0,0 +1 @@
1
+ import{readFile as e}from"node:fs/promises";import{constants as t,publicEncrypt as n}from"node:crypto";import{z as r}from"zod";var i=class e extends Error{code;statusCode;response;requestId;cause;retryable;constructor(t){super(t.message),Object.defineProperty(this,`name`,{value:`PesafyError`}),this.code=t.code,this.statusCode=t.statusCode,this.response=t.response,this.requestId=t.requestId,this.cause=t.cause,this.retryable=t.retryable??(t.code===`NETWORK_ERROR`||t.code===`TIMEOUT`||t.code===`RATE_LIMITED`||t.code===`REQUEST_FAILED`),Error.captureStackTrace&&Error.captureStackTrace(this,e)}get isValidation(){return this.code===`VALIDATION_ERROR`}get isAuth(){return this.code===`AUTH_FAILED`||this.code===`INVALID_CREDENTIALS`}toJSON(){return{name:this.name,code:this.code,message:this.message,statusCode:this.statusCode,requestId:this.requestId,retryable:this.retryable}}};function a(e){return new i(e)}function o(e,t){return t?.idempotency?{...e,idempotency:t.idempotency}:e}const s=new Set([429,500,502,503,504]);function c(e){return new Promise(t=>setTimeout(t,e))}function l(e){let t=e*.25;return e+(Math.random()*t*2-t)}async function u(e,t){let n=t.retries??4,r=t.retryDelay??2e3,a=t.timeout??3e4,o={"Content-Type":`application/json`,Accept:`application/json`,...t.headers},u=t.idempotency,d=t.idempotencyKey;if(t.method===`POST`&&u?.enabled){d=u.reserve(d);let e=u.headerName;o[e]=d}else d&&(o[`Idempotency-Key`]=d);let f={method:t.method,headers:o,...t.body===void 0?{}:{body:JSON.stringify(t.body)}},p=null;for(let o=0;o<=n;o++){if(o>0){let i=l(r*2**(o-1));console.warn(`[pesafy] Retry ${o}/${n} → ${t.method} ${e} in ${Math.round(i)} ms`),await c(i)}let m=new AbortController,h=setTimeout(()=>m.abort(),a),g;try{g=await fetch(e,{...f,signal:m.signal})}catch(t){if(clearTimeout(h),p=t instanceof Error&&t.name===`AbortError`?new i({code:`TIMEOUT`,message:`Request to ${e} timed out after ${a} ms`,cause:t,retryable:!0}):new i({code:`NETWORK_ERROR`,message:`Network error: ${t instanceof Error?t.message:String(t)}`,cause:t,retryable:!0}),o<n)continue;throw d&&u?.enabled&&u.release(d),p}finally{clearTimeout(h)}let _=``,v=null,y=g.headers.get(`content-type`)??``;try{_=await g.text(),_&&(v=y.includes(`application/json`)?JSON.parse(_):_)}catch{v=_||null}let b={};if(g.headers.forEach((e,t)=>{b[t]=e}),g.ok)return d&&u?.enabled&&u.complete(d),{data:v,status:g.status,headers:b};let x=s.has(g.status),S=typeof v==`object`&&v?v:{},C=S.errorMessage??S.ResponseDescription??S.resultDesc??_??`HTTP ${g.status}`;if(p=new i({code:x?`REQUEST_FAILED`:`API_ERROR`,message:C,statusCode:g.status,response:v,retryable:x,...typeof S.requestId==`string`?{requestId:S.requestId}:{}}),!(x&&o<n))throw d&&u?.enabled&&u.release(d),p}throw d&&u?.enabled&&u.release(d),p}const d={INVALID_AUTH_TYPE:`400.008.01`,INVALID_GRANT_TYPE:`400.008.02`};var f=class{consumerKey;consumerSecret;baseUrl;cachedToken=null;tokenExpiresAt=0;constructor(e,t,n){this.consumerKey=e,this.consumerSecret=t,this.baseUrl=n}getBasicAuthHeader(){let e=`${this.consumerKey}:${this.consumerSecret}`;return`Basic ${Buffer.from(e,`utf-8`).toString(`base64`)}`}mapAuthError(e){if(e instanceof i){if(e.code===`AUTH_FAILED`)throw e;let t=e.response;if(t&&typeof t==`object`){let n=t.errorCode??t.error_code;if(n===d.INVALID_AUTH_TYPE)throw new i({code:`AUTH_FAILED`,message:`Invalid authentication type (400.008.01). Use Basic authentication: Authorization: Basic <Base64(consumerKey:consumerSecret)>.`,...e.statusCode!==void 0&&{statusCode:e.statusCode},response:e.response});if(n===d.INVALID_GRANT_TYPE)throw new i({code:`AUTH_FAILED`,message:`Invalid grant type (400.008.02). Set grant_type=client_credentials in the request query parameters.`,...e.statusCode!==void 0&&{statusCode:e.statusCode},response:e.response})}throw e}throw e}async getAccessToken(){let e=Date.now()/1e3;if(this.cachedToken&&this.tokenExpiresAt>e+60)return this.cachedToken;let t=`${this.baseUrl}/oauth/v1/generate?grant_type=client_credentials`;try{let n=await u(t,{method:`GET`,headers:{Authorization:this.getBasicAuthHeader()}}),{access_token:r,expires_in:a}=n.data;if(!r)throw new i({code:`AUTH_FAILED`,message:`Daraja did not return an access token. Verify your consumer key and consumer secret.`,response:n.data});return this.cachedToken=r,this.tokenExpiresAt=e+(a??3600),this.cachedToken}catch(e){return this.mapAuthError(e)}}clearCache(){this.cachedToken=null,this.tokenExpiresAt=0}};function p(e,r){try{let i=Buffer.from(e,`utf-8`);return n({key:r,padding:t.RSA_PKCS1_PADDING},i).toString(`base64`)}catch(e){throw new i({code:`ENCRYPTION_FAILED`,message:`Failed to encrypt security credential. Ensure the certificate PEM is valid and matches the environment (sandbox/production).`,cause:e})}}function m(e){let t=crypto.randomUUID();return e?`${e}-${t}`:t}function h(){return m(`pesafy`)}function g(){return crypto.randomUUID()}var _=class{entries=new Map;get(e){return this.entries.get(e)}set(e,t){this.entries.set(e,t)}delete(e){this.entries.delete(e)}prune(e){let t=Date.now()-e;for(let[e,n]of this.entries)n.createdAt<t&&this.entries.delete(e)}},v=class{enabled;headerName;ttlMs;store;generateKey;constructor(e={}){this.enabled=e.enabled!==!1,this.headerName=e.headerName??`Idempotency-Key`,this.ttlMs=e.ttlMs??864e5,this.store=e.store??new _,this.generateKey=e.generateKey??m}reserve(e){if(!this.enabled)return e??this.generateKey();this.pruneExpired();let t=e??this.generateKey(),n=this.store.get(t);if(n){if(Date.now()-n.createdAt<this.ttlMs)throw new i({code:`IDEMPOTENCY_ERROR`,message:`Duplicate request detected for idempotency key "${t}".`});this.store.delete(t)}return this.store.set(t,{key:t,createdAt:Date.now()}),t}complete(e){if(!this.enabled)return;let t=this.store.get(e);t&&this.store.set(e,{...t,completedAt:Date.now()})}release(e){this.enabled&&this.store.delete(e)}pruneExpired(){this.store instanceof _&&this.store.prune(this.ttlMs)}};function y(e){return{ok:!0,data:e}}function b(e){return{ok:!1,error:e}}function x(e,t=`Request`){return new i({code:`VALIDATION_ERROR`,message:`${t} validation failed: ${e.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`; `)}`,cause:e})}function S(e,t,n){let r=e.safeParse(t);if(!r.success)throw x(r.error,n);return r.data}r.enum([`sandbox`,`production`]),r.string().min(10).regex(/^254\d{9}$/,`Must be Safaricom format 2547XXXXXXXX`);const C=r.number().finite().positive().refine(e=>Math.round(e)>=1,{message:`amount must round to at least 1 KES`}),w=r.string().trim().min(1),T=r.string().url();r.object({errorMessage:r.string().optional(),ResponseDescription:r.string().optional(),resultDesc:r.string().optional(),requestId:r.string().optional()}).passthrough();const E=r.enum([`1`,`2`,`4`]),D=r.object({ConversationID:r.string().optional(),OriginatorConversationID:r.string().optional(),ResponseCode:r.string(),ResponseDescription:r.string()}).passthrough(),ee=r.object({transactionId:r.string().optional(),originalConversationId:r.string().optional(),partyA:w,identifierType:E,resultUrl:T,queueTimeOutUrl:T,commandId:r.literal(`TransactionStatusQuery`).optional(),remarks:r.string().optional(),occasion:r.string().optional()}).superRefine((e,t)=>{!e.transactionId?.trim()&&!e.originalConversationId?.trim()&&t.addIssue({code:`custom`,message:`Either transactionId (M-Pesa Receipt Number) or originalConversationId is required`,path:[`transactionId`]})}),te=D,O=r.object({partyA:w,identifierType:E,resultUrl:T,queueTimeOutUrl:T,remarks:r.string().optional()}),k=D,ne=r.object({transactionId:w,receiverParty:w,receiverIdentifierType:r.literal(`11`).optional(),amount:C,resultUrl:T,queueTimeOutUrl:T,remarks:r.string().optional(),occasion:r.string().optional()}).superRefine((e,t)=>{e.receiverIdentifierType!==void 0&&e.receiverIdentifierType!==`11`&&t.addIssue({code:`custom`,message:`receiverIdentifierType must be "11" for the Reversals API`,path:[`receiverIdentifierType`]});let n=e.remarks??`Transaction Reversal`;(n.length<2||n.length>100)&&t.addIssue({code:`custom`,message:`remarks must be between 2 and 100 characters`,path:[`remarks`]})}),re=D,ie=r.object({amount:C,partyA:w,partyB:r.string().optional(),accountReference:w,resultUrl:T,queueTimeOutUrl:T,remarks:r.string().optional()}),ae=D,oe=r.object({merchantName:w,refNo:w,amount:C,trxCode:r.enum([`BG`,`WA`,`PB`,`SM`,`SB`]),cpi:w,size:r.number().int().min(1).max(1e3).optional()}),se=r.object({ResponseCode:r.string(),RequestID:r.string().optional(),ResponseDescription:r.string(),QRCode:r.string().optional()}).passthrough();async function ce(e,t,n,r,i,a){let s=S(O,i,`Account Balance request`),c={Initiator:r,SecurityCredential:n,CommandID:`AccountBalance`,PartyA:String(s.partyA.trim()),IdentifierType:s.identifierType,ResultURL:s.resultUrl,QueueTimeOutURL:s.queueTimeOutUrl,Remarks:s.remarks??`Account Balance Query`},{data:l}=await u(`${e}/mpesa/accountbalance/v1/query`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:c},a));return S(k,l,`Account Balance response`)}function le(e){if(!e.trim())return[];let t=e.split(`|`),n=[];for(let e=0;e+2<t.length;e++){let r=t[e]?.trim(),i=t[e+1]?.trim(),a=t[e+2]?.trim();r&&i&&a!==void 0&&isNaN(Number(r))&&r.length>0&&n.push({name:r,currency:i,amount:a})}return n}function ue(e,t){let n=e.Result.ResultParameters?.ResultParameter;if(n)return(Array.isArray(n)?n:[n]).find(e=>e.Key===t)?.Value}function de(e){let t=ue(e,`AccountBalance`);return t==null?null:String(t)}function fe(e){let t=e.Result.ResultCode;return t===0||t===`0`}const A=r.object({ConversationID:r.string(),OriginatorConversationID:r.string(),ResponseCode:r.string(),ResponseDescription:r.string()}).passthrough(),j=r.object({amount:C,partyA:w,partyB:w,accountReference:w,requester:r.string().optional(),remarks:r.string().optional(),resultUrl:T,queueTimeOutUrl:T,occasion:r.string().optional()}),pe=j.extend({commandId:r.literal(`BusinessBuyGoods`)}),M=j.extend({commandId:r.literal(`BusinessPayBill`)}),N=A,P=A,F=r.object({primaryShortCode:w,receiverShortCode:w,amount:C,paymentRef:w,callbackUrl:T,partnerName:w,requestRefId:w.optional()}),I=r.object({code:r.string(),status:r.string()}).passthrough();r.object({ConversationID:r.string().optional(),OriginatorConversationID:r.string().optional(),ResponseCode:r.string(),ResponseDescription:r.string()}).passthrough();async function L(e,t,n,r){let i=S(F,n,`B2B Express Checkout request`),a=Math.round(i.amount),s={primaryShortCode:String(i.primaryShortCode),receiverShortCode:String(i.receiverShortCode),amount:String(a),paymentRef:i.paymentRef,callbackUrl:i.callbackUrl,partnerName:i.partnerName,RequestRefID:i.requestRefId??g()},{data:c}=await u(`${e}/v1/ussdpush/get-msisdn`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:s},r));return S(I,c,`B2B Express Checkout response`)}const R={SUCCESS:`0`,CANCELLED:`4001`,KYC_FAIL:`4102`,NO_NOMINATED_NUMBER:`4104`,USSD_NETWORK_ERROR:`4201`,USSD_EXCEPTION_ERROR:`4203`};new Set(Object.values(R));function z(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.resultCode==`string`&&typeof t.requestId==`string`&&typeof t.amount==`string`}function B(e){return e.resultCode===R.SUCCESS}function me(e){return e.resultCode===R.CANCELLED}function he(e){return Number(e.amount)}function ge(e){return B(e)?e.transactionId??null:null}function _e(e){return B(e)?e.conversationID??null:null}async function ve(e,t,n,r,i,a){let s=S(pe,i,`B2B Buy Goods request`),c=Math.round(s.amount),l={Initiator:r,SecurityCredential:n,CommandID:s.commandId,SenderIdentifierType:`4`,RecieverIdentifierType:`4`,Amount:String(c),PartyA:String(s.partyA),PartyB:String(s.partyB),AccountReference:s.accountReference.slice(0,13),Remarks:s.remarks??`Business Buy Goods`,QueueTimeOutURL:s.queueTimeOutUrl,ResultURL:s.resultUrl};s.requester?.trim()&&(l.Requester=String(s.requester)),s.occasion?.trim()&&(l.Occassion=s.occasion);let{data:d}=await u(`${e}/mpesa/b2b/v1/paymentrequest`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:l},a));return S(N,d,`B2B Buy Goods response`)}async function ye(e,t,n,r,i,a){let s=S(M,i,`B2B Pay Bill request`),c=Math.round(s.amount),l={Initiator:r,SecurityCredential:n,CommandID:s.commandId,SenderIdentifierType:`4`,RecieverIdentifierType:`4`,Amount:String(c),PartyA:String(s.partyA),PartyB:String(s.partyB),AccountReference:s.accountReference.slice(0,13),Remarks:s.remarks??`Business Pay Bill`,QueueTimeOutURL:s.queueTimeOutUrl,ResultURL:s.resultUrl};s.requester?.trim()&&(l.Requester=String(s.requester)),s.occasion?.trim()&&(l.Occassion=s.occasion);let{data:d}=await u(`${e}/mpesa/b2b/v1/paymentrequest`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:l},a));return S(P,d,`B2B Pay Bill response`)}const V=r.object({ConversationID:r.string(),OriginatorConversationID:r.string(),ResponseCode:r.string(),ResponseDescription:r.string()}).passthrough(),be=r.object({commandId:r.literal(`BusinessPayToBulk`),amount:C,partyA:w,partyB:w,accountReference:w,requester:r.string().optional(),remarks:r.string().optional(),resultUrl:T,queueTimeOutUrl:T}),xe=V,Se=r.object({commandId:r.enum([`BusinessPayment`,`SalaryPayment`,`PromotionPayment`]),amount:r.number().finite().positive(),partyA:w,partyB:w,remarks:w,queueTimeOutUrl:T,resultUrl:T,originatorConversationId:w.optional(),occasion:r.string().optional()}),Ce=V;async function we(e,t,n,r,i,a){let s=S(be,i,`B2C request`),c=Math.round(s.amount),l={Initiator:r,SecurityCredential:n,CommandID:s.commandId,SenderIdentifierType:`4`,RecieverIdentifierType:`4`,Amount:String(c),PartyA:String(s.partyA),PartyB:String(s.partyB),AccountReference:s.accountReference,Remarks:s.remarks??`B2C Account Top Up`,QueueTimeOutURL:s.queueTimeOutUrl,ResultURL:s.resultUrl};s.requester?.trim()&&(l.Requester=String(s.requester));let{data:d}=await u(`${e}/mpesa/b2b/v1/paymentrequest`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:l},a));return S(xe,d,`B2C response`)}function Te(e){if(!e||typeof e!=`object`)return!1;let t=e;if(!t.Result||typeof t.Result!=`object`)return!1;let n=t.Result;return(typeof n.ResultCode==`number`||typeof n.ResultCode==`string`)&&typeof n.ConversationID==`string`&&typeof n.OriginatorConversationID==`string`}function Ee(e){let t=e.Result.ResultCode;return t===0||t===`0`}function De(e){return e.Result.TransactionID??null}function Oe(e){return e.Result.OriginatorConversationID}function ke(e){let t=Ae(e,`Amount`);if(t===void 0)return null;let n=Number(t);return Number.isFinite(n)?n:null}function Ae(e,t){let n=e.Result.ResultParameters?.ResultParameter;if(n)return(Array.isArray(n)?n:[n]).find(e=>e.Key===t)?.Value}const je=new Set([`BusinessPayment`,`SalaryPayment`,`PromotionPayment`]);async function Me(e,t,n,r,i,s){let c=i.originatorConversationId?.trim()||h(),l=S(Se,{...i,originatorConversationId:c},`B2C Disbursement request`);if(!l.commandId||!je.has(l.commandId))throw a({code:`VALIDATION_ERROR`,message:`commandId must be one of: BusinessPayment, SalaryPayment, PromotionPayment. Got "${l.commandId}".`});let d=Math.round(l.amount);if(!Number.isFinite(d)||d<10)throw a({code:`VALIDATION_ERROR`,message:`amount must be ≥ 10 KES (got ${l.amount} which rounds to ${d}).`});if(!l.partyA?.trim())throw a({code:`VALIDATION_ERROR`,message:`partyA is required — the sending organisation shortcode.`});if(!l.partyB?.trim())throw a({code:`VALIDATION_ERROR`,message:`partyB is required — the receiving customer MSISDN (2547XXXXXXXX).`});if(!l.remarks?.trim())throw a({code:`VALIDATION_ERROR`,message:`remarks is required (2–100 characters).`});if(!l.resultUrl?.trim())throw a({code:`VALIDATION_ERROR`,message:`resultUrl is required — Safaricom POSTs the async result here.`});if(!l.queueTimeOutUrl?.trim())throw a({code:`VALIDATION_ERROR`,message:`queueTimeOutUrl is required — Safaricom calls this on request timeout.`});let f={OriginatorConversationID:c,InitiatorName:r,SecurityCredential:n,CommandID:l.commandId,Amount:d,PartyA:String(l.partyA),PartyB:String(l.partyB),Remarks:l.remarks,QueueTimeOutURL:l.queueTimeOutUrl,ResultURL:l.resultUrl};l.occasion?.trim()&&(f.Occassion=l.occasion);let{data:p}=await u(`${e}/mpesa/b2c/v3/paymentrequest`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:f},s));return S(Ce,p,`B2C Disbursement response`)}function Ne(e){if(!e||typeof e!=`object`)return!1;let t=e;if(!t.Result||typeof t.Result!=`object`)return!1;let n=t.Result;return(typeof n.ResultCode==`number`||typeof n.ResultCode==`string`)&&typeof n.ConversationID==`string`&&typeof n.OriginatorConversationID==`string`}function Pe(e){let t=e.Result.ResultCode;return t===0||t===`0`}const Fe=r.enum([`0`,`1`]),H=r.object({shortcode:w,email:w,officialContact:w,sendReminders:Fe,logo:r.string().optional(),callbackUrl:T}),Ie=r.object({app_key:r.string().optional(),resmsg:r.string(),rescode:r.string()}).passthrough(),Le=H,Re=r.object({resmsg:r.string(),rescode:r.string()}).passthrough(),ze=r.object({itemName:w,amount:C}),U=r.object({externalReference:w,billedFullName:w,billedPhoneNumber:w,billedPeriod:w,invoiceName:w,dueDate:w,accountReference:w,amount:C,invoiceItems:r.array(ze).optional()}),Be=r.object({Status_Message:r.string().optional(),resmsg:r.string(),rescode:r.string()}).passthrough(),Ve=r.object({invoices:r.array(U).min(1).max(1e3)}),He=r.object({Status_Message:r.string().optional(),resmsg:r.string(),rescode:r.string()}).passthrough(),Ue=r.object({externalReference:w}),We=r.object({Status_Message:r.string().optional(),resmsg:r.string(),rescode:r.string(),errors:r.array(r.unknown()).optional()}).passthrough(),Ge=r.object({externalReferences:r.array(w).min(1)}),Ke=r.object({Status_Message:r.string().optional(),resmsg:r.string(),rescode:r.string(),errors:r.array(r.unknown()).optional()}).passthrough(),qe=r.object({paymentDate:w,paidAmount:w,accountReference:w,transactionId:w,phoneNumber:w,fullName:w,invoiceName:w,externalReference:w}),Je=r.object({resmsg:r.string(),rescode:r.string()}).passthrough();async function Ye(e,t,n,r){let i=S(H,n,`Bill Manager opt-in request`),a={shortcode:i.shortcode,email:i.email,officialContact:i.officialContact,sendReminders:i.sendReminders,logo:i.logo??``,callbackurl:i.callbackUrl},{data:s}=await u(`${e}/v1/billmanager-invoice/optin`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:a},r));return S(Ie,s,`Bill Manager opt-in response`)}async function Xe(e,t,n,r){let i=S(Le,n,`Bill Manager update opt-in request`),a={shortcode:i.shortcode,email:i.email,officialContact:i.officialContact,sendReminders:i.sendReminders,logo:i.logo??``,callbackurl:i.callbackUrl},{data:s}=await u(`${e}/v1/billmanager-invoice/change-optin-details`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:a},r));return S(Re,s,`Bill Manager update opt-in response`)}async function Ze(e,t,n,r){let i=S(U,n,`Bill Manager single invoice request`),a=Math.round(i.amount),s={externalReference:i.externalReference,billedFullName:i.billedFullName,billedPhoneNumber:i.billedPhoneNumber,billedPeriod:i.billedPeriod,invoiceName:i.invoiceName,dueDate:i.dueDate,accountReference:i.accountReference,amount:String(a),invoiceItems:i.invoiceItems?.map(e=>({itemName:e.itemName,amount:String(Math.round(e.amount))}))??[]},{data:c}=await u(`${e}/v1/billmanager-invoice/single-invoicing`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:s},r));return S(Be,c,`Bill Manager single invoice response`)}async function Qe(e,t,n,r){let i=S(Ve,n,`Bill Manager bulk invoice request`).invoices.map(e=>({externalReference:e.externalReference,billedFullName:e.billedFullName,billedPhoneNumber:e.billedPhoneNumber,billedPeriod:e.billedPeriod,invoiceName:e.invoiceName,dueDate:e.dueDate,accountReference:e.accountReference,amount:String(Math.round(e.amount)),invoiceItems:e.invoiceItems?.map(e=>({itemName:e.itemName,amount:String(Math.round(e.amount))}))??[]})),{data:a}=await u(`${e}/v1/billmanager-invoice/bulk-invoicing`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:i},r));return S(He,a,`Bill Manager bulk invoice response`)}async function $e(e,t,n,r){let i=S(Ue,n,`Bill Manager cancel invoice request`),{data:a}=await u(`${e}/v1/billmanager-invoice/cancel-single-invoice`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:{externalReference:i.externalReference}},r));return S(We,a,`Bill Manager cancel invoice response`)}async function et(e,t,n,r){let i=S(Ge,n,`Bill Manager cancel bulk invoices request`).externalReferences.map(e=>({externalReference:e})),{data:a}=await u(`${e}/v1/billmanager-invoice/cancel-bulk-invoices`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:i},r));return S(Ke,a,`Bill Manager cancel bulk invoices response`)}async function tt(e,t,n,r){let i=S(qe,n,`Bill Manager reconciliation request`),a={paymentDate:i.paymentDate,paidAmount:i.paidAmount,accountReference:i.accountReference,transactionId:i.transactionId,phoneNumber:i.phoneNumber,fullName:i.fullName,invoiceName:i.invoiceName,externalReference:i.externalReference},{data:s}=await u(`${e}/v1/billmanager-invoice/reconciliation`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:a},r));return S(Je,s,`Bill Manager reconciliation response`)}const nt=r.object({shortCode:w,responseType:r.enum([`Completed`,`Cancelled`]),confirmationUrl:T,validationUrl:T,apiVersion:r.enum([`v1`,`v2`]).optional()}),W=r.object({OriginatorCoversationID:r.string(),ResponseCode:r.string(),ResponseDescription:r.string()}).passthrough(),rt=W,it=W,at=r.object({shortCode:r.union([w,r.number()]),commandId:r.enum([`CustomerPayBillOnline`,`CustomerBuyGoodsOnline`]),amount:C,msisdn:r.union([w,r.number()]),billRefNumber:r.union([w,r.null()]).optional(),apiVersion:r.enum([`v1`,`v2`]).optional()}).superRefine((e,t)=>{e.commandId===`CustomerPayBillOnline`&&!e.billRefNumber?.trim()&&t.addIssue({code:`custom`,message:`billRefNumber is required for CustomerPayBillOnline`,path:[`billRefNumber`]})});r.object({TransactionType:r.string(),TransID:r.string(),TransTime:r.string(),TransAmount:r.union([r.string(),r.number()]),BusinessShortCode:r.string(),BillRefNumber:r.string().optional(),MSISDN:r.string()}).passthrough();const ot=[`mpesa`,`safaricom`,`exec`,`exe`,`cme`,`cmd`,`sql`,`query`];function G(e,t){if(!e||!e.trim())throw a({code:`VALIDATION_ERROR`,message:`${t} is required`});let n=e.toLowerCase();for(let e of ot)if(n.includes(e))throw a({code:`VALIDATION_ERROR`,message:`${t} must not contain the keyword "${e}". Daraja rejects URLs containing: mpesa, safaricom, exe, exec, cme (and variants: cmd, sql, query).`})}async function st(e,t,n,r){let i=S(nt,n,`C2B Register URL request`);G(i.confirmationUrl,`confirmationUrl`),G(i.validationUrl,`validationUrl`);let a=i.apiVersion??`v2`,s={ShortCode:String(i.shortCode),ResponseType:i.responseType,ConfirmationURL:i.confirmationUrl,ValidationURL:i.validationUrl},{data:c}=await u(`${e}/mpesa/c2b/${a}/registerurl`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:s},r));return S(rt,c,`C2B Register URL response`)}async function ct(e,t,n,r){let i=S(at,n,`C2B Simulate request`);if(!e.includes(`sandbox`))throw a({code:`VALIDATION_ERROR`,message:`C2B simulate is only available in the Sandbox environment (per Daraja docs). In production, customers initiate payments directly via M-PESA App, USSD, or SIM Toolkit.`});let s=Math.round(i.amount),c=i.commandId===`CustomerBuyGoodsOnline`,l=i.apiVersion??`v2`,d={ShortCode:Number(i.shortCode),CommandID:i.commandId,Amount:s,Msisdn:Number(i.msisdn)};c||(d.BillRefNumber=i.billRefNumber.trim());let{data:f}=await u(`${e}/mpesa/c2b/${l}/simulate`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:d},r));return S(it,f,`C2B Simulate response`)}function lt(e){return{ResultCode:`0`,ResultDesc:`Accepted`,...e?{ThirdPartyTransID:e}:{}}}function ut(e,t){switch(e){case`404.001.04`:return new i({code:`AUTH_FAILED`,message:`Daraja rejected the request due to an invalid authentication header. Ensure the Dynamic QR endpoint is called with POST and that the Authorization: Bearer <token> header is present. Daraja: "${t}"`,statusCode:404});case`400.003.01`:return new i({code:`AUTH_FAILED`,message:`The M-PESA access token is invalid or has expired. Call clearTokenCache() on the Mpesa instance to force a token refresh and retry the request. Daraja: "${t}"`,statusCode:401});case`400.002.05`:return new i({code:`VALIDATION_ERROR`,message:`Daraja rejected the request payload as malformed. Verify that all required fields (MerchantName, RefNo, Amount, TrxCode, CPI, Size) are present and have correct types. Daraja: "${t}"`,statusCode:400});default:return new i({code:`REQUEST_FAILED`,message:`Dynamic QR request failed (${e}): ${t}`,statusCode:400})}}function dt(e){return typeof e==`object`&&!!e&&`errorCode`in e&&typeof e.errorCode==`string`}function ft(e){return typeof e==`object`&&!!e&&`ResponseCode`in e&&`QRCode`in e&&typeof e.QRCode==`string`&&e.QRCode.length>0}async function pt(e,t,n,r){let a=S(oe,n,`Dynamic QR request`);if(!t||typeof t!=`string`||t.trim().length===0)throw new i({code:`AUTH_FAILED`,message:`accessToken is required. Obtain one via the Daraja Authorization API (GET /oauth/v1/generate?grant_type=client_credentials).`});let s=a.size??300,c=Math.round(a.amount),l={MerchantName:a.merchantName.trim(),RefNo:a.refNo.trim(),Amount:c,TrxCode:a.trxCode,CPI:a.cpi.trim(),Size:String(s)},{data:d}=await u(`${e}/mpesa/qrcode/v1/generate`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:l},r));if(dt(d))throw ut(d.errorCode,d.errorMessage);if(!ft(d))throw new i({code:`REQUEST_FAILED`,message:`Daraja returned an unexpected response structure for the Dynamic QR request. The response was missing required fields (ResponseCode, QRCode). Raw response: ${JSON.stringify(d).slice(0,300)}`});return S(se,d,`Dynamic QR response`)}const mt={SUCCESS:0,INSUFFICIENT_BALANCE:1,DEBIT_PARTY_INVALID_STATE:11,INITIATOR_NOT_ALLOWED:21,INITIATOR_INFORMATION_INVALID:2001,DECLINED_ACCOUNT_RULE:2006,NOT_PERMITTED:2028,SECURITY_CREDENTIAL_LOCKED:8006,ALREADY_REVERSED:`R000001`,INVALID_TRANSACTION_ID:`R000002`};function ht(e){if(!e||typeof e!=`object`)return!1;let t=e;if(!t.Result||typeof t.Result!=`object`)return!1;let n=t.Result;return n.ResultCode!==void 0&&typeof n.ResultDesc==`string`&&typeof n.ConversationID==`string`}function gt(e){return e.Result.ResultCode===mt.SUCCESS}function _t(e){return e.Result.TransactionID??null}async function vt(e,t,n,r,i,a){let s=S(ne,i,`Reversal request`),c=Math.round(s.amount),l=s.remarks??`Transaction Reversal`,d={Initiator:r,SecurityCredential:n,CommandID:`TransactionReversal`,TransactionID:s.transactionId,Amount:String(c),ReceiverParty:String(s.receiverParty),RecieverIdentifierType:`11`,ResultURL:s.resultUrl,QueueTimeOutURL:s.queueTimeOutUrl,Remarks:l};s.occasion!==void 0&&s.occasion!==null&&(d.Occasion=s.occasion);let{data:f}=await u(`${e}/mpesa/reversal/v1/request`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:d},a));return S(re,f,`Reversal response`)}const yt=r.enum([`CustomerPayBillOnline`,`CustomerBuyGoodsOnline`]),bt=r.object({amount:r.number().finite({message:`amount must be a finite number (not NaN or Infinity)`}),phoneNumber:w,shortCode:w,passKey:w,callbackUrl:T,accountReference:w,transactionDesc:w,transactionType:yt.optional(),partyB:r.string().optional()}),xt=r.object({MerchantRequestID:r.string(),CheckoutRequestID:r.string(),ResponseCode:r.string(),ResponseDescription:r.string(),CustomerMessage:r.string().optional()}).passthrough(),St=r.object({checkoutRequestId:w,shortCode:w,passKey:w}),Ct=r.object({ResponseCode:r.string(),ResponseDescription:r.string(),MerchantRequestID:r.string().optional(),CheckoutRequestID:r.string().optional(),ResultCode:r.union([r.string(),r.number()]).optional(),ResultDesc:r.string().optional()}).passthrough();r.object({Body:r.object({stkCallback:r.object({MerchantRequestID:r.string(),CheckoutRequestID:r.string(),ResultCode:r.number(),ResultDesc:r.string(),CallbackMetadata:r.object({Item:r.array(r.object({Name:r.string(),Value:r.union([r.string(),r.number()])}))}).optional()}).passthrough()})});const K={MIN_AMOUNT:1,MAX_AMOUNT:25e4};function q(e){let t=e.replace(/\D/g,``),n;if(t.startsWith(`254`)&&t.length===12)n=t;else if(t.startsWith(`0`)&&t.length===10)n=`254${t.slice(1)}`;else if(t.length===9)n=`254${t}`;else throw new i({code:`INVALID_PHONE`,message:`Cannot parse "${e}". Use 07XXXXXXXX, 2547XXXXXXXX, 2541XXXXXXXX (Airtel), or +2547XXXXXXXX.`});if(n.length!==12)throw new i({code:`INVALID_PHONE`,message:`"${e}" normalised to "${n}" — expected 12 digits.`});return n}function J(e,t,n){return btoa(`${e}${t}${n}`)}function Y(){let e=new Date,t=e=>e.toString().padStart(2,`0`);return[e.getFullYear(),t(e.getMonth()+1),t(e.getDate()),t(e.getHours()),t(e.getMinutes()),t(e.getSeconds())].join(``)}async function wt(e,t,n,r){let a=S(bt,n,`STK Push request`);if(!Number.isFinite(a.amount))throw new i({code:`VALIDATION_ERROR`,message:`amount must be a finite number (got ${a.amount}).`});let s=Math.round(a.amount);if(s<K.MIN_AMOUNT)throw new i({code:`VALIDATION_ERROR`,message:`Amount must be at least KES ${K.MIN_AMOUNT} (got ${a.amount} which rounds to ${s}).`});if(s>K.MAX_AMOUNT)throw new i({code:`VALIDATION_ERROR`,message:`Amount must not exceed KES ${K.MAX_AMOUNT.toLocaleString()} per transaction as per Safaricom Daraja limits (got ${a.amount} which rounds to ${s}).`});let c=Y(),l=a.partyB??a.shortCode,d={BusinessShortCode:a.shortCode,Password:J(a.shortCode,a.passKey,c),Timestamp:c,TransactionType:a.transactionType??`CustomerPayBillOnline`,Amount:s,PartyA:q(a.phoneNumber),PartyB:l,PhoneNumber:q(a.phoneNumber),CallBackURL:a.callbackUrl,AccountReference:a.accountReference.slice(0,12),TransactionDesc:a.transactionDesc.slice(0,13)},{data:f}=await u(`${e}/mpesa/stkpush/v1/processrequest`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:d,retries:5,retryDelay:3e3},r));return S(xt,f,`STK Push response`)}async function Tt(e,t,n,r){let i=S(St,n,`STK Query request`),a=Y(),s={BusinessShortCode:i.shortCode,Password:J(i.shortCode,i.passKey,a),Timestamp:a,CheckoutRequestID:i.checkoutRequestId},{data:c}=await u(`${e}/mpesa/stkpushquery/v1/query`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:s},r));return S(Ct,c,`STK Query response`)}async function Et(e,t,n,r,i,a){let s=S(ie,i,`Tax Remittance request`),c=Math.round(s.amount),l={Initiator:r,SecurityCredential:n,CommandID:`PayTaxToKRA`,SenderIdentifierType:`4`,RecieverIdentifierType:`4`,Amount:String(c),PartyA:String(s.partyA),PartyB:s.partyB??`572572`,AccountReference:s.accountReference,Remarks:s.remarks??`Tax Remittance`,QueueTimeOutURL:s.queueTimeOutUrl,ResultURL:s.resultUrl},{data:d}=await u(`${e}/mpesa/b2b/v1/remittax`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:l},a));return S(ae,d,`Tax Remittance response`)}function X(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Dt(e){return typeof e==`string`?Number(e):e}function Ot(e){if(!X(e))return!1;let t=e;if(!X(t.Result))return!1;let n=t.Result;return n.ResultCode!==void 0&&n.ResultCode!==null&&typeof n.ConversationID==`string`&&typeof n.OriginatorConversationID==`string`}function kt(e){return Dt(e.Result.ResultCode)===0}async function At(e,t,n,r,i,a){let s=S(ee,i,`Transaction Status request`),c={Initiator:r,SecurityCredential:n,CommandID:s.commandId??`TransactionStatusQuery`,TransactionID:s.transactionId??``,OriginalConversationID:s.originalConversationId??``,PartyA:s.partyA,IdentifierType:s.identifierType,ResultURL:s.resultUrl,QueueTimeOutURL:s.queueTimeOutUrl,Remarks:s.remarks??`Transaction Status Query`,Occasion:s.occasion??``},{data:l}=await u(`${e}/mpesa/transactionstatus/v1/query`,o({method:`POST`,headers:{Authorization:`Bearer ${t}`},body:c},a));return S(te,l,`Transaction Status response`)}new Set(Object.values({SUCCESS:0,INVALID_INITIATOR:2001}));function jt(e){if(!e||typeof e!=`object`)return!1;let t=e;if(!t.Result||typeof t.Result!=`object`)return!1;let n=t.Result;return(typeof n.ResultCode==`number`||typeof n.ResultCode==`string`)&&typeof n.ConversationID==`string`&&typeof n.OriginatorConversationID==`string`}function Mt(e){let t=e.Result.ResultCode;return t===0||t===`0`}const Nt={sandbox:`https://sandbox.safaricom.co.ke`,production:`https://api.safaricom.co.ke`},Pt={sha256:`SHA-256`,sha512:`SHA-512`};function Z(e){let t=e.trim();if(!/^[0-9a-fA-F]+$/.test(t)||t.length%2!=0)return null;let n=new Uint8Array(t.length/2);for(let e=0;e<n.length;e++)n[e]=Number.parseInt(t.slice(e*2,e*2+2),16);return n}function Q(e){return[...new Uint8Array(e)].map(e=>e.toString(16).padStart(2,`0`)).join(``)}function Ft(e,t){if(e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r++)n|=e[r]^t[r];return n===0}async function It(e,t,n,r=`sha256`){if(!n||!t)return!1;let i=globalThis.crypto?.subtle;if(!i)return!1;let a=typeof e==`string`?new TextEncoder().encode(e):e instanceof Uint8Array?e:new Uint8Array(e),o=Z(t);if(!o)return!1;try{let e=await i.importKey(`raw`,new TextEncoder().encode(n),{name:`HMAC`,hash:Pt[r]},!1,[`sign`]),t=Z(Q(await i.sign(`HMAC`,e,a)));return t?Ft(o,t):!1}catch{return!1}}const $=[`196.201.214.200`,`196.201.214.206`,`196.201.213.114`,`196.201.214.207`,`196.201.214.208`,`196.201.213.44`,`196.201.212.127`,`196.201.212.138`,`196.201.212.129`,`196.201.212.136`,`196.201.212.74`,`196.201.212.69`];function Lt(e,t=$){return t.includes(e)}async function Rt(e){let t=[],n=e.allowedIPs??$,r=e.skipIPCheck===!0||Lt(e.requestIP,n);r||t.push(`Request IP is not in the Safaricom allowlist.`);let i=!0;return e.secret&&e.signature&&e.rawBody!==void 0?(i=await It(e.rawBody,e.signature,e.secret,e.hmacAlgorithm),i||t.push(`Webhook HMAC signature verification failed.`)):e.requireHMAC&&(i=!1,t.push(`HMAC verification required but secret, signature, or rawBody missing.`)),{valid:r&&i,ipValid:r,hmacValid:i,errors:t}}function zt(e){let t=(e.Body?.stkCallback?.CallbackMetadata?.Item)?.find(e=>e.Name===`MpesaReceiptNumber`);return t?String(t.Value):null}function Bt(e){let t=(e.Body?.stkCallback?.CallbackMetadata?.Item)?.find(e=>e.Name===`Amount`);return t?Number(t.Value):null}function Vt(e){let t=(e.Body?.stkCallback?.CallbackMetadata?.Item)?.find(e=>e.Name===`PhoneNumber`);return t?String(t.Value):null}function Ht(e){return e.Body?.stkCallback?.ResultCode===0}var Ut=class{config;tokenManager;baseUrl;idempotencyManager;constructor(e){if(!e.consumerKey||!e.consumerSecret)throw new i({code:`INVALID_CREDENTIALS`,message:`consumerKey and consumerSecret are required.`});this.config=e,this.baseUrl=Nt[e.environment],this.tokenManager=new f(e.consumerKey,e.consumerSecret,this.baseUrl),this.idempotencyManager=new v(e.idempotency)}darajaHttp(){return{idempotency:this.idempotencyManager}}getToken(){return this.tokenManager.getAccessToken()}async buildSecurityCredential(){if(this.config.securityCredential)return this.config.securityCredential;if(!this.config.initiatorPassword)throw new i({code:`INVALID_CREDENTIALS`,message:`Provide securityCredential (pre-encrypted) OR (initiatorPassword + certificatePath/certificatePem).`});let t;if(this.config.certificatePem)t=this.config.certificatePem;else if(this.config.certificatePath)t=await e(this.config.certificatePath,`utf-8`);else throw new i({code:`INVALID_CREDENTIALS`,message:`certificatePath or certificatePem is required to encrypt the initiator password.`});return p(this.config.initiatorPassword,t)}requireInitiator(e){let t=this.config.initiatorName??``;if(!t)throw new i({code:`VALIDATION_ERROR`,message:`initiatorName is required for ${e}.`});return t}async stkPushSafe(e){try{return y(await this.stkPush(e))}catch(e){return b(e)}}async accountBalanceSafe(e){try{return y(await this.accountBalance(e))}catch(e){return b(e)}}async stkPush(e){let t=this.config.lipaNaMpesaShortCode??``,n=this.config.lipaNaMpesaPassKey??``;if(!t||!n)throw new i({code:`VALIDATION_ERROR`,message:`lipaNaMpesaShortCode and lipaNaMpesaPassKey are required for STK Push.`});let r=await this.getToken();return wt(this.baseUrl,r,{...e,shortCode:t,passKey:n},this.darajaHttp())}async stkQuery(e){let t=this.config.lipaNaMpesaShortCode??``,n=this.config.lipaNaMpesaPassKey??``;if(!t||!n)throw new i({code:`VALIDATION_ERROR`,message:`lipaNaMpesaShortCode and lipaNaMpesaPassKey are required for STK Query.`});let r=await this.getToken();return Tt(this.baseUrl,r,{...e,shortCode:t,passKey:n},this.darajaHttp())}async transactionStatus(e){let t=this.requireInitiator(`Transaction Status`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return At(this.baseUrl,n,r,t,e,this.darajaHttp())}async accountBalance(e){let t=this.requireInitiator(`Account Balance`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return ce(this.baseUrl,n,r,t,e,this.darajaHttp())}async reverseTransaction(e){let t=this.requireInitiator(`Reversal`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return vt(this.baseUrl,n,r,t,e,this.darajaHttp())}async generateDynamicQR(e){let t=await this.getToken();return pt(this.baseUrl,t,e,this.darajaHttp())}async registerC2BUrls(e){let t=await this.getToken();return st(this.baseUrl,t,e,this.darajaHttp())}async simulateC2B(e){let t=await this.getToken();return ct(this.baseUrl,t,e,this.darajaHttp())}async remitTax(e){let t=this.requireInitiator(`Tax Remittance`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return Et(this.baseUrl,n,r,t,e,this.darajaHttp())}async b2bExpressCheckout(e){let t=await this.getToken();return L(this.baseUrl,t,e,this.darajaHttp())}async b2bBuyGoods(e){let t=this.requireInitiator(`B2B Buy Goods`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return ve(this.baseUrl,n,r,t,e,this.darajaHttp())}async b2bPayBill(e){let t=this.requireInitiator(`B2B Pay Bill`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return ye(this.baseUrl,n,r,t,e,this.darajaHttp())}async b2cPayment(e){let t=this.requireInitiator(`B2C Payment`),[n,r]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return we(this.baseUrl,n,r,t,e,this.darajaHttp())}async b2cDisbursement(e){let t=this.requireInitiator(`B2C Disbursement`),n={...e,originatorConversationId:e.originatorConversationId??h()},[r,i]=await Promise.all([this.getToken(),this.buildSecurityCredential()]);return Me(this.baseUrl,r,i,t,n,this.darajaHttp())}async billManagerOptIn(e){let t=await this.getToken();return Ye(this.baseUrl,t,e,this.darajaHttp())}async updateOptIn(e){let t=await this.getToken();return Xe(this.baseUrl,t,e,this.darajaHttp())}async sendInvoice(e){let t=await this.getToken();return Ze(this.baseUrl,t,e,this.darajaHttp())}async sendBulkInvoices(e){let t=await this.getToken();return Qe(this.baseUrl,t,e,this.darajaHttp())}async cancelInvoice(e){let t=await this.getToken();return $e(this.baseUrl,t,e,this.darajaHttp())}async cancelBulkInvoices(e){let t=await this.getToken();return et(this.baseUrl,t,e,this.darajaHttp())}async reconcilePayment(e){let t=await this.getToken();return tt(this.baseUrl,t,e,this.darajaHttp())}clearTokenCache(){this.tokenManager.clearCache()}get environment(){return this.config.environment}};async function Wt(e,t,n,r){let i=r.signatureHeader??`x-safaricom-signature`,a=n(i)??n(i.toLowerCase())??n(i.toUpperCase()),o=await Rt({requestIP:e,...r.skipIPCheck===void 0?{}:{skipIPCheck:r.skipIPCheck},...r.webhookSecret===void 0?{}:{secret:r.webhookSecret},...a===void 0?{}:{signature:a},...t===void 0?{}:{rawBody:t},...r.requireHMAC===void 0?{}:{requireHMAC:r.requireHMAC}});return o.valid||console.warn(`[pesafy] Webhook verification failed:`,o.errors.join(`; `)),o.valid}export{le as A,_e as C,B as D,me as E,de as O,he as S,z as T,ke as _,zt as a,Te as b,Mt as c,_t as d,ht as f,Pe as g,Ne as h,Vt as i,i as j,fe as k,Ot as l,lt as m,Ut as n,Ht as o,gt as p,Bt as r,jt as s,Wt as t,kt as u,Oe as v,ge as w,Ee as x,De as y};
package/package.json ADDED
@@ -0,0 +1,213 @@
1
+ {
2
+ "name": "pesafy",
3
+ "version": "0.0.2",
4
+ "private": false,
5
+ "description": "Type-safe M-PESA Daraja SDK for Node.js, Bun, Deno, Cloudflare Workers, and all JS frameworks",
6
+ "keywords": [
7
+ "africa",
8
+ "b2b",
9
+ "b2c",
10
+ "c2b",
11
+ "daraja",
12
+ "express",
13
+ "fastify",
14
+ "fintech",
15
+ "gateway",
16
+ "hono",
17
+ "kenya",
18
+ "kra",
19
+ "mpesa",
20
+ "nextjs",
21
+ "payment",
22
+ "pesafy",
23
+ "safaricom",
24
+ "stk-push",
25
+ "tax-remittance",
26
+ "typescript"
27
+ ],
28
+ "homepage": "https://pesafy.vercel.app",
29
+ "bugs": {
30
+ "url": "https://github.com/levos-snr/pesafy/issues"
31
+ },
32
+ "license": "MIT",
33
+ "author": {
34
+ "name": "Lewis Odero",
35
+ "email": "lewisodero27@gmail.com"
36
+ },
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/levos-snr/pesafy.git"
40
+ },
41
+ "type": "module",
42
+ "types": "./dist/index.d.ts",
43
+ "bin": {
44
+ "pesafy": "./dist/cli.mjs"
45
+ },
46
+ "exports": {
47
+ ".": {
48
+ "types": "./dist/index.d.ts",
49
+ "default": "./dist/index.js"
50
+ },
51
+ "./adapters/express": {
52
+ "types": "./dist/adapters/express.d.ts",
53
+ "default": "./dist/adapters/express.js"
54
+ },
55
+ "./adapters/hono": {
56
+ "types": "./dist/adapters/hono.d.ts",
57
+ "default": "./dist/adapters/hono.js"
58
+ },
59
+ "./adapters/nextjs": {
60
+ "types": "./dist/adapters/nextjs.d.ts",
61
+ "default": "./dist/adapters/nextjs.js"
62
+ },
63
+ "./adapters/fastify": {
64
+ "types": "./dist/adapters/fastify.d.ts",
65
+ "default": "./dist/adapters/fastify.js"
66
+ },
67
+ "./react": {
68
+ "types": "./dist/react/index.d.ts",
69
+ "default": "./dist/react/index.js"
70
+ },
71
+ "./cli": {
72
+ "default": "./dist/cli.mjs"
73
+ },
74
+ "./package.json": "./package.json"
75
+ },
76
+ "files": [
77
+ "dist",
78
+ "README.md",
79
+ "CHANGELOG.md",
80
+ "LICENSE"
81
+ ],
82
+ "sideEffects": false,
83
+ "engines": {
84
+ "node": ">=18.0.0",
85
+ "pnpm": ">=9.0.0"
86
+ },
87
+ "publishConfig": {
88
+ "access": "public",
89
+ "registry": "https://registry.npmjs.org",
90
+ "provenance": true
91
+ },
92
+ "size-limit": [
93
+ {
94
+ "name": "Core (index)",
95
+ "path": "dist/index.js",
96
+ "limit": "55 kB"
97
+ },
98
+ {
99
+ "name": "Adapter: Express",
100
+ "path": "dist/adapters/express.js",
101
+ "limit": "15 kB"
102
+ },
103
+ {
104
+ "name": "Adapter: Hono",
105
+ "path": "dist/adapters/hono.js",
106
+ "limit": "5 kB"
107
+ },
108
+ {
109
+ "name": "Adapter: Next.js",
110
+ "path": "dist/adapters/nextjs.js",
111
+ "limit": "5 kB"
112
+ },
113
+ {
114
+ "name": "Adapter: Fastify",
115
+ "path": "dist/adapters/fastify.js",
116
+ "limit": "5 kB"
117
+ },
118
+ {
119
+ "name": "React",
120
+ "path": "dist/react/index.js",
121
+ "limit": "1 kB"
122
+ }
123
+ ],
124
+ "simple-git-hooks": {
125
+ "pre-commit": "pnpm lint-staged"
126
+ },
127
+ "lint-staged": {
128
+ "*.{ts,tsx}": [
129
+ "oxlint",
130
+ "prettier --write"
131
+ ],
132
+ "*.{json,md,yml,yaml}": [
133
+ "prettier --write"
134
+ ]
135
+ },
136
+ "devDependencies": {
137
+ "@changesets/cli": "^2.29.8",
138
+ "@types/express": "^5.0.6",
139
+ "@types/react": "^19.2.14",
140
+ "@vitest/coverage-v8": "^4.1.2",
141
+ "express": "^5.2.1",
142
+ "fastify-plugin": "^5.1.0",
143
+ "hono": "^4.4.0",
144
+ "lint-staged": "^16.4.0",
145
+ "oxlint": "^1.39.0",
146
+ "prettier": "^3.5.3",
147
+ "publint": "^0.3.12",
148
+ "simple-git-hooks": "^2.13.0",
149
+ "size-limit": "^12.0.1",
150
+ "size-limit-preset-node-lib": "^0.4.0",
151
+ "tsdown": "^0.21.7",
152
+ "typescript": "^6.0.2",
153
+ "vitepress": "2.0.0-alpha.17",
154
+ "vitest": "^4.1.2",
155
+ "vue": "^3.5.31"
156
+ },
157
+ "peerDependencies": {
158
+ "express": ">=4.0.0",
159
+ "fastify": ">=4.0.0",
160
+ "hono": ">=4.0.0",
161
+ "react": ">=18.0.0",
162
+ "typescript": "^5",
163
+ "vue": ">=3.0.0"
164
+ },
165
+ "peerDependenciesMeta": {
166
+ "express": {
167
+ "optional": true
168
+ },
169
+ "fastify": {
170
+ "optional": true
171
+ },
172
+ "hono": {
173
+ "optional": true
174
+ },
175
+ "react": {
176
+ "optional": true
177
+ },
178
+ "vue": {
179
+ "optional": true
180
+ }
181
+ },
182
+ "workspaces": {
183
+ "packages": [
184
+ "."
185
+ ]
186
+ },
187
+ "dependencies": {
188
+ "zod": "^3.25.76"
189
+ },
190
+ "scripts": {
191
+ "build": "tsdown",
192
+ "build:watch": "tsdown --watch",
193
+ "typecheck": "tsc --noEmit",
194
+ "test": "vitest run",
195
+ "test:watch": "vitest",
196
+ "test:coverage": "vitest run --coverage",
197
+ "lint": "oxlint src",
198
+ "lint:fix": "oxlint src --fix",
199
+ "format": "prettier --write .",
200
+ "format:check": "prettier --check .",
201
+ "changeset": "changeset",
202
+ "version-bump": "changeset version",
203
+ "release": "changeset publish --access public",
204
+ "cli": "node dist/cli.mjs",
205
+ "docs:dev": "vitepress dev docs",
206
+ "docs:build": "vitepress build docs",
207
+ "docs:preview": "vitepress preview docs",
208
+ "size-limit": "size-limit",
209
+ "size": "pnpm build && size-limit",
210
+ "size:why": "pnpm build && size-limit --why",
211
+ "check:all": "pnpm lint && pnpm format:check && pnpm typecheck && pnpm test:coverage"
212
+ }
213
+ }