meta-cloud-api 3.8.0 → 3.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -10
- package/dist/index.d.mts +656 -238
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +7 -5
- package/dist/index.mjs.map +1 -1
- package/dist/node/chunk.mjs +1 -0
- package/dist/node/index.d.mts +10398 -0
- package/dist/node/index.d.mts.map +1 -0
- package/dist/node/index.mjs +23 -0
- package/dist/node/index.mjs.map +1 -0
- package/dist/testing/index.d.ts +377 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +4 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/node/index.js +3 -0
- package/dist/types/index.d.ts +210 -7
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +264 -4
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +6 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/node/index.d.ts +682 -0
- package/dist/utils/node/index.d.ts.map +1 -0
- package/dist/utils/node/index.js +16 -0
- package/dist/utils/node/index.js.map +1 -0
- package/package.json +31 -6
package/dist/utils/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
`)}const i=[0,1,2,3,4,10,33,100,190,200,299,368,613,80007,130429,130472,130497,131e3,131005,131008,131009,131016,131020,131021,131026,131030,131031,131037,131041,131042,131044,131045,131047,131048,131049,131050,131051,131052,131053,131055,131056,131057,131059,131061,131062,131063,131201,131202,131203,131204,131207,131208,131209,131210,131211,131212,131213,131214,131215,132e3,132001,132005,132007,132008,132012,132015,132016,132068,132069,133e3,133004,133005,133006,133008,133009,133010,133015,133016,134011,134100,134101,134102,135e3,137e3,138e3,138001,138002,138003,138004,138005,138006,138007,138009,138012,138013,138018,139e3,139001,139002,139003,139004,139100,139101,139102,139103,147005,200005,200006,200007,1752041,2388001,2388012,2388019,2388040,2388047,2388072,2388073,2388091,2388093,2388103,2388293,2388299,2494100,2494191,2593079,2593085,2593107,2593108],a=new Set(i),o=[0,3,10,190],s=[4,80007,130429,131048,131056],c=[368,130497,131031],l=[130472,131e3,131005,131008,131009,131016,131021,131026,131030,131042,131044,131045,131047,131050,131051,131052,131053,131056,131057,131048,131061,131062,131063,132e3,132001,132005,132007,132008,132012,132015,132016,132068,132069,135e3,137e3],u=[139e3,139001,139002,139003,139004],d=[139100,139101,139102,139103],f=[138e3,138001,138002,138003,138004,138005,138006,138007,138009,138012,138013,138018,613],p=[131020,131041,131059,131201,131202,131203,131204,131207,131208,131209,131210,131211,131212,131213,131214,131215],m=new Set(o),h=new Set(s),g=new Set(c),_=new Set(l),ee=new Set(u),te=new Set(d),ne=new Set(f),v=new Set(p);function y(e){return b(e)?!0:a.has(e)}function b(e){return e>=200&&e<300}function x(e){return b(e)||m.has(e)}function S(e){return h.has(e)}function C(e){return g.has(e)}function w(e){return _.has(e)}function T(e){return ee.has(e)}function E(e){return te.has(e)}function D(e){return ne.has(e)}function O(e){return v.has(e)}var k=class extends Error{constructor(e){super(e),this.name=`WhatsAppError`}},A=class extends k{error;statusCode;constructor(e,t,n){super(e),this.name=`WhatsAppApiError`,this.error=t,this.statusCode=n}},j=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppAuthorizationError`}},M=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppThrottlingError`}},N=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppIntegrityError`}},P=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppSendMessageError`}},F=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppFlowError`}},I=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppBlockUserError`}},L=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppCallingError`}},R=class extends A{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppGroupError`}};function z(e,t){let n=e.code;return x(n)?new j(e.message,e,t):S(n)?new M(e.message,e,t):C(n)?new N(e.message,e,t):w(n)?new P(e.message,e,t):T(n)?new F(e.message,e,t):E(n)?new I(e.message,e,t):D(n)?new L(e.message,e,t):O(n)?new R(e.message,e,t):new A(e.message,e,t)}var re=class extends k{cause;constructor(e,t){super(e),this.name=`WhatsAppNetworkError`,this.cause=t}},B=class extends k{cause;constructor(e,t){super(e),this.name=`WhatsAppUnknownError`,this.cause=t}},V=class extends Error{constructor(e){super(e),this.name=`WhatsAppValidationError`}};function H(e){if(typeof e!=`object`||!e||!(`error`in e)||typeof e.error!=`object`||e.error==null)return!1;let t=e.error;if(typeof t.message!=`string`||typeof t.type!=`string`||typeof t.code!=`number`||typeof t.fbtrace_id!=`string`)return!1;if(`error_data`in t&&t.error_data!=null){if(typeof t.error_data!=`object`)return!1;let e=t.error_data;if(`messaging_product`in e&&e.messaging_product!==`whatsapp`||`details`in e&&typeof e.details!=`string`)return!1}return!(`error_subcode`in t&&typeof t.error_subcode!=`number`)}function U(e){return H(e)&&y(e.error.code)}function W(e){return e instanceof j}function G(e){return e instanceof M}function K(e){return e instanceof N}function q(e){return e instanceof P}function J(e){return e instanceof F}function Y(e){return e instanceof I}function ie(e){return e instanceof L}function ae(e){return e instanceof R}function oe(e,t){if(H(e))return e;let n=`Unknown error occurred`;if(e&&typeof e==`object`&&`message`in e){let t=e.message;typeof t==`string`&&(n=t)}return{name:`MetaError`,message:n,error:{message:n,type:`UnknownError`,code:typeof t==`number`?t:500,fbtrace_id:``}}}var X=class{name;debug;constructor(e,t=!1){this.name=e,this.debug=t}formatData(t){return t.map(t=>typeof t==`object`?e(t,{depth:null,colors:!0}):t).join(` `)}log(...e){if(this.debug){let t=`[ ${Date.now()} ]`;this.name&&(t+=` - ${this.name}`),console.log(t,`: `,this.formatData(e))}}error(...e){let t=`[ ${Date.now()} ] - ERROR`;this.name&&(t+=` - ${this.name}`),console.error(t,`: `,this.formatData(e))}warn(...e){if(this.debug){let t=`[ ${Date.now()} ] - WARN`;this.name&&(t+=` - ${this.name}`),console.warn(t,`: `,this.formatData(e))}}info(...e){if(this.debug){let t=`[ ${Date.now()} ] - INFO`;this.name&&(t+=` - ${this.name}`),console.info(t,`: `,this.formatData(e))}}};const se=e=>{if(!e||Object.keys(e).length===0)return``;let t=[];for(let[n,r]of Object.entries(e))if(r!==void 0){let e=encodeURIComponent(n),i=encodeURIComponent(String(r));t.push(`${e}=${i}`)}return t.length>0?`?${t.join(`&`)}`:``},Z=new X(`FLOW_ENCRYPTION_UTILS`,process.env.DEBUG===`true`);function ce(){if(!t||typeof t.generateKeyPairSync!=`function`){let e=Error(`This utility requires Node.js environment with crypto module. It cannot be used in browser or edge runtime environments.`);throw Z.error(`Environment validation failed:`,e),e}if(typeof window<`u`){let e=Error(`This utility cannot run in a browser environment. Please use it in a Node.js server environment only.`);throw Z.error(`Browser environment detected:`,e),e}if(process.versions?.node){let e=process.versions.node.split(`.`).map(Number),t=e[0]??0,n=e[1]??0;if(t<10||t===10&&n<12){let e=Error(`Node.js version ${process.versions.node} is not supported. Please upgrade to Node.js 10.12.0 or higher.`);throw Z.error(`Node.js version check failed:`,e),e}}}function le(e){Z.info(`[generateEncryption] Starting key pair generation`),ce();let n=e||process.env.FLOW_API_PASSPHRASE;if(!n||n.trim().length===0){let e=Error(`Passphrase is empty. Please provide a passphrase as parameter or set FLOW_API_PASSPHRASE environment variable.`);throw Z.error(`[generateEncryption] Passphrase validation failed:`,e),e}n.length<8&&Z.warn(`[generateEncryption] Passphrase is shorter than 8 characters. Consider using a longer passphrase for better security.`);try{Z.info(`[generateEncryption] Generating 2048-bit RSA key pair`);let e=t.generateKeyPairSync(`rsa`,{modulusLength:2048,publicKeyEncoding:{type:`spki`,format:`pem`},privateKeyEncoding:{type:`pkcs8`,format:`pem`,cipher:`aes-256-cbc`,passphrase:n}});return Z.info(`[generateEncryption] Key pair generated successfully`),{passphrase:n,privateKey:e.privateKey,publicKey:e.publicKey}}catch(e){let t=e instanceof Error?e.message:String(e),n=Error(`Failed to generate key pair: ${t}`);throw Z.error(`[generateEncryption] Key generation failed:`,n),n}}function ue(e,n){if(Z.info(`[decryptFlowRequest] Starting Flow request decryption`),!n.FLOW_API_PRIVATE_PEM||n.FLOW_API_PRIVATE_PEM.trim()===``){let e=Error(`Missing FLOW_API_PRIVATE_PEM. Please set the FLOW_API_PRIVATE_PEM environment variable or pass privatePem via config.`);throw Z.error(`[decryptFlowRequest] Configuration error:`,e),e}if(!n.FLOW_API_PASSPHRASE||n.FLOW_API_PASSPHRASE.trim()===``){let e=Error(`Missing FLOW_API_PASSPHRASE. Please set the FLOW_API_PASSPHRASE environment variable or pass passphrase via config.`);throw Z.error(`[decryptFlowRequest] Configuration error:`,e),e}Z.info(`[decryptFlowRequest] Configuration validated`);let{encrypted_aes_key:r,encrypted_flow_data:i,initial_vector:a}=e;if(!r||!i||!a)throw Z.error(`[decryptFlowRequest] Missing required encryption properties in request body`),Error(`Missing required encryption properties`);Z.info(`[decryptFlowRequest] Request body validated`);let o=n.FLOW_API_PRIVATE_PEM;o.includes(`\\n`)&&(o=o.replace(/\\n/g,`
|
|
3
|
-
`));let s=
|
|
1
|
+
function e(e){if(!e)return``;let t=``;return t=Array.isArray(e)?e.join(`,`):typeof e==`string`?e:Object.entries(e).filter(([e,t])=>t).map(([e])=>e).join(`,`),t?`?fields=${t}`:``}function t(e){let t=[[`App ID`,e.M4D_APP_ID||`Not Set`],[`Phone Number ID`,e.WA_PHONE_NUMBER_ID?.toString()||`Not Set`],[`Business Account ID`,e.WA_BUSINESS_ACCOUNT_ID||`Not Set`],[`API Version`,e.CLOUD_API_VERSION||`Not Set`],[`Access Token`,e.CLOUD_API_ACCESS_TOKEN?`${e.CLOUD_API_ACCESS_TOKEN.substring(0,20)}...`:`Not Set`],[`Webhook Endpoint`,e.WEBHOOK_ENDPOINT||`Not Set`],[`Webhook Verification Token`,e.WEBHOOK_VERIFICATION_TOKEN?`${e.WEBHOOK_VERIFICATION_TOKEN.substring(0,10)}...`:`Not Set`],[`Listener Port`,e.LISTENER_PORT?.toString()||`Not Set`],[`Debug Mode`,e.DEBUG?`Enabled`:`Disabled`],[`Max Retries`,e.MAX_RETRIES_AFTER_WAIT?.toString()||`Not Set`],[`Request Timeout`,e.REQUEST_TIMEOUT?`${e.REQUEST_TIMEOUT}ms`:`Not Set`],[`Private PEM`,e.FLOW_API_PRIVATE_PEM?`Configured`:`Not Set`],[`Passphrase`,e.FLOW_API_PASSPHRASE?`Configured`:`Not Set`]],n=Math.max(...t.map(([e])=>e?.length||0)),r=Math.max(...t.map(([,e])=>e?.length||0)),i=Math.max(n,20),a=Math.max(r,30),o=`┌${`─`.repeat(i+2)}┬${`─`.repeat(a+2)}┐`,s=`├${`─`.repeat(i+2)}┼${`─`.repeat(a+2)}┤`,c=`└${`─`.repeat(i+2)}┴${`─`.repeat(a+2)}┘`;return[o,`│ ${`Configuration`.padEnd(i)} │ ${`Value`.padEnd(a)} │`,s,...t.map(([e,t])=>`│ ${e?.padEnd(i)} │ ${t?.padEnd(a)} │`),c].join(`
|
|
2
|
+
`)}const n=[0,1,2,3,4,10,33,100,190,200,299,368,613,80007,130429,130472,130497,131e3,131005,131008,131009,131016,131020,131021,131026,131030,131031,131037,131041,131042,131044,131045,131047,131048,131049,131050,131051,131052,131053,131055,131056,131057,131059,131061,131062,131063,131201,131202,131203,131204,131207,131208,131209,131210,131211,131212,131213,131214,131215,132e3,132001,132005,132007,132008,132012,132015,132016,132068,132069,133e3,133004,133005,133006,133008,133009,133010,133015,133016,134011,134100,134101,134102,135e3,137e3,138e3,138001,138002,138003,138004,138005,138006,138007,138009,138012,138013,138018,139e3,139001,139002,139003,139004,139100,139101,139102,139103,147005,200005,200006,200007,1752041,2388001,2388012,2388019,2388040,2388047,2388072,2388073,2388091,2388093,2388103,2388293,2388299,2494100,2494191,2593079,2593085,2593107,2593108],r=new Set(n),i=[0,3,10,190],a=[4,80007,130429,131048,131056],o=[368,130497,131031],s=[130472,131e3,131005,131008,131009,131016,131021,131026,131030,131042,131044,131045,131047,131050,131051,131052,131053,131056,131057,131048,131061,131062,131063,132e3,132001,132005,132007,132008,132012,132015,132016,132068,132069,135e3,137e3],c=[139e3,139001,139002,139003,139004],l=[139100,139101,139102,139103],u=[138e3,138001,138002,138003,138004,138005,138006,138007,138009,138012,138013,138018,613],d=[131020,131041,131059,131201,131202,131203,131204,131207,131208,131209,131210,131211,131212,131213,131214,131215],f=new Set(i),p=new Set(a),m=new Set(o),ee=new Set(s),h=new Set(c),g=new Set(l),te=new Set(u),ne=new Set(d);function re(e){return _(e)?!0:r.has(e)}function _(e){return e>=200&&e<300}function ie(e){return _(e)||f.has(e)}function ae(e){return p.has(e)}function oe(e){return m.has(e)}function se(e){return ee.has(e)}function v(e){return h.has(e)}function y(e){return g.has(e)}function b(e){return te.has(e)}function x(e){return ne.has(e)}var S=class extends Error{constructor(e){super(e),this.name=`WhatsAppError`}},C=class extends S{error;statusCode;rateLimit;constructor(e,t,n){super(e),this.name=`WhatsAppApiError`,this.error=t,this.statusCode=n}},w=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppAuthorizationError`}},T=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppThrottlingError`}},E=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppIntegrityError`}},D=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppSendMessageError`}},O=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppFlowError`}},k=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppBlockUserError`}},A=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppCallingError`}},j=class extends C{constructor(e,t,n){super(e,t,n),this.name=`WhatsAppGroupError`}};function ce(e,t){let n=e.code;return ie(n)?new w(e.message,e,t):ae(n)?new T(e.message,e,t):oe(n)?new E(e.message,e,t):se(n)?new D(e.message,e,t):v(n)?new O(e.message,e,t):y(n)?new k(e.message,e,t):b(n)?new A(e.message,e,t):x(n)?new j(e.message,e,t):new C(e.message,e,t)}var le=class extends S{cause;constructor(e,t){super(e),this.name=`WhatsAppNetworkError`,this.cause=t}},ue=class extends S{cause;constructor(e,t){super(e),this.name=`WhatsAppUnknownError`,this.cause=t}},M=class extends Error{constructor(e){super(e),this.name=`WhatsAppValidationError`}};function N(e){if(typeof e!=`object`||!e||!(`error`in e)||typeof e.error!=`object`||e.error==null)return!1;let t=e.error;if(typeof t.message!=`string`||typeof t.type!=`string`||typeof t.code!=`number`||typeof t.fbtrace_id!=`string`)return!1;if(`error_data`in t&&t.error_data!=null){if(typeof t.error_data!=`object`)return!1;let e=t.error_data;if(`messaging_product`in e&&e.messaging_product!==`whatsapp`||`details`in e&&typeof e.details!=`string`)return!1}return!(`error_subcode`in t&&typeof t.error_subcode!=`number`)}function de(e){return N(e)&&re(e.error.code)}function fe(e){return e instanceof w}function pe(e){return e instanceof T}function me(e){return e instanceof E}function he(e){return e instanceof D}function ge(e){return e instanceof O}function _e(e){return e instanceof k}function ve(e){return e instanceof A}function ye(e){return e instanceof j}function be(e,t){if(N(e))return e;let n=`Unknown error occurred`;if(e&&typeof e==`object`&&`message`in e){let t=e.message;typeof t==`string`&&(n=t)}return{name:`MetaError`,message:n,error:{message:n,type:`UnknownError`,code:typeof t==`number`?t:500,fbtrace_id:``}}}const P=3600*1e3,F=24*P,I=72*P,xe=168*P,L=1e11;function R(e,t){let n;if(e instanceof Date)n=e.getTime();else if(typeof e==`number`)n=Math.abs(e)<L?e*1e3:e;else if(typeof e==`string`){let t=e.trim();if(/^\d+(\.\d+)?$/.test(t)){let e=Number(t);n=e<L?e*1e3:e}else n=t===``?NaN:Date.parse(t)}else n=NaN;if(!Number.isFinite(n)||!Number.isFinite(new Date(n).getTime()))throw new M(`${t} is not a valid timestamp: ${String(e)}`);return n}function z(e,t,n){if(e===void 0)return n;if(typeof e!=`number`||!Number.isFinite(e)||e<0)throw new M(`${t} must be a non-negative number of milliseconds`);return e}function B(e,t,n,r){if(!Number.isFinite(new Date(t).getTime()))throw new M(`Window expiry is outside the supported timestamp range`);let i=Math.max(0,t-e),a=t-r,o=Math.min(Math.max(0,a-n),i);return{isOpen:o>0,expiresAt:new Date(t),remainingMs:o}}const V=Object.freeze({isOpen:!1,expiresAt:null,remainingMs:0});function H(e,t={}){let n=z(t.safetyMarginMs,`safetyMarginMs`,0),r=t.now===void 0?Date.now():R(t.now,`now`);if(e==null)return{...V};let i=R(e,`lastInboundAt`);return B(i,i+F,r,n)}function Se(e,t={}){return H(e,t).isOpen}function Ce(e,t={}){let n=z(t.safetyMarginMs,`safetyMarginMs`,0),r=z(t.durationMs,`durationMs`,I),i=t.now===void 0?Date.now():R(t.now,`now`);if(e==null)return{...V};let a=R(e,`openedAt`);return B(a,t.expiresAt===void 0?a+r:R(t.expiresAt,`expiresAt`),i,n)}var U=class{name;debugEnabled;constructor(e,t=!1){this.name=e,this.debugEnabled=t}formatData(e){return e.map(e=>typeof e==`object`&&e?we(e):e).join(` `)}log(...e){if(this.debugEnabled){let t=`[ ${Date.now()} ]`;this.name&&(t+=` - ${this.name}`),console.log(t,`: `,this.formatData(e))}}error(...e){let t=`[ ${Date.now()} ] - ERROR`;this.name&&(t+=` - ${this.name}`),console.error(t,`: `,this.formatData(e))}warn(...e){if(this.debugEnabled){let t=`[ ${Date.now()} ] - WARN`;this.name&&(t+=` - ${this.name}`),console.warn(t,`: `,this.formatData(e))}}info(...e){if(this.debugEnabled){let t=`[ ${Date.now()} ] - INFO`;this.name&&(t+=` - ${this.name}`),console.info(t,`: `,this.formatData(e))}}debug(...e){if(this.debugEnabled){let t=`[ ${Date.now()} ] - DEBUG`;this.name&&(t+=` - ${this.name}`),console.debug(t,`: `,this.formatData(e))}}};function we(e){if(e instanceof Error)return e.stack||`${e.name}: ${e.message}`;let t=new WeakSet;try{return JSON.stringify(e,(e,n)=>{if(n instanceof Error)return{name:n.name,message:n.message,stack:n.stack};if(typeof n==`bigint`)return n.toString();if(typeof n==`object`&&n){if(t.has(n))return`[Circular]`;t.add(n)}return n},2)}catch{return String(e)}}const Te=e=>{if(!e||Object.keys(e).length===0)return``;let t=[];for(let[n,r]of Object.entries(e))if(r!==void 0){let e=encodeURIComponent(n),i=encodeURIComponent(String(r));t.push(`${e}=${i}`)}return t.length>0?`?${t.join(`&`)}`:``};function W(e,t){if(typeof e.get==`function`)return e.get(t)??void 0;let n=e,r=Object.keys(n).find(e=>e.toLowerCase()===t);if(r===void 0)return;let i=n[r];return Array.isArray(i)?i[0]:i}function Ee(e){if(!(e===void 0||e.trim()===``))try{return JSON.parse(e)}catch{return}}function G(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function K(e){if(typeof e==`number`&&Number.isFinite(e))return e;if(typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e)))return Number(e)}function De(e){return typeof e==`string`?e:void 0}function Oe(e){let t={},n=K(e.call_count),r=K(e.total_cputime),i=K(e.total_time);return n!==void 0&&(t.callCount=n),r!==void 0&&(t.totalCputime=r),i!==void 0&&(t.totalTime=i),t}function ke(e){if(!G(e))return[];let t=[];for(let[n,r]of Object.entries(e))if(Array.isArray(r))for(let e of r){if(!G(e))continue;let r={businessId:n,...Oe(e)},i=De(e.type),a=K(e.estimated_time_to_regain_access),o=De(e.ads_api_access_tier);i!==void 0&&(r.type=i),a!==void 0&&(r.estimatedTimeToRegainAccessMinutes=a),o!==void 0&&(r.adsApiAccessTier=o),t.push(r)}return t}function Ae(e,t=Date.now()){if(e==null)return;let n=e.trim();if(n===``)return;if(/^\d+(\.\d+)?$/.test(n))return Math.round(Number(n)*1e3);if(!/[a-z]/i.test(n))return;let r=Date.parse(n);if(Number.isFinite(r))return Math.max(0,r-t)}function je(e){if(!e)return;let t=W(e,`x-app-usage`),n=W(e,`x-business-use-case-usage`),r=W(e,`retry-after`);if(t===void 0&&n===void 0&&r===void 0)return;let i={businessUseCaseUsage:[]},a=Ee(t);G(a)&&(i.appUsage=Oe(a)),i.businessUseCaseUsage=ke(Ee(n));let o=Ae(r);o!==void 0&&(i.retryAfterMs=o);let s=[...i.appUsage?[i.appUsage]:[],...i.businessUseCaseUsage].flatMap(e=>[e.callCount,e.totalCputime,e.totalTime].filter(e=>e!==void 0));s.length>0&&(i.maxUsagePercent=Math.max(...s));let c=[...o===void 0?[]:[o],...i.businessUseCaseUsage.map(e=>e.estimatedTimeToRegainAccessMinutes).filter(e=>e!==void 0&&e>0).map(e=>e*6e4)];return c.length>0&&(i.retryDelayMs=Math.max(...c)),i}function q(){let e=globalThis.process;return typeof e==`object`&&e?e:void 0}function Me(e){return q()?.env?.[e]}function Ne(){return Me(`DEBUG`)===`true`}function J(){let e=q()?.getBuiltinModule;if(typeof e!=`function`)return q(),void 0;try{return e(`node:crypto`)}catch{return}}function Pe(e){let t=J();if(!t)throw Error(`${e} needs the node:crypto module, which is not available in this runtime. Use the async Web Crypto variant instead, or run on Node.js >= 20.12, Bun or Deno.`);return t}function Y(){let e=globalThis.crypto?.subtle;if(!e)throw Error(`Web Crypto (globalThis.crypto.subtle) is not available in this runtime.`);return e}const Fe=new TextEncoder,Ie=new TextDecoder;function Le(e){return Fe.encode(e)}function Re(e){return Ie.decode(e)}function X(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}function ze(e){let t=``,n=32768;for(let r=0;r<e.length;r+=n)t+=String.fromCharCode(...e.subarray(r,r+n));return btoa(t)}const Z=new U(`FLOW_ENCRYPTION_UTILS`,Ne());function Be(){let e=J();if(!e||typeof e.generateKeyPairSync!=`function`){let e=Error(`This utility requires Node.js environment with crypto module. It cannot be used in browser or edge runtime environments.`);throw Z.error(`Environment validation failed:`,e),e}if(typeof window<`u`){let e=Error(`This utility cannot run in a browser environment. Please use it in a Node.js server environment only.`);throw Z.error(`Browser environment detected:`,e),e}let t=globalThis.process?.versions?.node;if(t){let e=t.split(`.`).map(Number),n=e[0]??0,r=e[1]??0;if(n<10||n===10&&r<12){let e=Error(`Node.js version ${t} is not supported. Please upgrade to Node.js 10.12.0 or higher.`);throw Z.error(`Node.js version check failed:`,e),e}}return e}function Ve(e){Z.info(`[generateEncryption] Starting key pair generation`);let t=Be(),n=e||Me(`FLOW_API_PASSPHRASE`);if(!n||n.trim().length===0){let e=Error(`Passphrase is empty. Please provide a passphrase as parameter or set FLOW_API_PASSPHRASE environment variable.`);throw Z.error(`[generateEncryption] Passphrase validation failed:`,e),e}n.length<8&&Z.warn(`[generateEncryption] Passphrase is shorter than 8 characters. Consider using a longer passphrase for better security.`);try{Z.info(`[generateEncryption] Generating 2048-bit RSA key pair`);let e=t.generateKeyPairSync(`rsa`,{modulusLength:2048,publicKeyEncoding:{type:`spki`,format:`pem`},privateKeyEncoding:{type:`pkcs8`,format:`pem`,cipher:`aes-256-cbc`,passphrase:n}});return Z.info(`[generateEncryption] Key pair generated successfully`),{passphrase:n,privateKey:e.privateKey,publicKey:e.publicKey}}catch(e){let t=e instanceof Error?e.message:String(e),n=Error(`Failed to generate key pair: ${t}`);throw Z.error(`[generateEncryption] Key generation failed:`,n),n}}function He(e,t){Z.info(`[decryptFlowRequest] Starting Flow request decryption`);let n=Pe(`decryptFlowRequest`);if(!t.FLOW_API_PRIVATE_PEM||t.FLOW_API_PRIVATE_PEM.trim()===``){let e=Error(`Missing FLOW_API_PRIVATE_PEM. Please set the FLOW_API_PRIVATE_PEM environment variable or pass privatePem via config.`);throw Z.error(`[decryptFlowRequest] Configuration error:`,e),e}if(!t.FLOW_API_PASSPHRASE||t.FLOW_API_PASSPHRASE.trim()===``){let e=Error(`Missing FLOW_API_PASSPHRASE. Please set the FLOW_API_PASSPHRASE environment variable or pass passphrase via config.`);throw Z.error(`[decryptFlowRequest] Configuration error:`,e),e}Z.info(`[decryptFlowRequest] Configuration validated`);let{encrypted_aes_key:r,encrypted_flow_data:i,initial_vector:a}=e;if(!r||!i||!a)throw Z.error(`[decryptFlowRequest] Missing required encryption properties in request body`),Error(`Missing required encryption properties`);Z.info(`[decryptFlowRequest] Request body validated`);let o=t.FLOW_API_PRIVATE_PEM;o.includes(`\\n`)&&(o=o.replace(/\\n/g,`
|
|
3
|
+
`));let s=t.FLOW_API_PASSPHRASE,c=o.includes(`-----BEGIN RSA PRIVATE KEY-----`),l=o.includes(`-----BEGIN PRIVATE KEY-----`)||o.includes(`-----BEGIN ENCRYPTED PRIVATE KEY-----`);Z.info(`[decryptFlowRequest] Loading private key`,{format:l?`PKCS#8`:c?`PKCS#1`:`Unknown`});let u;try{u=s?n.createPrivateKey({key:o,format:`pem`,passphrase:s}):n.createPrivateKey(o),Z.info(`[decryptFlowRequest] Private key loaded successfully`)}catch(e){if(Z.error(`[decryptFlowRequest] Failed to load private key (first attempt):`,{error:e instanceof Error?e.message:e,hasPassphrase:!!s,format:l?`PKCS#8`:c?`PKCS#1`:`Unknown`}),c&&s)try{Z.info(`[decryptFlowRequest] Attempting to convert PKCS#1 to PKCS#8 format`);let e=n.createPrivateKey({key:o,format:`pem`,passphrase:s}).export({type:`pkcs8`,format:`pem`,cipher:`aes-256-cbc`,passphrase:s});u=n.createPrivateKey({key:e,format:`pem`,passphrase:s}),Z.info(`[decryptFlowRequest] Successfully converted PKCS#1 to PKCS#8 and loaded private key`)}catch(t){Z.error(`[decryptFlowRequest] Failed to convert PKCS#1 to PKCS#8:`,{error:t instanceof Error?t.message:t});let n=`Failed to parse private key. Error: ${e instanceof Error?e.message:e}`;throw n+=`
|
|
4
4
|
|
|
5
5
|
Your key is in PKCS#1 format with unsupported encryption (DES-EDE3-CBC).`,n+=`
|
|
6
6
|
Please convert it to PKCS#8 format using:`,n+=`
|
|
@@ -10,5 +10,7 @@ Your key is in PKCS#1 format (-----BEGIN RSA PRIVATE KEY-----).`,t+=`
|
|
|
10
10
|
Please convert it to PKCS#8 format using:`,t+=`
|
|
11
11
|
openssl pkcs8 -topk8 -inform PEM -outform PEM -in old_key.pem -out new_key.pem`):l||(t+=`
|
|
12
12
|
|
|
13
|
-
Your key format is not recognized. Please ensure it is in PKCS#8 format.`),Error(t)}}let d;try{Z.info(`[decryptFlowRequest] Decrypting AES key with RSA private key`),d=
|
|
13
|
+
Your key format is not recognized. Please ensure it is in PKCS#8 format.`),Error(t)}}let d;try{Z.info(`[decryptFlowRequest] Decrypting AES key with RSA private key`),d=n.privateDecrypt({key:u,padding:n.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:`sha256`},Buffer.from(r,`base64`)),Z.info(`[decryptFlowRequest] AES key decrypted successfully`)}catch(e){throw Z.error(`[decryptFlowRequest] Failed to decrypt AES key:`,e),Error(`Failed to decrypt the request. Please verify your private key.`)}let f=Buffer.from(i,`base64`),p=Buffer.from(a,`base64`),m=f.subarray(0,-16),ee=f.subarray(-16);Z.info(`[decryptFlowRequest] Decrypting flow data with AES-128-GCM`);let h=n.createDecipheriv(`aes-128-gcm`,d,p);h.setAuthTag(ee);let g=Buffer.concat([h.update(m),h.final()]).toString(`utf-8`);return Z.info(`[decryptFlowRequest] Flow request decrypted successfully`),{decryptedBody:JSON.parse(g),aesKeyBuffer:d,initialVectorBuffer:p}}function Ue(e,t,n){Z.info(`[encryptFlowResponse] Starting Flow response encryption`);let r=Pe(`encryptFlowResponse`),i=[];for(let e of Array.from(n.entries()))i.push(~e[1]);try{Z.info(`[encryptFlowResponse] Encrypting response with AES-128-GCM`);let n=r.createCipheriv(`aes-128-gcm`,t,Buffer.from(i)),a=Buffer.concat([n.update(JSON.stringify(e||{}),`utf-8`),n.final(),n.getAuthTag()]).toString(`base64`);return Z.info(`[encryptFlowResponse] Flow response encrypted successfully`),a}catch(e){throw Z.error(`[encryptFlowResponse] Response encryption failed:`,e),Error(`Failed to encrypt response. Internal server error.`)}}const We=/-----BEGIN ([A-Z ]+)-----([\s\S]*?)-----END \1-----/;let Q;function Ge(e,t){let n=We.exec(e);if(!n)throw Error(`Failed to parse private key. Expected a PEM encoded PKCS#8 private key.`);let r=n[1];if(r===`PRIVATE KEY`)return X((n[2]??``).replace(/\s+/g,``));let i=J();if(!i)throw Error(`Failed to parse private key. "${r}" keys need node:crypto, which this runtime lacks. Convert the key to an unencrypted PKCS#8 key and keep it in a secret store:
|
|
14
|
+
openssl pkcs8 -topk8 -nocrypt -in private.pem -out private-pkcs8.pem`);try{let n=i.createPrivateKey({key:e,format:`pem`,passphrase:t||void 0}).export({type:`pkcs8`,format:`der`});return new Uint8Array(n)}catch(e){throw Error(`Failed to parse private key. Error: ${e instanceof Error?e.message:e}`)}}function Ke(e,t){if(Q&&Q.pem===e&&Q.passphrase===t)return Q.key;let n=(async()=>Y().importKey(`pkcs8`,Ge(e,t),{name:`RSA-OAEP`,hash:`SHA-256`},!1,[`decrypt`]))();return Q={pem:e,passphrase:t,key:n},n.catch(()=>{Q?.key===n&&(Q=void 0)}),n}async function qe(e,t){if(!t.FLOW_API_PRIVATE_PEM||t.FLOW_API_PRIVATE_PEM.trim()===``)throw Error(`Missing FLOW_API_PRIVATE_PEM. Please set the FLOW_API_PRIVATE_PEM environment variable or pass privatePem via config.`);let{encrypted_aes_key:n,encrypted_flow_data:r,initial_vector:i}=e??{};if(!n||!r||!i)throw Error(`Missing required encryption properties`);let a=t.FLOW_API_PRIVATE_PEM;a.includes(`\\n`)&&(a=a.replace(/\\n/g,`
|
|
15
|
+
`));let o=Y(),s=await Ke(a,t.FLOW_API_PASSPHRASE||``),c;try{c=new Uint8Array(await o.decrypt({name:`RSA-OAEP`},s,X(n)))}catch(e){throw Z.error(`[decryptFlowRequestAsync] Failed to decrypt AES key:`,e),Error(`Failed to decrypt the request. Please verify your private key.`)}let l=X(i),u=await o.importKey(`raw`,c,{name:`AES-GCM`},!1,[`decrypt`]),d=await o.decrypt({name:`AES-GCM`,iv:l,tagLength:128},u,X(r));return{decryptedBody:JSON.parse(Re(new Uint8Array(d))),aesKeyBuffer:c,initialVectorBuffer:l}}async function Je(e,t,n){let r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=~(n[e]??0)&255;try{let n=Y(),i=await n.importKey(`raw`,new Uint8Array(t),{name:`AES-GCM`},!1,[`encrypt`]),a=await n.encrypt({name:`AES-GCM`,iv:r,tagLength:128},i,Le(JSON.stringify(e||{})));return ze(new Uint8Array(a))}catch(e){throw Z.error(`[encryptFlowResponseAsync] Response encryption failed:`,e),Error(`Failed to encrypt response. Internal server error.`)}}function Ye(e){return typeof e==`object`&&!!e}function $(e){return typeof e==`string`}const Xe=[`data_exchange`,`INIT`,`BACK`],Ze=[`data_exchange`,`INIT`];function Qe(e){if(!(`flow_token`in e&&$(e.flow_token)&&`action`in e))return!1;let{action:t,version:n,screen:r,data:i}=e,a=n===`3.0`,o=Xe.includes(t),s=r===void 0||$(r)&&r!==`SUCCESS`,c=t===`data_exchange`||Ye(i);return a&&o&&s&&c}function $e(e){if(!(`flow_token`in e&&$(e.flow_token)&&`action`in e))return!1;let{action:t,screen:n,data:r}=e,i=Ze.includes(t),a=$(n),o=Ye(r)&&`error_key`in r&&$(r.error)&&`error_message`in r&&$(r.error_message);return i&&a&&o}function et(e){return`action`in e&&e.action===`ping`}export{i as AUTHORIZATION_ERROR_CODES,l as BLOCK_USER_ERROR_CODES,u as CALLING_ERROR_CODES,F as CUSTOMER_SERVICE_WINDOW_MS,c as FLOW_ERROR_CODES,I as FREE_ENTRY_POINT_WINDOW_MS,d as GROUP_ERROR_CODES,o as INTEGRITY_ERROR_CODES,U as Logger,xe as MAX_FREE_ENTRY_POINT_WINDOW_MS,s as SEND_MESSAGE_ERROR_CODES,a as THROTTLING_ERROR_CODES,n as WHATSAPP_ERROR_CODES,C as WhatsAppApiError,w as WhatsAppAuthorizationError,k as WhatsAppBlockUserError,A as WhatsAppCallingError,S as WhatsAppError,O as WhatsAppFlowError,j as WhatsAppGroupError,E as WhatsAppIntegrityError,le as WhatsAppNetworkError,D as WhatsAppSendMessageError,T as WhatsAppThrottlingError,ue as WhatsAppUnknownError,M as WhatsAppValidationError,e as buildFieldsQueryString,Se as canSendFreeformMessage,ce as createWhatsAppApiError,He as decryptFlowRequest,qe as decryptFlowRequestAsync,Ue as encryptFlowResponse,Je as encryptFlowResponseAsync,t as formatConfigTable,Ve as generateEncryption,H as getCustomerServiceWindow,Ce as getFreeEntryPointWindow,_ as isApiPermissionErrorCode,ie as isAuthorizationErrorCode,y as isBlockUserErrorCode,b as isCallingErrorCode,Qe as isFlowDataExchangeRequest,v as isFlowErrorCode,$e as isFlowErrorRequest,et as isFlowPingRequest,x as isGroupErrorCode,oe as isIntegrityErrorCode,N as isMetaError,se as isSendMessageErrorCode,ae as isThrottlingErrorCode,de as isWhatsAppApiErrorResponse,fe as isWhatsAppAuthorizationError,_e as isWhatsAppBlockUserError,ve as isWhatsAppCallingError,re as isWhatsAppErrorCode,ge as isWhatsAppFlowError,ye as isWhatsAppGroupError,me as isWhatsAppIntegrityError,he as isWhatsAppSendMessageError,pe as isWhatsAppThrottlingError,be as normalizeMetaError,Te as objectToQueryString,je as parseRateLimitHeaders,Ae as parseRetryAfter};
|
|
14
16
|
//# sourceMappingURL=index.js.map
|
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/utils/buildFieldsQueryString.ts","../../src/utils/configTable.ts","../../src/utils/isMetaError.ts","../../src/utils/logger.ts","../../src/utils/objectToQueryString.ts","../../src/utils/flowEncryptionUtils.ts","../../src/utils/flowTypeGuards.ts"],"sourcesContent":["export function buildFieldsQueryString(fields?: string[] | string): string {\n if (!fields) return '';\n\n let fieldParams = '';\n\n if (Array.isArray(fields)) {\n fieldParams = fields.join(',');\n } else if (typeof fields === 'string') {\n fieldParams = fields;\n } else {\n fieldParams = Object.entries(fields)\n .filter(([_, value]) => value)\n .map(([key]) => key)\n .join(',');\n }\n\n return fieldParams ? `?fields=${fieldParams}` : '';\n}\n","import type { WabaConfigType } from '../types/config';\nimport { WabaConfigEnum } from '../types/enums';\n\n/**\n * Formats configuration as a terminal table\n * @param config - The WABA configuration object\n * @param apiName - The name of the API being initialized\n * @returns Formatted table string\n */\nexport function formatConfigTable(config: WabaConfigType): string {\n const configData = [\n ['App ID', config[WabaConfigEnum.AppId] || 'Not Set'],\n ['Phone Number ID', config[WabaConfigEnum.PhoneNumberId]?.toString() || 'Not Set'],\n ['Business Account ID', config[WabaConfigEnum.BusinessAcctId] || 'Not Set'],\n ['API Version', config[WabaConfigEnum.APIVersion] || 'Not Set'],\n [\n 'Access Token',\n config[WabaConfigEnum.AccessToken]\n ? `${config[WabaConfigEnum.AccessToken].substring(0, 20)}...`\n : 'Not Set',\n ],\n ['Webhook Endpoint', config[WabaConfigEnum.WebhookEndpoint] || 'Not Set'],\n [\n 'Webhook Verification Token',\n config[WabaConfigEnum.WebhookVerificationToken]\n ? `${config[WabaConfigEnum.WebhookVerificationToken].substring(0, 10)}...`\n : 'Not Set',\n ],\n ['Listener Port', config[WabaConfigEnum.ListenerPort]?.toString() || 'Not Set'],\n ['Debug Mode', config[WabaConfigEnum.Debug] ? 'Enabled' : 'Disabled'],\n ['Max Retries', config[WabaConfigEnum.MaxRetriesAfterWait]?.toString() || 'Not Set'],\n [\n 'Request Timeout',\n config[WabaConfigEnum.RequestTimeout] ? `${config[WabaConfigEnum.RequestTimeout]}ms` : 'Not Set',\n ],\n ['Private PEM', config[WabaConfigEnum.PrivatePem] ? 'Configured' : 'Not Set'],\n ['Passphrase', config[WabaConfigEnum.Passphrase] ? 'Configured' : 'Not Set'],\n ];\n\n // Calculate column widths\n const maxKeyLength = Math.max(...configData.map(([key]) => key?.length || 0));\n const maxValueLength = Math.max(...configData.map(([, value]) => value?.length || 0));\n\n const keyWidth = Math.max(maxKeyLength, 20);\n const valueWidth = Math.max(maxValueLength, 30);\n\n // Create table\n const horizontalLine = `┌${'─'.repeat(keyWidth + 2)}┬${'─'.repeat(valueWidth + 2)}┐`;\n const separator = `├${'─'.repeat(keyWidth + 2)}┼${'─'.repeat(valueWidth + 2)}┤`;\n const bottomLine = `└${'─'.repeat(keyWidth + 2)}┴${'─'.repeat(valueWidth + 2)}┘`;\n\n const header = `│ ${'Configuration'.padEnd(keyWidth)} │ ${'Value'.padEnd(valueWidth)} │`;\n\n const rows = configData.map(([key, value]) => `│ ${key?.padEnd(keyWidth)} │ ${value?.padEnd(valueWidth)} │`);\n\n return [horizontalLine, header, separator, ...rows, bottomLine].join('\\n');\n}\n","export type MetaErrorData = {\n message: string;\n type: string;\n code: number;\n error_data?: {\n messaging_product?: 'whatsapp';\n details?: string;\n };\n error_subcode?: number;\n fbtrace_id: string;\n};\n\nexport interface MetaError extends Error {\n error: MetaErrorData;\n}\n\nexport const WHATSAPP_ERROR_CODES = [\n 0, 1, 2, 3, 4, 10, 33, 100, 190, 200, 299, 368, 613, 80007, 130429, 130472, 130497, 131000, 131005, 131008, 131009,\n 131016, 131020, 131021, 131026, 131030, 131031, 131037, 131041, 131042, 131044, 131045, 131047, 131048, 131049,\n 131050, 131051, 131052, 131053, 131055, 131056, 131057, 131059, 131061, 131062, 131063, 131201, 131202, 131203,\n 131204, 131207, 131208, 131209, 131210, 131211, 131212, 131213, 131214, 131215, 132000, 132001, 132005, 132007,\n 132008, 132012, 132015, 132016, 132068, 132069, 133000, 133004, 133005, 133006, 133008, 133009, 133010, 133015,\n 133016, 134011, 134100, 134101, 134102, 135000, 137000, 138000, 138001, 138002, 138003, 138004, 138005, 138006,\n 138007, 138009, 138012, 138013, 138018, 139000, 139001, 139002, 139003, 139004, 139100, 139101, 139102, 139103,\n 147005, 200005, 200006, 200007, 1752041, 2388001, 2388012, 2388019, 2388040, 2388047, 2388072, 2388073, 2388091,\n 2388093, 2388103, 2388293, 2388299, 2494100, 2494191, 2593079, 2593085, 2593107, 2593108,\n] as const;\n\nconst WHATSAPP_ERROR_CODE_SET = new Set<number>(WHATSAPP_ERROR_CODES);\n\nexport type ApiPermissionErrorCode = number;\nexport type WhatsAppErrorCode = (typeof WHATSAPP_ERROR_CODES)[number] | ApiPermissionErrorCode;\n\nexport const AUTHORIZATION_ERROR_CODES = [0, 3, 10, 190] as const;\nexport const THROTTLING_ERROR_CODES = [4, 80007, 130429, 131048, 131056] as const;\nexport const INTEGRITY_ERROR_CODES = [368, 130497, 131031] as const;\nexport const SEND_MESSAGE_ERROR_CODES = [\n 130472, 131000, 131005, 131008, 131009, 131016, 131021, 131026, 131030, 131042, 131044, 131045, 131047, 131050,\n 131051, 131052, 131053, 131056, 131057, 131048, 131061, 131062, 131063, 132000, 132001, 132005, 132007, 132008,\n 132012, 132015, 132016, 132068, 132069, 135000, 137000,\n] as const;\nexport const FLOW_ERROR_CODES = [139000, 139001, 139002, 139003, 139004] as const;\nexport const BLOCK_USER_ERROR_CODES = [139100, 139101, 139102, 139103] as const;\nexport const CALLING_ERROR_CODES = [\n 138000, 138001, 138002, 138003, 138004, 138005, 138006, 138007, 138009, 138012, 138013, 138018, 613,\n] as const;\nexport const GROUP_ERROR_CODES = [\n 131020, 131041, 131059, 131201, 131202, 131203, 131204, 131207, 131208, 131209, 131210, 131211, 131212, 131213,\n 131214, 131215,\n] as const;\n\nconst AUTHORIZATION_ERROR_CODE_SET = new Set<number>(AUTHORIZATION_ERROR_CODES);\nconst THROTTLING_ERROR_CODE_SET = new Set<number>(THROTTLING_ERROR_CODES);\nconst INTEGRITY_ERROR_CODE_SET = new Set<number>(INTEGRITY_ERROR_CODES);\nconst SEND_MESSAGE_ERROR_CODE_SET = new Set<number>(SEND_MESSAGE_ERROR_CODES);\nconst FLOW_ERROR_CODE_SET = new Set<number>(FLOW_ERROR_CODES);\nconst BLOCK_USER_ERROR_CODE_SET = new Set<number>(BLOCK_USER_ERROR_CODES);\nconst CALLING_ERROR_CODE_SET = new Set<number>(CALLING_ERROR_CODES);\nconst GROUP_ERROR_CODE_SET = new Set<number>(GROUP_ERROR_CODES);\n\nexport function isWhatsAppErrorCode(code: number): code is WhatsAppErrorCode {\n if (isApiPermissionErrorCode(code)) return true;\n return WHATSAPP_ERROR_CODE_SET.has(code);\n}\n\nexport function isApiPermissionErrorCode(code: number): code is ApiPermissionErrorCode {\n return code >= 200 && code < 300;\n}\n\nexport function isAuthorizationErrorCode(\n code: number,\n): code is ApiPermissionErrorCode | (typeof AUTHORIZATION_ERROR_CODES)[number] {\n return isApiPermissionErrorCode(code) || AUTHORIZATION_ERROR_CODE_SET.has(code);\n}\n\nexport function isThrottlingErrorCode(code: number): code is (typeof THROTTLING_ERROR_CODES)[number] {\n return THROTTLING_ERROR_CODE_SET.has(code);\n}\n\nexport function isIntegrityErrorCode(code: number): code is (typeof INTEGRITY_ERROR_CODES)[number] {\n return INTEGRITY_ERROR_CODE_SET.has(code);\n}\n\nexport function isSendMessageErrorCode(code: number): code is (typeof SEND_MESSAGE_ERROR_CODES)[number] {\n return SEND_MESSAGE_ERROR_CODE_SET.has(code);\n}\n\nexport function isFlowErrorCode(code: number): code is (typeof FLOW_ERROR_CODES)[number] {\n return FLOW_ERROR_CODE_SET.has(code);\n}\n\nexport function isBlockUserErrorCode(code: number): code is (typeof BLOCK_USER_ERROR_CODES)[number] {\n return BLOCK_USER_ERROR_CODE_SET.has(code);\n}\n\nexport function isCallingErrorCode(code: number): code is (typeof CALLING_ERROR_CODES)[number] {\n return CALLING_ERROR_CODE_SET.has(code);\n}\n\nexport function isGroupErrorCode(code: number): code is (typeof GROUP_ERROR_CODES)[number] {\n return GROUP_ERROR_CODE_SET.has(code);\n}\n\nexport class WhatsAppError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WhatsAppError';\n }\n}\n\nexport class WhatsAppApiError extends WhatsAppError {\n readonly error: MetaErrorData;\n readonly statusCode?: number;\n\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message);\n this.name = 'WhatsAppApiError';\n this.error = error;\n this.statusCode = statusCode;\n }\n}\n\nexport class WhatsAppAuthorizationError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppAuthorizationError';\n }\n}\n\nexport class WhatsAppThrottlingError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppThrottlingError';\n }\n}\n\nexport class WhatsAppIntegrityError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppIntegrityError';\n }\n}\n\nexport class WhatsAppSendMessageError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppSendMessageError';\n }\n}\n\nexport class WhatsAppFlowError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppFlowError';\n }\n}\n\nexport class WhatsAppBlockUserError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppBlockUserError';\n }\n}\n\nexport class WhatsAppCallingError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppCallingError';\n }\n}\n\nexport class WhatsAppGroupError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppGroupError';\n }\n}\n\nexport function createWhatsAppApiError(error: MetaErrorData, statusCode?: number): WhatsAppApiError {\n const code = error.code;\n\n if (isAuthorizationErrorCode(code)) {\n return new WhatsAppAuthorizationError(error.message, error, statusCode);\n }\n if (isThrottlingErrorCode(code)) {\n return new WhatsAppThrottlingError(error.message, error, statusCode);\n }\n if (isIntegrityErrorCode(code)) {\n return new WhatsAppIntegrityError(error.message, error, statusCode);\n }\n if (isSendMessageErrorCode(code)) {\n return new WhatsAppSendMessageError(error.message, error, statusCode);\n }\n if (isFlowErrorCode(code)) {\n return new WhatsAppFlowError(error.message, error, statusCode);\n }\n if (isBlockUserErrorCode(code)) {\n return new WhatsAppBlockUserError(error.message, error, statusCode);\n }\n if (isCallingErrorCode(code)) {\n return new WhatsAppCallingError(error.message, error, statusCode);\n }\n if (isGroupErrorCode(code)) {\n return new WhatsAppGroupError(error.message, error, statusCode);\n }\n\n return new WhatsAppApiError(error.message, error, statusCode);\n}\n\nexport class WhatsAppNetworkError extends WhatsAppError {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'WhatsAppNetworkError';\n this.cause = cause;\n }\n}\n\nexport class WhatsAppUnknownError extends WhatsAppError {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'WhatsAppUnknownError';\n this.cause = cause;\n }\n}\n\n/**\n * Thrown when an API method receives invalid input (e.g., malformed phone number,\n * empty required array). This error is thrown client-side before any API call is made.\n */\nexport class WhatsAppValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WhatsAppValidationError';\n }\n}\n\n/**\n * Determines if the error is a Meta API error response\n * @param error Any error object to check\n * @returns Type guard indicating if error is a Meta API error\n */\nexport function isMetaError(error: any): error is MetaError {\n if (error == null || typeof error !== 'object') return false;\n if (!('error' in error) || typeof error.error !== 'object' || error.error == null) return false;\n\n const metaError = error.error as Record<string, unknown>;\n\n if (typeof metaError.message !== 'string') return false;\n if (typeof metaError.type !== 'string') return false;\n if (typeof metaError.code !== 'number') return false;\n if (typeof metaError.fbtrace_id !== 'string') return false;\n\n if ('error_data' in metaError && metaError.error_data != null) {\n if (typeof metaError.error_data !== 'object') return false;\n const errorData = metaError.error_data as Record<string, unknown>;\n if ('messaging_product' in errorData && errorData.messaging_product !== 'whatsapp') return false;\n if ('details' in errorData && typeof errorData.details !== 'string') return false;\n }\n\n if ('error_subcode' in metaError && typeof metaError.error_subcode !== 'number') return false;\n\n return true;\n}\n\nexport function isWhatsAppApiErrorResponse(error: any): error is MetaError & { error: { code: WhatsAppErrorCode } } {\n return isMetaError(error) && isWhatsAppErrorCode(error.error.code);\n}\n\nexport function isWhatsAppAuthorizationError(error: unknown): error is WhatsAppAuthorizationError {\n return error instanceof WhatsAppAuthorizationError;\n}\n\nexport function isWhatsAppThrottlingError(error: unknown): error is WhatsAppThrottlingError {\n return error instanceof WhatsAppThrottlingError;\n}\n\nexport function isWhatsAppIntegrityError(error: unknown): error is WhatsAppIntegrityError {\n return error instanceof WhatsAppIntegrityError;\n}\n\nexport function isWhatsAppSendMessageError(error: unknown): error is WhatsAppSendMessageError {\n return error instanceof WhatsAppSendMessageError;\n}\n\nexport function isWhatsAppFlowError(error: unknown): error is WhatsAppFlowError {\n return error instanceof WhatsAppFlowError;\n}\n\nexport function isWhatsAppBlockUserError(error: unknown): error is WhatsAppBlockUserError {\n return error instanceof WhatsAppBlockUserError;\n}\n\nexport function isWhatsAppCallingError(error: unknown): error is WhatsAppCallingError {\n return error instanceof WhatsAppCallingError;\n}\n\nexport function isWhatsAppGroupError(error: unknown): error is WhatsAppGroupError {\n return error instanceof WhatsAppGroupError;\n}\n\nexport function normalizeMetaError(errorData: unknown, statusCode?: number): MetaError {\n if (isMetaError(errorData)) return errorData;\n\n let message = 'Unknown error occurred';\n if (errorData && typeof errorData === 'object' && 'message' in errorData) {\n const candidate = (errorData as { message?: unknown }).message;\n if (typeof candidate === 'string') message = candidate;\n }\n\n return {\n name: 'MetaError',\n message,\n error: {\n message,\n type: 'UnknownError',\n code: typeof statusCode === 'number' ? statusCode : 500,\n fbtrace_id: '',\n },\n };\n}\n","// @ts-nocheck\nimport { inspect } from 'node:util';\nimport type { LoggerInterface } from '../types/logger';\n\nexport default class Logger implements LoggerInterface {\n private name: string;\n private debug: boolean;\n\n constructor(name: string, debug: boolean = false) {\n this.name = name;\n this.debug = debug;\n }\n\n private formatData(data: any[]): string {\n return data\n .map((item) => (typeof item === 'object' ? inspect(item, { depth: null, colors: true }) : item))\n .join(' ');\n }\n\n log(...data: any[]) {\n if (this.debug) {\n let prefix = `[ ${Date.now()} ]`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.log(prefix, ': ', this.formatData(data));\n }\n }\n\n error(...data: any[]) {\n let prefix = `[ ${Date.now()} ] - ERROR`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.error(prefix, ': ', this.formatData(data));\n }\n\n warn(...data: any[]) {\n if (this.debug) {\n let prefix = `[ ${Date.now()} ] - WARN`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.warn(prefix, ': ', this.formatData(data));\n }\n }\n\n info(...data: any[]) {\n if (this.debug) {\n let prefix = `[ ${Date.now()} ] - INFO`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.info(prefix, ': ', this.formatData(data));\n }\n }\n}\n","export const objectToQueryString = (params: Record<string, any>): string => {\n if (!params || Object.keys(params).length === 0) {\n return '';\n }\n\n const queryParts: string[] = [];\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n const encodedKey = encodeURIComponent(key);\n const encodedValue = encodeURIComponent(String(value));\n queryParts.push(`${encodedKey}=${encodedValue}`);\n }\n }\n\n return queryParts.length > 0 ? `?${queryParts.join('&')}` : '';\n};\n","/**\n * WhatsApp Flow Encryption/Decryption Utilities\n * Handles encryption and decryption of WhatsApp Flow requests and responses\n * @see https://developers.facebook.com/docs/whatsapp/cloud-api/reference/whatsapp-business-encryption/\n */\n\nimport crypto from 'node:crypto';\n\nimport type { FlowEndpointRequest } from '../api/flow';\nimport type { WabaConfigType } from '../types/config';\nimport Logger from './logger';\n\nconst LIB_NAME = 'FLOW_ENCRYPTION_UTILS';\nconst LOGGER = new Logger(LIB_NAME, process.env.DEBUG === 'true');\n\n/**\n * Environment model for encryption keys\n */\nexport type EncryptionKeyPair = {\n passphrase: string;\n privateKey: string;\n publicKey: string;\n};\n\n/**\n * Validates that the code is running in a Node.js environment\n * @throws {Error} If not running in Node.js environment\n */\nfunction validateNodeEnvironment(): void {\n // Check if crypto module exists and has required methods\n if (!crypto || typeof crypto.generateKeyPairSync !== 'function') {\n const error = new Error(\n 'This utility requires Node.js environment with crypto module. ' +\n 'It cannot be used in browser or edge runtime environments.',\n );\n LOGGER.error('Environment validation failed:', error);\n throw error;\n }\n\n // Check if running in browser\n if (typeof window !== 'undefined') {\n const error = new Error(\n 'This utility cannot run in a browser environment. ' +\n 'Please use it in a Node.js server environment only.',\n );\n LOGGER.error('Browser environment detected:', error);\n throw error;\n }\n\n // Check Node.js version (crypto.generateKeyPairSync requires Node.js 10.12.0+)\n if (process.versions?.node) {\n const nodeVersion = process.versions.node.split('.').map(Number);\n const major = nodeVersion[0] ?? 0;\n const minor = nodeVersion[1] ?? 0;\n\n if (major < 10 || (major === 10 && minor < 12)) {\n const error = new Error(\n `Node.js version ${process.versions.node} is not supported. ` +\n 'Please upgrade to Node.js 10.12.0 or higher.',\n );\n LOGGER.error('Node.js version check failed:', error);\n throw error;\n }\n }\n}\n\n/**\n * Generates RSA key pair for WhatsApp Business Flow API encryption\n *\n * This function generates a 2048-bit RSA key pair with:\n * - Public key in SPKI format (PEM)\n * - Private key in PKCS#8 format (PEM) encrypted with AES-256-CBC\n *\n * @param passphrase - Passphrase to encrypt the private key. If not provided, uses FLOW_API_PASSPHRASE from environment\n * @returns Object containing passphrase, privateKey, and publicKey\n * @throws {Error} If passphrase is empty or key generation fails\n * @throws {Error} If not running in Node.js environment\n *\n * @example\n * ```typescript\n * import { WhatsApp } from 'meta-cloud-api';\n *\n * const wa = new WhatsApp();\n *\n * try {\n * // Uses FLOW_API_PASSPHRASE from environment\n * const keys = wa.generateEncryption();\n * console.log('Public Key:', keys.publicKey);\n * console.log('Private Key:', keys.privateKey);\n *\n * // Or provide custom passphrase\n * const customKeys = wa.generateEncryption('my-secret-passphrase');\n * } catch (error) {\n * console.error('Failed to generate keys:', error.message);\n * }\n * ```\n */\nexport function generateEncryption(passphrase?: string): EncryptionKeyPair {\n LOGGER.info('[generateEncryption] Starting key pair generation');\n\n // Validate environment first\n validateNodeEnvironment();\n\n // Get passphrase from parameter or environment variable\n const effectivePassphrase = passphrase || process.env.FLOW_API_PASSPHRASE;\n\n // Validate passphrase\n if (!effectivePassphrase || effectivePassphrase.trim().length === 0) {\n const error = new Error(\n 'Passphrase is empty. Please provide a passphrase as parameter or set FLOW_API_PASSPHRASE environment variable.',\n );\n LOGGER.error('[generateEncryption] Passphrase validation failed:', error);\n throw error;\n }\n\n // Warn if passphrase is too short\n if (effectivePassphrase.length < 8) {\n LOGGER.warn(\n '[generateEncryption] Passphrase is shorter than 8 characters. Consider using a longer passphrase for better security.',\n );\n }\n\n try {\n LOGGER.info('[generateEncryption] Generating 2048-bit RSA key pair');\n\n // Generate RSA key pair\n const keyPair = crypto.generateKeyPairSync('rsa', {\n modulusLength: 2048,\n publicKeyEncoding: {\n type: 'spki',\n format: 'pem',\n },\n privateKeyEncoding: {\n type: 'pkcs8',\n format: 'pem',\n cipher: 'aes-256-cbc',\n passphrase: effectivePassphrase,\n },\n });\n\n LOGGER.info('[generateEncryption] Key pair generated successfully');\n\n return {\n passphrase: effectivePassphrase,\n privateKey: keyPair.privateKey,\n publicKey: keyPair.publicKey,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const generationError = new Error(`Failed to generate key pair: ${errorMessage}`);\n LOGGER.error('[generateEncryption] Key generation failed:', generationError);\n throw generationError;\n }\n}\n\n/**\n * Decrypt a WhatsApp Flow request\n * @param body - Encrypted request body containing encrypted_aes_key, encrypted_flow_data, and initial_vector\n * @param config - WABA configuration containing FLOW_API_PRIVATE_PEM and FLOW_API_PASSPHRASE\n * @returns Decrypted flow request body, AES key buffer, and initial vector buffer\n * @throws {Error} If required encryption properties are missing or decryption fails\n */\nexport function decryptFlowRequest(\n body: any,\n config: WabaConfigType,\n): {\n decryptedBody: FlowEndpointRequest;\n aesKeyBuffer: Buffer;\n initialVectorBuffer: Buffer;\n} {\n LOGGER.info('[decryptFlowRequest] Starting Flow request decryption');\n\n // Validate required environment variables\n if (!config.FLOW_API_PRIVATE_PEM || config.FLOW_API_PRIVATE_PEM.trim() === '') {\n const error = new Error(\n 'Missing FLOW_API_PRIVATE_PEM. Please set the FLOW_API_PRIVATE_PEM environment variable or pass privatePem via config.',\n );\n LOGGER.error('[decryptFlowRequest] Configuration error:', error);\n throw error;\n }\n\n if (!config.FLOW_API_PASSPHRASE || config.FLOW_API_PASSPHRASE.trim() === '') {\n const error = new Error(\n 'Missing FLOW_API_PASSPHRASE. Please set the FLOW_API_PASSPHRASE environment variable or pass passphrase via config.',\n );\n LOGGER.error('[decryptFlowRequest] Configuration error:', error);\n throw error;\n }\n\n LOGGER.info('[decryptFlowRequest] Configuration validated');\n\n const { encrypted_aes_key, encrypted_flow_data, initial_vector } = body;\n\n if (!encrypted_aes_key || !encrypted_flow_data || !initial_vector) {\n LOGGER.error('[decryptFlowRequest] Missing required encryption properties in request body');\n throw new Error('Missing required encryption properties');\n }\n\n LOGGER.info('[decryptFlowRequest] Request body validated');\n\n // Handle both escaped and unescaped newlines\n let privatePem = config.FLOW_API_PRIVATE_PEM;\n if (privatePem.includes('\\\\n')) {\n privatePem = privatePem.replace(/\\\\n/g, '\\n');\n }\n\n const passphrase = config.FLOW_API_PASSPHRASE;\n\n const isPKCS1 = privatePem.includes('-----BEGIN RSA PRIVATE KEY-----');\n const isPKCS8 =\n privatePem.includes('-----BEGIN PRIVATE KEY-----') ||\n privatePem.includes('-----BEGIN ENCRYPTED PRIVATE KEY-----');\n\n LOGGER.info('[decryptFlowRequest] Loading private key', {\n format: isPKCS8 ? 'PKCS#8' : isPKCS1 ? 'PKCS#1' : 'Unknown',\n });\n\n let privateKey: crypto.KeyObject;\n try {\n // Try to create private key with passphrase\n if (passphrase) {\n privateKey = crypto.createPrivateKey({\n key: privatePem,\n format: 'pem',\n passphrase,\n });\n } else {\n privateKey = crypto.createPrivateKey(privatePem);\n }\n LOGGER.info('[decryptFlowRequest] Private key loaded successfully');\n } catch (error) {\n LOGGER.error('[decryptFlowRequest] Failed to load private key (first attempt):', {\n error: error instanceof Error ? error.message : error,\n hasPassphrase: !!passphrase,\n format: isPKCS8 ? 'PKCS#8' : isPKCS1 ? 'PKCS#1' : 'Unknown',\n });\n\n // If PKCS#1 key failed, try to convert it to PKCS#8 format automatically\n if (isPKCS1 && passphrase) {\n try {\n LOGGER.info('[decryptFlowRequest] Attempting to convert PKCS#1 to PKCS#8 format');\n\n // First, load the PKCS#1 key with passphrase\n const pkcs1Key = crypto.createPrivateKey({\n key: privatePem,\n format: 'pem',\n passphrase,\n });\n\n // Export it as PKCS#8 with the same passphrase\n const pkcs8Pem = pkcs1Key.export({\n type: 'pkcs8',\n format: 'pem',\n cipher: 'aes-256-cbc',\n passphrase,\n });\n\n // Now create the private key from PKCS#8 format\n privateKey = crypto.createPrivateKey({\n key: pkcs8Pem as string,\n format: 'pem',\n passphrase,\n });\n\n LOGGER.info('[decryptFlowRequest] Successfully converted PKCS#1 to PKCS#8 and loaded private key');\n } catch (conversionError) {\n LOGGER.error('[decryptFlowRequest] Failed to convert PKCS#1 to PKCS#8:', {\n error: conversionError instanceof Error ? conversionError.message : conversionError,\n });\n\n // Provide helpful error message\n let errorMessage = `Failed to parse private key. Error: ${error instanceof Error ? error.message : error}`;\n errorMessage += '\\n\\nYour key is in PKCS#1 format with unsupported encryption (DES-EDE3-CBC).';\n errorMessage += '\\nPlease convert it to PKCS#8 format using:';\n errorMessage += '\\n openssl pkcs8 -topk8 -inform PEM -outform PEM -in old_key.pem -out new_key.pem';\n\n throw new Error(errorMessage);\n }\n } else {\n // Provide helpful error message\n let errorMessage = `Failed to parse private key. Error: ${error instanceof Error ? error.message : error}`;\n\n if (isPKCS1) {\n errorMessage += '\\n\\nYour key is in PKCS#1 format (-----BEGIN RSA PRIVATE KEY-----).';\n errorMessage += '\\nPlease convert it to PKCS#8 format using:';\n errorMessage += '\\n openssl pkcs8 -topk8 -inform PEM -outform PEM -in old_key.pem -out new_key.pem';\n } else if (!isPKCS8) {\n errorMessage += '\\n\\nYour key format is not recognized. Please ensure it is in PKCS#8 format.';\n }\n\n throw new Error(errorMessage);\n }\n }\n\n let decryptedAesKey: Buffer;\n\n try {\n LOGGER.info('[decryptFlowRequest] Decrypting AES key with RSA private key');\n decryptedAesKey = crypto.privateDecrypt(\n {\n key: privateKey,\n padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,\n oaepHash: 'sha256',\n },\n Buffer.from(encrypted_aes_key, 'base64'),\n );\n LOGGER.info('[decryptFlowRequest] AES key decrypted successfully');\n } catch (error) {\n LOGGER.error('[decryptFlowRequest] Failed to decrypt AES key:', error);\n throw new Error('Failed to decrypt the request. Please verify your private key.');\n }\n\n const flowDataBuffer = Buffer.from(encrypted_flow_data, 'base64');\n const initialVectorBuffer = Buffer.from(initial_vector, 'base64');\n\n const TAG_LENGTH = 16;\n const encrypted_flow_data_body = flowDataBuffer.subarray(0, -TAG_LENGTH);\n const encrypted_flow_data_tag = flowDataBuffer.subarray(-TAG_LENGTH);\n\n LOGGER.info('[decryptFlowRequest] Decrypting flow data with AES-128-GCM');\n\n const decipher = crypto.createDecipheriv('aes-128-gcm', decryptedAesKey, initialVectorBuffer);\n decipher.setAuthTag(encrypted_flow_data_tag);\n\n const decryptedJSONString = Buffer.concat([decipher.update(encrypted_flow_data_body), decipher.final()]).toString(\n 'utf-8',\n );\n\n LOGGER.info('[decryptFlowRequest] Flow request decrypted successfully');\n\n return {\n decryptedBody: JSON.parse(decryptedJSONString),\n aesKeyBuffer: decryptedAesKey,\n initialVectorBuffer,\n };\n}\n\n/**\n * Encrypt a WhatsApp Flow response\n * @param response - Response object to encrypt\n * @param aesKeyBuffer - AES key buffer from the decrypted request\n * @param initialVectorBuffer - Initial vector buffer from the decrypted request\n * @returns Base64-encoded encrypted response\n * @throws {Error} If encryption fails\n */\nexport function encryptFlowResponse(response: any, aesKeyBuffer: Buffer, initialVectorBuffer: Buffer): string {\n LOGGER.info('[encryptFlowResponse] Starting Flow response encryption');\n\n const flipped_iv: number[] = [];\n for (const pair of Array.from(initialVectorBuffer.entries())) {\n flipped_iv.push(~pair[1]);\n }\n\n try {\n LOGGER.info('[encryptFlowResponse] Encrypting response with AES-128-GCM');\n const cipher = crypto.createCipheriv('aes-128-gcm', aesKeyBuffer, Buffer.from(flipped_iv));\n const encryptedResponse = Buffer.concat([\n cipher.update(JSON.stringify(response || {}), 'utf-8'),\n cipher.final(),\n cipher.getAuthTag(),\n ]).toString('base64');\n\n LOGGER.info('[encryptFlowResponse] Flow response encrypted successfully');\n\n return encryptedResponse;\n } catch (error) {\n LOGGER.error('[encryptFlowResponse] Response encryption failed:', error);\n throw new Error('Failed to encrypt response. Internal server error.');\n }\n}\n","import {\n FlowActionEnum,\n type FlowDataExchangeRequest,\n type FlowEndpointRequest,\n type FlowErrorNotificationRequest,\n type FlowHealthCheckRequest,\n} from '../api/flow/types';\n\n/**\n * Helper function to check if a value is an object\n * @param value The value to check\n * @returns True if the value is a non-null object\n */\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Helper function to check if a value is a string\n * @param value The value to check\n * @returns True if the value is a string\n */\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n// Array of allowed action types for data exchange requests\nconst DATA_EXCHANGE_ACTIONS = [FlowActionEnum.DATA_EXCHANGE, FlowActionEnum.INIT, FlowActionEnum.BACK] as const;\n\n// Array of allowed action types for error notification requests\nconst ERROR_ACTIONS = [FlowActionEnum.DATA_EXCHANGE, FlowActionEnum.INIT] as const;\n\n/**\n * Type guard to check if a request is a Data Exchange request\n * Validates the request structure according to the Flow API specifications\n *\n * @param request The Flow endpoint request to check\n * @returns True if the request is a valid Data Exchange request, false otherwise\n */\nexport function isFlowDataExchangeRequest(request: FlowEndpointRequest): request is FlowDataExchangeRequest & {\n action: (typeof DATA_EXCHANGE_ACTIONS)[number];\n screen?: string;\n flow_token: string;\n data?: Record<string, any>;\n} {\n // Check for basic required fields\n if (!('flow_token' in request && isString(request.flow_token) && 'action' in request)) {\n return false;\n }\n\n const { action, version, screen, data } = request;\n\n // Validate API version\n const hasValidVersion = version === '3.0';\n\n // Check if the action is one of the allowed actions for data exchange\n const hasValidAction = DATA_EXCHANGE_ACTIONS.includes(action as any);\n\n // Screen is optional, but when present must be a string and not 'SUCCESS'\n const hasValidScreen = typeof screen === 'undefined' || (isString(screen) && screen !== 'SUCCESS');\n\n // Data is required except for DATA_EXCHANGE action\n const hasValidData = action === FlowActionEnum.DATA_EXCHANGE || isObject(data);\n\n // All conditions must be met for a valid data exchange request\n return hasValidVersion && hasValidAction && hasValidScreen && hasValidData;\n}\n\n/**\n * Type guard to check if a request is an Error Notification request\n * Validates the request structure according to the Flow API error specifications\n *\n * @param request The Flow endpoint request to check\n * @returns True if the request is a valid Error Notification request, false otherwise\n */\nexport function isFlowErrorRequest(request: FlowEndpointRequest): request is FlowErrorNotificationRequest & {\n action: (typeof ERROR_ACTIONS)[number];\n screen: string;\n flow_token: string;\n data: {\n error: string;\n error_message: string;\n };\n} {\n // Check for basic required fields\n if (!('flow_token' in request && isString(request.flow_token) && 'action' in request)) {\n return false;\n }\n\n const { action, screen, data } = request;\n\n // Check if the action is one of the allowed actions for error notifications\n const hasValidAction = ERROR_ACTIONS.includes(action as any);\n\n // Screen is required for error notifications\n const hasValidScreen = isString(screen);\n\n // Validate error data structure\n const hasValidData =\n isObject(data) &&\n 'error_key' in data &&\n isString(data.error) &&\n 'error_message' in data &&\n isString(data.error_message);\n\n // All conditions must be met for a valid error notification request\n return hasValidAction && hasValidScreen && hasValidData;\n}\n\n/**\n * Type guard to check if a request is a Ping (health check) request\n * Simple validation for health check endpoints in the Flow API\n *\n * @param request The Flow endpoint request to check\n * @returns True if the request is a Ping request, false otherwise\n */\nexport function isFlowPingRequest(request: FlowEndpointRequest): request is FlowHealthCheckRequest {\n // A ping request only requires the 'action' field with value 'ping'\n return 'action' in request && request.action === 'ping';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/utils/buildFieldsQueryString.ts","../../src/utils/configTable.ts","../../src/utils/isMetaError.ts","../../src/utils/customerServiceWindow.ts","../../src/utils/logger.ts","../../src/utils/objectToQueryString.ts","../../src/utils/rateLimit.ts","../../src/utils/runtime.ts","../../src/utils/flowEncryptionUtils.ts","../../src/utils/flowTypeGuards.ts"],"sourcesContent":["export function buildFieldsQueryString(fields?: string[] | string): string {\n if (!fields) return '';\n\n let fieldParams = '';\n\n if (Array.isArray(fields)) {\n fieldParams = fields.join(',');\n } else if (typeof fields === 'string') {\n fieldParams = fields;\n } else {\n fieldParams = Object.entries(fields)\n .filter(([_, value]) => value)\n .map(([key]) => key)\n .join(',');\n }\n\n return fieldParams ? `?fields=${fieldParams}` : '';\n}\n","import type { WabaConfigType } from '../types/config';\nimport { WabaConfigEnum } from '../types/enums';\n\n/**\n * Formats configuration as a terminal table\n * @param config - The WABA configuration object\n * @param apiName - The name of the API being initialized\n * @returns Formatted table string\n */\nexport function formatConfigTable(config: WabaConfigType): string {\n const configData = [\n ['App ID', config[WabaConfigEnum.AppId] || 'Not Set'],\n ['Phone Number ID', config[WabaConfigEnum.PhoneNumberId]?.toString() || 'Not Set'],\n ['Business Account ID', config[WabaConfigEnum.BusinessAcctId] || 'Not Set'],\n ['API Version', config[WabaConfigEnum.APIVersion] || 'Not Set'],\n [\n 'Access Token',\n config[WabaConfigEnum.AccessToken]\n ? `${config[WabaConfigEnum.AccessToken].substring(0, 20)}...`\n : 'Not Set',\n ],\n ['Webhook Endpoint', config[WabaConfigEnum.WebhookEndpoint] || 'Not Set'],\n [\n 'Webhook Verification Token',\n config[WabaConfigEnum.WebhookVerificationToken]\n ? `${config[WabaConfigEnum.WebhookVerificationToken].substring(0, 10)}...`\n : 'Not Set',\n ],\n ['Listener Port', config[WabaConfigEnum.ListenerPort]?.toString() || 'Not Set'],\n ['Debug Mode', config[WabaConfigEnum.Debug] ? 'Enabled' : 'Disabled'],\n ['Max Retries', config[WabaConfigEnum.MaxRetriesAfterWait]?.toString() || 'Not Set'],\n [\n 'Request Timeout',\n config[WabaConfigEnum.RequestTimeout] ? `${config[WabaConfigEnum.RequestTimeout]}ms` : 'Not Set',\n ],\n ['Private PEM', config[WabaConfigEnum.PrivatePem] ? 'Configured' : 'Not Set'],\n ['Passphrase', config[WabaConfigEnum.Passphrase] ? 'Configured' : 'Not Set'],\n ];\n\n // Calculate column widths\n const maxKeyLength = Math.max(...configData.map(([key]) => key?.length || 0));\n const maxValueLength = Math.max(...configData.map(([, value]) => value?.length || 0));\n\n const keyWidth = Math.max(maxKeyLength, 20);\n const valueWidth = Math.max(maxValueLength, 30);\n\n // Create table\n const horizontalLine = `┌${'─'.repeat(keyWidth + 2)}┬${'─'.repeat(valueWidth + 2)}┐`;\n const separator = `├${'─'.repeat(keyWidth + 2)}┼${'─'.repeat(valueWidth + 2)}┤`;\n const bottomLine = `└${'─'.repeat(keyWidth + 2)}┴${'─'.repeat(valueWidth + 2)}┘`;\n\n const header = `│ ${'Configuration'.padEnd(keyWidth)} │ ${'Value'.padEnd(valueWidth)} │`;\n\n const rows = configData.map(([key, value]) => `│ ${key?.padEnd(keyWidth)} │ ${value?.padEnd(valueWidth)} │`);\n\n return [horizontalLine, header, separator, ...rows, bottomLine].join('\\n');\n}\n","import type { RateLimitInfo } from './rateLimit';\n\nexport type MetaErrorData = {\n message: string;\n type: string;\n code: number;\n error_data?: {\n messaging_product?: 'whatsapp';\n details?: string;\n };\n error_subcode?: number;\n fbtrace_id: string;\n};\n\nexport interface MetaError extends Error {\n error: MetaErrorData;\n}\n\nexport const WHATSAPP_ERROR_CODES = [\n 0, 1, 2, 3, 4, 10, 33, 100, 190, 200, 299, 368, 613, 80007, 130429, 130472, 130497, 131000, 131005, 131008, 131009,\n 131016, 131020, 131021, 131026, 131030, 131031, 131037, 131041, 131042, 131044, 131045, 131047, 131048, 131049,\n 131050, 131051, 131052, 131053, 131055, 131056, 131057, 131059, 131061, 131062, 131063, 131201, 131202, 131203,\n 131204, 131207, 131208, 131209, 131210, 131211, 131212, 131213, 131214, 131215, 132000, 132001, 132005, 132007,\n 132008, 132012, 132015, 132016, 132068, 132069, 133000, 133004, 133005, 133006, 133008, 133009, 133010, 133015,\n 133016, 134011, 134100, 134101, 134102, 135000, 137000, 138000, 138001, 138002, 138003, 138004, 138005, 138006,\n 138007, 138009, 138012, 138013, 138018, 139000, 139001, 139002, 139003, 139004, 139100, 139101, 139102, 139103,\n 147005, 200005, 200006, 200007, 1752041, 2388001, 2388012, 2388019, 2388040, 2388047, 2388072, 2388073, 2388091,\n 2388093, 2388103, 2388293, 2388299, 2494100, 2494191, 2593079, 2593085, 2593107, 2593108,\n] as const;\n\nconst WHATSAPP_ERROR_CODE_SET = new Set<number>(WHATSAPP_ERROR_CODES);\n\nexport type ApiPermissionErrorCode = number;\nexport type WhatsAppErrorCode = (typeof WHATSAPP_ERROR_CODES)[number] | ApiPermissionErrorCode;\n\nexport const AUTHORIZATION_ERROR_CODES = [0, 3, 10, 190] as const;\nexport const THROTTLING_ERROR_CODES = [4, 80007, 130429, 131048, 131056] as const;\nexport const INTEGRITY_ERROR_CODES = [368, 130497, 131031] as const;\nexport const SEND_MESSAGE_ERROR_CODES = [\n 130472, 131000, 131005, 131008, 131009, 131016, 131021, 131026, 131030, 131042, 131044, 131045, 131047, 131050,\n 131051, 131052, 131053, 131056, 131057, 131048, 131061, 131062, 131063, 132000, 132001, 132005, 132007, 132008,\n 132012, 132015, 132016, 132068, 132069, 135000, 137000,\n] as const;\nexport const FLOW_ERROR_CODES = [139000, 139001, 139002, 139003, 139004] as const;\nexport const BLOCK_USER_ERROR_CODES = [139100, 139101, 139102, 139103] as const;\nexport const CALLING_ERROR_CODES = [\n 138000, 138001, 138002, 138003, 138004, 138005, 138006, 138007, 138009, 138012, 138013, 138018, 613,\n] as const;\nexport const GROUP_ERROR_CODES = [\n 131020, 131041, 131059, 131201, 131202, 131203, 131204, 131207, 131208, 131209, 131210, 131211, 131212, 131213,\n 131214, 131215,\n] as const;\n\nconst AUTHORIZATION_ERROR_CODE_SET = new Set<number>(AUTHORIZATION_ERROR_CODES);\nconst THROTTLING_ERROR_CODE_SET = new Set<number>(THROTTLING_ERROR_CODES);\nconst INTEGRITY_ERROR_CODE_SET = new Set<number>(INTEGRITY_ERROR_CODES);\nconst SEND_MESSAGE_ERROR_CODE_SET = new Set<number>(SEND_MESSAGE_ERROR_CODES);\nconst FLOW_ERROR_CODE_SET = new Set<number>(FLOW_ERROR_CODES);\nconst BLOCK_USER_ERROR_CODE_SET = new Set<number>(BLOCK_USER_ERROR_CODES);\nconst CALLING_ERROR_CODE_SET = new Set<number>(CALLING_ERROR_CODES);\nconst GROUP_ERROR_CODE_SET = new Set<number>(GROUP_ERROR_CODES);\n\nexport function isWhatsAppErrorCode(code: number): code is WhatsAppErrorCode {\n if (isApiPermissionErrorCode(code)) return true;\n return WHATSAPP_ERROR_CODE_SET.has(code);\n}\n\nexport function isApiPermissionErrorCode(code: number): code is ApiPermissionErrorCode {\n return code >= 200 && code < 300;\n}\n\nexport function isAuthorizationErrorCode(\n code: number,\n): code is ApiPermissionErrorCode | (typeof AUTHORIZATION_ERROR_CODES)[number] {\n return isApiPermissionErrorCode(code) || AUTHORIZATION_ERROR_CODE_SET.has(code);\n}\n\nexport function isThrottlingErrorCode(code: number): code is (typeof THROTTLING_ERROR_CODES)[number] {\n return THROTTLING_ERROR_CODE_SET.has(code);\n}\n\nexport function isIntegrityErrorCode(code: number): code is (typeof INTEGRITY_ERROR_CODES)[number] {\n return INTEGRITY_ERROR_CODE_SET.has(code);\n}\n\nexport function isSendMessageErrorCode(code: number): code is (typeof SEND_MESSAGE_ERROR_CODES)[number] {\n return SEND_MESSAGE_ERROR_CODE_SET.has(code);\n}\n\nexport function isFlowErrorCode(code: number): code is (typeof FLOW_ERROR_CODES)[number] {\n return FLOW_ERROR_CODE_SET.has(code);\n}\n\nexport function isBlockUserErrorCode(code: number): code is (typeof BLOCK_USER_ERROR_CODES)[number] {\n return BLOCK_USER_ERROR_CODE_SET.has(code);\n}\n\nexport function isCallingErrorCode(code: number): code is (typeof CALLING_ERROR_CODES)[number] {\n return CALLING_ERROR_CODE_SET.has(code);\n}\n\nexport function isGroupErrorCode(code: number): code is (typeof GROUP_ERROR_CODES)[number] {\n return GROUP_ERROR_CODE_SET.has(code);\n}\n\nexport class WhatsAppError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WhatsAppError';\n }\n}\n\nexport class WhatsAppApiError extends WhatsAppError {\n readonly error: MetaErrorData;\n readonly statusCode?: number;\n /**\n * Rate limit headers of the failed response, when it carried any. Set by the SDK's requester;\n * use `rateLimit.retryDelayMs` to reschedule a throttled call.\n */\n rateLimit?: RateLimitInfo;\n\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message);\n this.name = 'WhatsAppApiError';\n this.error = error;\n this.statusCode = statusCode;\n }\n}\n\nexport class WhatsAppAuthorizationError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppAuthorizationError';\n }\n}\n\nexport class WhatsAppThrottlingError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppThrottlingError';\n }\n}\n\nexport class WhatsAppIntegrityError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppIntegrityError';\n }\n}\n\nexport class WhatsAppSendMessageError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppSendMessageError';\n }\n}\n\nexport class WhatsAppFlowError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppFlowError';\n }\n}\n\nexport class WhatsAppBlockUserError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppBlockUserError';\n }\n}\n\nexport class WhatsAppCallingError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppCallingError';\n }\n}\n\nexport class WhatsAppGroupError extends WhatsAppApiError {\n constructor(message: string, error: MetaErrorData, statusCode?: number) {\n super(message, error, statusCode);\n this.name = 'WhatsAppGroupError';\n }\n}\n\nexport function createWhatsAppApiError(error: MetaErrorData, statusCode?: number): WhatsAppApiError {\n const code = error.code;\n\n if (isAuthorizationErrorCode(code)) {\n return new WhatsAppAuthorizationError(error.message, error, statusCode);\n }\n if (isThrottlingErrorCode(code)) {\n return new WhatsAppThrottlingError(error.message, error, statusCode);\n }\n if (isIntegrityErrorCode(code)) {\n return new WhatsAppIntegrityError(error.message, error, statusCode);\n }\n if (isSendMessageErrorCode(code)) {\n return new WhatsAppSendMessageError(error.message, error, statusCode);\n }\n if (isFlowErrorCode(code)) {\n return new WhatsAppFlowError(error.message, error, statusCode);\n }\n if (isBlockUserErrorCode(code)) {\n return new WhatsAppBlockUserError(error.message, error, statusCode);\n }\n if (isCallingErrorCode(code)) {\n return new WhatsAppCallingError(error.message, error, statusCode);\n }\n if (isGroupErrorCode(code)) {\n return new WhatsAppGroupError(error.message, error, statusCode);\n }\n\n return new WhatsAppApiError(error.message, error, statusCode);\n}\n\nexport class WhatsAppNetworkError extends WhatsAppError {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'WhatsAppNetworkError';\n this.cause = cause;\n }\n}\n\nexport class WhatsAppUnknownError extends WhatsAppError {\n readonly cause?: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'WhatsAppUnknownError';\n this.cause = cause;\n }\n}\n\n/**\n * Thrown when an API method receives invalid input (e.g., malformed phone number,\n * empty required array). This error is thrown client-side before any API call is made.\n */\nexport class WhatsAppValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'WhatsAppValidationError';\n }\n}\n\n/**\n * Determines if the error is a Meta API error response\n * @param error Any error object to check\n * @returns Type guard indicating if error is a Meta API error\n */\nexport function isMetaError(error: any): error is MetaError {\n if (error == null || typeof error !== 'object') return false;\n if (!('error' in error) || typeof error.error !== 'object' || error.error == null) return false;\n\n const metaError = error.error as Record<string, unknown>;\n\n if (typeof metaError.message !== 'string') return false;\n if (typeof metaError.type !== 'string') return false;\n if (typeof metaError.code !== 'number') return false;\n if (typeof metaError.fbtrace_id !== 'string') return false;\n\n if ('error_data' in metaError && metaError.error_data != null) {\n if (typeof metaError.error_data !== 'object') return false;\n const errorData = metaError.error_data as Record<string, unknown>;\n if ('messaging_product' in errorData && errorData.messaging_product !== 'whatsapp') return false;\n if ('details' in errorData && typeof errorData.details !== 'string') return false;\n }\n\n if ('error_subcode' in metaError && typeof metaError.error_subcode !== 'number') return false;\n\n return true;\n}\n\nexport function isWhatsAppApiErrorResponse(error: any): error is MetaError & { error: { code: WhatsAppErrorCode } } {\n return isMetaError(error) && isWhatsAppErrorCode(error.error.code);\n}\n\nexport function isWhatsAppAuthorizationError(error: unknown): error is WhatsAppAuthorizationError {\n return error instanceof WhatsAppAuthorizationError;\n}\n\nexport function isWhatsAppThrottlingError(error: unknown): error is WhatsAppThrottlingError {\n return error instanceof WhatsAppThrottlingError;\n}\n\nexport function isWhatsAppIntegrityError(error: unknown): error is WhatsAppIntegrityError {\n return error instanceof WhatsAppIntegrityError;\n}\n\nexport function isWhatsAppSendMessageError(error: unknown): error is WhatsAppSendMessageError {\n return error instanceof WhatsAppSendMessageError;\n}\n\nexport function isWhatsAppFlowError(error: unknown): error is WhatsAppFlowError {\n return error instanceof WhatsAppFlowError;\n}\n\nexport function isWhatsAppBlockUserError(error: unknown): error is WhatsAppBlockUserError {\n return error instanceof WhatsAppBlockUserError;\n}\n\nexport function isWhatsAppCallingError(error: unknown): error is WhatsAppCallingError {\n return error instanceof WhatsAppCallingError;\n}\n\nexport function isWhatsAppGroupError(error: unknown): error is WhatsAppGroupError {\n return error instanceof WhatsAppGroupError;\n}\n\nexport function normalizeMetaError(errorData: unknown, statusCode?: number): MetaError {\n if (isMetaError(errorData)) return errorData;\n\n let message = 'Unknown error occurred';\n if (errorData && typeof errorData === 'object' && 'message' in errorData) {\n const candidate = (errorData as { message?: unknown }).message;\n if (typeof candidate === 'string') message = candidate;\n }\n\n return {\n name: 'MetaError',\n message,\n error: {\n message,\n type: 'UnknownError',\n code: typeof statusCode === 'number' ? statusCode : 500,\n fbtrace_id: '',\n },\n };\n}\n","// Docs: https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/send-messages/\n\nimport { WhatsAppValidationError } from './isMetaError';\n\nconst HOUR_MS = 60 * 60 * 1000;\n\n/**\n * Length of the customer service window: 24 hours.\n *\n * \"When a WhatsApp user messages you or calls you, a 24-hour timer called a customer service window\n * starts. If the user messages or calls you again before the timer expires, the timer resets to\n * 24 hours. [...] When the window closes, you can only send pre-approved template messages.\"\n *\n * @see {@link https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/send-messages/ | Send messages: customer service windows}\n */\nexport const CUSTOMER_SERVICE_WINDOW_MS = 24 * HOUR_MS;\n\n/**\n * SDK fallback length of a free entry point (FEP) window: 72 hours.\n * Prefer the expiry supplied by Meta; this fallback does not establish billing eligibility.\n *\n * @see {@link https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing/ | Pricing: free entry point windows}\n */\nexport const FREE_ENTRY_POINT_WINDOW_MS = 72 * HOUR_MS;\n\n/**\n * Longest free entry point window Meta documents: up to 7 days for conversations started from an\n * ad that clicks to WhatsApp.\n *\n * @see {@link https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing/ | Pricing: free entry point windows}\n */\nexport const MAX_FREE_ENTRY_POINT_WINDOW_MS = 7 * 24 * HOUR_MS;\n\n/**\n * A point in time accepted by the window helpers:\n * - `Date`\n * - `number`: Unix epoch in milliseconds, or in seconds when below `1e11` (before the year 5138 in\n * seconds, before March 1973 in milliseconds), so both `Date.now()` and webhook timestamps work\n * - `string`: a numeric string such as the webhook `messages[].timestamp` (`\"1727856000\"`, Unix\n * seconds, same rule as numbers), or any string `Date.parse` understands (ISO 8601)\n */\nexport type WindowTimestamp = Date | number | string;\n\n/** State of a messaging window at a given instant. */\nexport interface MessagingWindow {\n /** True while the window is open (`now < expiresAt`). */\n isOpen: boolean;\n /** When the window closes, or `null` when there is no window (no inbound message yet). */\n expiresAt: Date | null;\n /** Milliseconds until the window closes, `0` once closed. Never more than the window length. */\n remainingMs: number;\n}\n\nexport interface CustomerServiceWindowOptions {\n /** The instant to evaluate. Defaults to `Date.now()`. */\n now?: WindowTimestamp;\n /**\n * Treat the window as closing this many milliseconds early. Use it to absorb clock drift between\n * your servers and Meta and the time a send spends in flight. Defaults to `0`.\n */\n safetyMarginMs?: number;\n}\n\nexport interface FreeEntryPointWindowOptions extends CustomerServiceWindowOptions {\n /**\n * Window length. Defaults to {@link FREE_ENTRY_POINT_WINDOW_MS} (72 hours). Meta may keep a\n * click-to-WhatsApp ad window open for up to {@link MAX_FREE_ENTRY_POINT_WINDOW_MS} (7 days)\n * without saying how long a given window lasts, so prefer `expiresAt` when you have it.\n */\n durationMs?: number;\n /**\n * Exact expiry when known, for example the status webhook's `conversation.expiration_timestamp`\n * (Unix seconds). Overrides `durationMs`.\n */\n expiresAt?: WindowTimestamp;\n}\n\nconst SECONDS_THRESHOLD = 1e11;\n\nfunction toEpochMs(value: WindowTimestamp, name: string): number {\n let ms: number;\n\n if (value instanceof Date) {\n ms = value.getTime();\n } else if (typeof value === 'number') {\n ms = Math.abs(value) < SECONDS_THRESHOLD ? value * 1000 : value;\n } else if (typeof value === 'string') {\n const trimmed = value.trim();\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) {\n const num = Number(trimmed);\n ms = num < SECONDS_THRESHOLD ? num * 1000 : num;\n } else {\n ms = trimmed === '' ? Number.NaN : Date.parse(trimmed);\n }\n } else {\n ms = Number.NaN;\n }\n\n if (!Number.isFinite(ms) || !Number.isFinite(new Date(ms).getTime())) {\n throw new WhatsAppValidationError(`${name} is not a valid timestamp: ${String(value)}`);\n }\n return ms;\n}\n\nfunction toNonNegativeMs(value: number | undefined, name: string, fallback: number): number {\n if (value === undefined) return fallback;\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {\n throw new WhatsAppValidationError(`${name} must be a non-negative number of milliseconds`);\n }\n return value;\n}\n\nfunction computeWindow(startMs: number, endMs: number, nowMs: number, safetyMarginMs: number): MessagingWindow {\n if (!Number.isFinite(new Date(endMs).getTime())) {\n throw new WhatsAppValidationError('Window expiry is outside the supported timestamp range');\n }\n const lengthMs = Math.max(0, endMs - startMs);\n const effectiveEndMs = endMs - safetyMarginMs;\n // A start in the future means the clocks disagree; never report more than one full window.\n const remainingMs = Math.min(Math.max(0, effectiveEndMs - nowMs), lengthMs);\n return {\n isOpen: remainingMs > 0,\n expiresAt: new Date(endMs),\n remainingMs,\n };\n}\n\nconst CLOSED: MessagingWindow = Object.freeze({ isOpen: false, expiresAt: null, remainingMs: 0 }) as MessagingWindow;\n\n/**\n * Returns the state of the 24-hour customer service window opened by the user's last inbound\n * message (or call).\n *\n * Free-form (non-template) messages can only be sent while it is open; outside it only approved\n * template messages are delivered (Meta rejects others with error `131047`). The window is exactly\n * 24 hours from the user's last message: at `lastInboundAt + 24h` it is closed.\n *\n * Pass the webhook message `timestamp` (Unix seconds string) of the latest message from the user.\n * Messages you send do not extend the window. Pass `null`/`undefined` when the user has never\n * messaged you; that returns a closed window with `expiresAt: null`.\n *\n * A free entry point window does not reopen this window: \"the customer service window is independent\n * of the FEP window, so if the customer service window closes, you will only be able to send template\n * messages.\" Use {@link getFreeEntryPointWindow} for the pricing side.\n *\n * @throws WhatsAppValidationError when a timestamp or `safetyMarginMs` is malformed.\n *\n * @see {@link https://developers.facebook.com/documentation/business-messaging/whatsapp/messages/send-messages/ | Send messages: customer service windows}\n * @see {@link https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing/ | Pricing}\n *\n * @example\n * ```ts\n * const { isOpen, expiresAt } = getCustomerServiceWindow(message.timestamp);\n * if (!isOpen) await sendTemplateInstead();\n * ```\n */\nexport function getCustomerServiceWindow(\n lastInboundAt: WindowTimestamp | null | undefined,\n options: CustomerServiceWindowOptions = {},\n): MessagingWindow {\n const safetyMarginMs = toNonNegativeMs(options.safetyMarginMs, 'safetyMarginMs', 0);\n const nowMs = options.now === undefined ? Date.now() : toEpochMs(options.now, 'now');\n if (lastInboundAt === null || lastInboundAt === undefined) return { ...CLOSED };\n\n const startMs = toEpochMs(lastInboundAt, 'lastInboundAt');\n return computeWindow(startMs, startMs + CUSTOMER_SERVICE_WINDOW_MS, nowMs, safetyMarginMs);\n}\n\n/**\n * True when a free-form (non-template) message can be sent: the customer service window opened by\n * the user's last inbound message is still open. See {@link getCustomerServiceWindow}.\n *\n * @throws WhatsAppValidationError when a timestamp or `safetyMarginMs` is malformed.\n */\nexport function canSendFreeformMessage(\n lastInboundAt: WindowTimestamp | null | undefined,\n options: CustomerServiceWindowOptions = {},\n): boolean {\n return getCustomerServiceWindow(lastInboundAt, options).isOpen;\n}\n\n/**\n * Returns the state of a free entry point (FEP) window.\n *\n * For eligible click-to-WhatsApp ad traffic, replying within the customer service window opens\n * a billing window from the time of your reply. Pass that first reply time as `openedAt`.\n *\n * Meta documents windows lasting up to 7 days for ads that click to WhatsApp. This helper uses\n * a 72-hour fallback estimate. Pass `expiresAt` (the status webhook's\n * `conversation.expiration_timestamp`) when you have it, or set `durationMs`.\n *\n * This is a billing window only. It does not allow free-form messages after the customer service\n * window closes; check {@link canSendFreeformMessage} for that.\n *\n * @throws WhatsAppValidationError when a timestamp, `durationMs` or `safetyMarginMs` is malformed.\n *\n * @see {@link https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing/ | Pricing: free entry point windows}\n */\nexport function getFreeEntryPointWindow(\n openedAt: WindowTimestamp | null | undefined,\n options: FreeEntryPointWindowOptions = {},\n): MessagingWindow {\n const safetyMarginMs = toNonNegativeMs(options.safetyMarginMs, 'safetyMarginMs', 0);\n const durationMs = toNonNegativeMs(options.durationMs, 'durationMs', FREE_ENTRY_POINT_WINDOW_MS);\n const nowMs = options.now === undefined ? Date.now() : toEpochMs(options.now, 'now');\n if (openedAt === null || openedAt === undefined) return { ...CLOSED };\n\n const startMs = toEpochMs(openedAt, 'openedAt');\n const endMs = options.expiresAt === undefined ? startMs + durationMs : toEpochMs(options.expiresAt, 'expiresAt');\n return computeWindow(startMs, endMs, nowMs, safetyMarginMs);\n}\n","import type { LoggerInterface } from '../types/logger';\n\nexport default class Logger implements LoggerInterface {\n private name: string;\n private debugEnabled: boolean;\n\n constructor(name: string, debug: boolean = false) {\n this.name = name;\n this.debugEnabled = debug;\n }\n\n private formatData(data: any[]): string {\n return data.map((item) => (typeof item === 'object' && item !== null ? stringify(item) : item)).join(' ');\n }\n\n log(...data: any[]) {\n if (this.debugEnabled) {\n let prefix = `[ ${Date.now()} ]`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.log(prefix, ': ', this.formatData(data));\n }\n }\n\n error(...data: any[]) {\n let prefix = `[ ${Date.now()} ] - ERROR`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.error(prefix, ': ', this.formatData(data));\n }\n\n warn(...data: any[]) {\n if (this.debugEnabled) {\n let prefix = `[ ${Date.now()} ] - WARN`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.warn(prefix, ': ', this.formatData(data));\n }\n }\n\n info(...data: any[]) {\n if (this.debugEnabled) {\n let prefix = `[ ${Date.now()} ] - INFO`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.info(prefix, ': ', this.formatData(data));\n }\n }\n\n debug(...data: any[]) {\n if (this.debugEnabled) {\n let prefix = `[ ${Date.now()} ] - DEBUG`;\n if (this.name) {\n prefix += ` - ${this.name}`;\n }\n console.debug(prefix, ': ', this.formatData(data));\n }\n }\n}\n\n/**\n * Serialize log data without `node:util` so logging works on every runtime.\n * Errors keep their message and stack; circular references are marked.\n */\nfunction stringify(value: object): string {\n if (value instanceof Error) {\n return value.stack || `${value.name}: ${value.message}`;\n }\n const seen = new WeakSet<object>();\n try {\n return JSON.stringify(\n value,\n (_key, val) => {\n if (val instanceof Error) {\n return { name: val.name, message: val.message, stack: val.stack };\n }\n if (typeof val === 'bigint') return val.toString();\n if (typeof val === 'object' && val !== null) {\n if (seen.has(val)) return '[Circular]';\n seen.add(val);\n }\n return val;\n },\n 2,\n );\n } catch {\n return String(value);\n }\n}\n","export const objectToQueryString = (params: Record<string, any>): string => {\n if (!params || Object.keys(params).length === 0) {\n return '';\n }\n\n const queryParts: string[] = [];\n\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n const encodedKey = encodeURIComponent(key);\n const encodedValue = encodeURIComponent(String(value));\n queryParts.push(`${encodedKey}=${encodedValue}`);\n }\n }\n\n return queryParts.length > 0 ? `?${queryParts.join('&')}` : '';\n};\n","// Docs: https://developers.facebook.com/docs/graph-api/overview/rate-limiting/\n\n/**\n * Usage percentages reported by Meta. Each value is the share (0-100+) of the allowance used in the\n * current rolling window.\n */\nexport interface RateLimitUsage {\n /** Percentage of calls made (`call_count`). */\n callCount?: number;\n /** Percentage of total CPU time used (`total_cputime`). */\n totalCputime?: number;\n /** Percentage of total time used (`total_time`). */\n totalTime?: number;\n}\n\n/** One entry of the `X-Business-Use-Case-Usage` header. */\nexport interface BusinessUseCaseUsage extends RateLimitUsage {\n /** The business object the entry belongs to (for WhatsApp, usually the WABA or phone number ID). */\n businessId: string;\n /** Rate limit type, e.g. `whatsapp_business_management` or `whatsapp`. */\n type?: string;\n /**\n * `estimated_time_to_regain_access`: \"Time, in minutes, until calls will no longer be throttled.\"\n * `0` when not throttled.\n */\n estimatedTimeToRegainAccessMinutes?: number;\n /** `ads_api_access_tier`, only sent for Marketing API use cases. */\n adsApiAccessTier?: string;\n}\n\n/**\n * Rate limit information parsed from a Graph API response.\n *\n * WhatsApp Cloud API responses carry `x-business-use-case-usage` (types\n * `whatsapp_business_management` and `whatsapp`) and `x-app-usage`; throttled responses may add\n * `Retry-After` (seconds).\n */\nexport interface RateLimitInfo {\n /** Parsed `X-App-Usage` header (platform rate limits). */\n appUsage?: RateLimitUsage;\n /** Parsed `X-Business-Use-Case-Usage` header, flattened across business IDs. Empty when absent. */\n businessUseCaseUsage: BusinessUseCaseUsage[];\n /** Parsed `Retry-After` header in milliseconds (seconds or HTTP-date form). */\n retryAfterMs?: number;\n /**\n * Highest usage percentage across every parsed metric, handy for alerting before Meta starts\n * throttling (it throttles at 100).\n */\n maxUsagePercent?: number;\n /**\n * How long Meta asks you to wait, in milliseconds: the larger of `retryAfterMs` and the largest\n * `estimatedTimeToRegainAccessMinutes`. Undefined when Meta gave no wait time.\n */\n retryDelayMs?: number;\n}\n\n/** Headers accepted by {@link parseRateLimitHeaders}. */\nexport type RateLimitHeadersInput =\n | Headers\n | Record<string, string | string[] | undefined>\n | { get(name: string): string | null };\n\nfunction readHeader(headers: RateLimitHeadersInput, name: string): string | undefined {\n if (typeof (headers as { get?: unknown }).get === 'function') {\n const value = (headers as { get(name: string): string | null }).get(name);\n return value ?? undefined;\n }\n const record = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(record).find((k) => k.toLowerCase() === name);\n if (key === undefined) return undefined;\n const value = record[key];\n return Array.isArray(value) ? value[0] : value;\n}\n\nfunction parseJson(value: string | undefined): unknown {\n if (value === undefined || value.trim() === '') return undefined;\n try {\n return JSON.parse(value);\n } catch {\n return undefined;\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction num(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))) return Number(value);\n return undefined;\n}\n\nfunction str(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction parseUsage(value: Record<string, unknown>): RateLimitUsage {\n const usage: RateLimitUsage = {};\n const callCount = num(value.call_count);\n const totalCputime = num(value.total_cputime);\n const totalTime = num(value.total_time);\n if (callCount !== undefined) usage.callCount = callCount;\n if (totalCputime !== undefined) usage.totalCputime = totalCputime;\n if (totalTime !== undefined) usage.totalTime = totalTime;\n return usage;\n}\n\nfunction parseBusinessUseCaseUsage(value: unknown): BusinessUseCaseUsage[] {\n if (!isRecord(value)) return [];\n const entries: BusinessUseCaseUsage[] = [];\n for (const [businessId, list] of Object.entries(value)) {\n if (!Array.isArray(list)) continue;\n for (const item of list) {\n if (!isRecord(item)) continue;\n const entry: BusinessUseCaseUsage = { businessId, ...parseUsage(item) };\n const type = str(item.type);\n const regain = num(item.estimated_time_to_regain_access);\n const tier = str(item.ads_api_access_tier);\n if (type !== undefined) entry.type = type;\n if (regain !== undefined) entry.estimatedTimeToRegainAccessMinutes = regain;\n if (tier !== undefined) entry.adsApiAccessTier = tier;\n entries.push(entry);\n }\n }\n return entries;\n}\n\n/**\n * Parses a `Retry-After` value (delta-seconds or HTTP-date) into milliseconds.\n * Returns undefined for missing or malformed values.\n */\nexport function parseRetryAfter(value: string | null | undefined, now: number = Date.now()): number | undefined {\n if (value === null || value === undefined) return undefined;\n const trimmed = value.trim();\n if (trimmed === '') return undefined;\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) return Math.round(Number(trimmed) * 1000);\n // An HTTP-date always names a weekday/month; this rejects values such as \"-1\" that Date.parse accepts.\n if (!/[a-z]/i.test(trimmed)) return undefined;\n const date = Date.parse(trimmed);\n if (!Number.isFinite(date)) return undefined;\n return Math.max(0, date - now);\n}\n\n/**\n * Parses Meta's rate limit headers (`X-App-Usage`, `X-Business-Use-Case-Usage`, `Retry-After`).\n * Header names are matched case-insensitively. Malformed JSON or values are ignored, never thrown.\n *\n * Returns undefined when none of the headers are present.\n *\n * @see {@link https://developers.facebook.com/docs/graph-api/overview/rate-limiting/ | Graph API rate limiting}\n *\n * @example\n * ```ts\n * const info = parseRateLimitHeaders(response.headers);\n * if ((info?.maxUsagePercent ?? 0) > 80) slowDown();\n * ```\n */\nexport function parseRateLimitHeaders(headers: RateLimitHeadersInput | null | undefined): RateLimitInfo | undefined {\n if (!headers) return undefined;\n\n const appRaw = readHeader(headers, 'x-app-usage');\n const bucRaw = readHeader(headers, 'x-business-use-case-usage');\n const retryAfterRaw = readHeader(headers, 'retry-after');\n if (appRaw === undefined && bucRaw === undefined && retryAfterRaw === undefined) return undefined;\n\n const info: RateLimitInfo = { businessUseCaseUsage: [] };\n\n const appJson = parseJson(appRaw);\n if (isRecord(appJson)) info.appUsage = parseUsage(appJson);\n\n info.businessUseCaseUsage = parseBusinessUseCaseUsage(parseJson(bucRaw));\n\n const retryAfterMs = parseRetryAfter(retryAfterRaw);\n if (retryAfterMs !== undefined) info.retryAfterMs = retryAfterMs;\n\n const usages: RateLimitUsage[] = [...(info.appUsage ? [info.appUsage] : []), ...info.businessUseCaseUsage];\n const percents = usages.flatMap((u) =>\n [u.callCount, u.totalCputime, u.totalTime].filter((v): v is number => v !== undefined),\n );\n if (percents.length > 0) info.maxUsagePercent = Math.max(...percents);\n\n const waits = [\n ...(retryAfterMs !== undefined ? [retryAfterMs] : []),\n ...info.businessUseCaseUsage\n .map((u) => u.estimatedTimeToRegainAccessMinutes)\n .filter((m): m is number => m !== undefined && m > 0)\n .map((m) => m * 60_000),\n ];\n if (waits.length > 0) info.retryDelayMs = Math.max(...waits);\n\n return info;\n}\n","import { nodeCrypto } from './runtimeCrypto';\n\n/**\n * Runtime helpers that keep the SDK free of static `node:*` imports, so the\n * universal bundle loads on Bun, Deno, Cloudflare Workers and Vercel Edge.\n * Node conditional entries inject crypto for versions lacking getBuiltinModule.\n */\n\ntype NodeCrypto = typeof import('node:crypto');\n\ntype ProcessLike = {\n env?: Record<string, string | undefined>;\n version?: string;\n versions?: Record<string, string | undefined>;\n getBuiltinModule?: (id: string) => unknown;\n};\n\nfunction getProcess(): ProcessLike | undefined {\n const proc = (globalThis as { process?: ProcessLike }).process;\n return typeof proc === 'object' && proc !== null ? proc : undefined;\n}\n\n/**\n * Read an environment variable. Returns undefined on runtimes without\n * `process.env` (e.g. Cloudflare Workers without `nodejs_compat`).\n */\nexport function readEnv(name: string): string | undefined {\n return getProcess()?.env?.[name];\n}\n\n/** True when the `DEBUG` environment variable is `'true'`. */\nexport function isDebugEnv(): boolean {\n return readEnv('DEBUG') === 'true';\n}\n\n/**\n * Load `node:crypto` synchronously without a static import, via\n * `process.getBuiltinModule` (Node.js >= 20.16, Bun, Deno, workerd with\n * `nodejs_compat`), or the Node entry module. Returns undefined\n * when it is not available.\n */\nexport function getNodeCrypto(): NodeCrypto | undefined {\n const getBuiltinModule = getProcess()?.getBuiltinModule;\n if (typeof getBuiltinModule !== 'function') return getProcess() ? nodeCrypto : undefined;\n try {\n return getBuiltinModule('node:crypto') as NodeCrypto;\n } catch {\n return undefined;\n }\n}\n\n/** Like {@link getNodeCrypto} but throws a descriptive error when missing. */\nexport function requireNodeCrypto(feature: string): NodeCrypto {\n const crypto = getNodeCrypto();\n if (!crypto) {\n throw new Error(\n `${feature} needs the node:crypto module, which is not available in this runtime. ` +\n 'Use the async Web Crypto variant instead, or run on Node.js >= 20.12, Bun or Deno.',\n );\n }\n return crypto;\n}\n\n/** Web Crypto `SubtleCrypto`, available on every supported runtime. */\nexport function getSubtle(): SubtleCrypto {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new Error('Web Crypto (globalThis.crypto.subtle) is not available in this runtime.');\n }\n return subtle;\n}\n\n/** Human-readable runtime name for the User-Agent header. */\nexport function describeRuntime(): string {\n const g = globalThis as {\n Bun?: { version?: string };\n Deno?: { version?: { deno?: string } };\n EdgeRuntime?: string;\n navigator?: { userAgent?: string };\n };\n if (g.Bun?.version) return `Bun ${g.Bun.version}`;\n if (g.Deno?.version?.deno) return `Deno ${g.Deno.version.deno}`;\n if (typeof g.EdgeRuntime === 'string') return `Edge Runtime ${g.EdgeRuntime}`;\n if (g.navigator?.userAgent === 'Cloudflare-Workers') return 'Cloudflare Workers';\n const version = getProcess()?.version;\n if (version) return `Node.js ${version}`;\n return 'unknown runtime';\n}\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\nexport function utf8Encode(value: string): Uint8Array<ArrayBuffer> {\n return textEncoder.encode(value) as Uint8Array<ArrayBuffer>;\n}\n\nexport function utf8Decode(value: Uint8Array): string {\n return textDecoder.decode(value);\n}\n\nexport function base64ToBytes(value: string): Uint8Array<ArrayBuffer> {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\nexport function bytesToBase64(bytes: Uint8Array): string {\n let binary = '';\n const chunk = 0x8000;\n for (let i = 0; i < bytes.length; i += chunk) {\n binary += String.fromCharCode(...bytes.subarray(i, i + chunk));\n }\n return btoa(binary);\n}\n\nexport function bytesToHex(bytes: Uint8Array): string {\n let hex = '';\n for (const byte of bytes) {\n hex += byte.toString(16).padStart(2, '0');\n }\n return hex;\n}\n\n/** Constant-time string comparison (length is not secret). */\nexport function timingSafeEqualString(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) {\n diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return diff === 0;\n}\n\n/** HMAC-SHA256 hex digest using Web Crypto. */\nexport async function hmacSha256Hex(key: string, data: string): Promise<string> {\n const subtle = getSubtle();\n const cryptoKey = await subtle.importKey('raw', utf8Encode(key), { name: 'HMAC', hash: 'SHA-256' }, false, [\n 'sign',\n ]);\n const signature = await subtle.sign('HMAC', cryptoKey, utf8Encode(data));\n return bytesToHex(new Uint8Array(signature));\n}\n","/**\n * WhatsApp Flow Encryption/Decryption Utilities\n * Handles encryption and decryption of WhatsApp Flow requests and responses\n * @see https://developers.facebook.com/docs/whatsapp/cloud-api/reference/whatsapp-business-encryption/\n */\n\nimport type { KeyObject } from 'node:crypto';\n\nimport type { FlowEndpointRequest } from '../api/flow';\nimport type { WabaConfigType } from '../types/config';\nimport Logger from './logger';\nimport {\n base64ToBytes,\n bytesToBase64,\n getNodeCrypto,\n getSubtle,\n isDebugEnv,\n readEnv,\n requireNodeCrypto,\n utf8Decode,\n utf8Encode,\n} from './runtime';\n\nconst LIB_NAME = 'FLOW_ENCRYPTION_UTILS';\nconst LOGGER = new Logger(LIB_NAME, isDebugEnv());\n\n/**\n * Environment model for encryption keys\n */\nexport type EncryptionKeyPair = {\n passphrase: string;\n privateKey: string;\n publicKey: string;\n};\n\n/**\n * Validates that the code is running in a Node.js environment\n * @throws {Error} If not running in Node.js environment\n */\nfunction validateNodeEnvironment(): typeof import('node:crypto') {\n const crypto = getNodeCrypto();\n // Check if crypto module exists and has required methods\n if (!crypto || typeof crypto.generateKeyPairSync !== 'function') {\n const error = new Error(\n 'This utility requires Node.js environment with crypto module. ' +\n 'It cannot be used in browser or edge runtime environments.',\n );\n LOGGER.error('Environment validation failed:', error);\n throw error;\n }\n\n // Check if running in browser\n if (typeof window !== 'undefined') {\n const error = new Error(\n 'This utility cannot run in a browser environment. ' +\n 'Please use it in a Node.js server environment only.',\n );\n LOGGER.error('Browser environment detected:', error);\n throw error;\n }\n\n // Check Node.js version (crypto.generateKeyPairSync requires Node.js 10.12.0+)\n const nodeVersionString = (globalThis as { process?: { versions?: { node?: string } } }).process?.versions?.node;\n if (nodeVersionString) {\n const nodeVersion = nodeVersionString.split('.').map(Number);\n const major = nodeVersion[0] ?? 0;\n const minor = nodeVersion[1] ?? 0;\n\n if (major < 10 || (major === 10 && minor < 12)) {\n const error = new Error(\n `Node.js version ${nodeVersionString} is not supported. ` +\n 'Please upgrade to Node.js 10.12.0 or higher.',\n );\n LOGGER.error('Node.js version check failed:', error);\n throw error;\n }\n }\n\n return crypto;\n}\n\n/**\n * Generates RSA key pair for WhatsApp Business Flow API encryption\n *\n * This function generates a 2048-bit RSA key pair with:\n * - Public key in SPKI format (PEM)\n * - Private key in PKCS#8 format (PEM) encrypted with AES-256-CBC\n *\n * @param passphrase - Passphrase to encrypt the private key. If not provided, uses FLOW_API_PASSPHRASE from environment\n * @returns Object containing passphrase, privateKey, and publicKey\n * @throws {Error} If passphrase is empty or key generation fails\n * @throws {Error} If not running in Node.js environment\n *\n * @example\n * ```typescript\n * import { WhatsApp } from 'meta-cloud-api';\n *\n * const wa = new WhatsApp();\n *\n * try {\n * // Uses FLOW_API_PASSPHRASE from environment\n * const keys = wa.generateEncryption();\n * console.log('Public Key:', keys.publicKey);\n * console.log('Private Key:', keys.privateKey);\n *\n * // Or provide custom passphrase\n * const customKeys = wa.generateEncryption('my-secret-passphrase');\n * } catch (error) {\n * console.error('Failed to generate keys:', error.message);\n * }\n * ```\n */\nexport function generateEncryption(passphrase?: string): EncryptionKeyPair {\n LOGGER.info('[generateEncryption] Starting key pair generation');\n\n // Validate environment first\n const crypto = validateNodeEnvironment();\n\n // Get passphrase from parameter or environment variable\n const effectivePassphrase = passphrase || readEnv('FLOW_API_PASSPHRASE');\n\n // Validate passphrase\n if (!effectivePassphrase || effectivePassphrase.trim().length === 0) {\n const error = new Error(\n 'Passphrase is empty. Please provide a passphrase as parameter or set FLOW_API_PASSPHRASE environment variable.',\n );\n LOGGER.error('[generateEncryption] Passphrase validation failed:', error);\n throw error;\n }\n\n // Warn if passphrase is too short\n if (effectivePassphrase.length < 8) {\n LOGGER.warn(\n '[generateEncryption] Passphrase is shorter than 8 characters. Consider using a longer passphrase for better security.',\n );\n }\n\n try {\n LOGGER.info('[generateEncryption] Generating 2048-bit RSA key pair');\n\n // Generate RSA key pair\n const keyPair = crypto.generateKeyPairSync('rsa', {\n modulusLength: 2048,\n publicKeyEncoding: {\n type: 'spki',\n format: 'pem',\n },\n privateKeyEncoding: {\n type: 'pkcs8',\n format: 'pem',\n cipher: 'aes-256-cbc',\n passphrase: effectivePassphrase,\n },\n });\n\n LOGGER.info('[generateEncryption] Key pair generated successfully');\n\n return {\n passphrase: effectivePassphrase,\n privateKey: keyPair.privateKey,\n publicKey: keyPair.publicKey,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n const generationError = new Error(`Failed to generate key pair: ${errorMessage}`);\n LOGGER.error('[generateEncryption] Key generation failed:', generationError);\n throw generationError;\n }\n}\n\n/**\n * Decrypt a WhatsApp Flow request (Node.js only; see {@link decryptFlowRequestAsync} for every runtime)\n * @param body - Encrypted request body containing encrypted_aes_key, encrypted_flow_data, and initial_vector\n * @param config - WABA configuration containing FLOW_API_PRIVATE_PEM and FLOW_API_PASSPHRASE\n * @returns Decrypted flow request body, AES key buffer, and initial vector buffer\n * @throws {Error} If required encryption properties are missing or decryption fails\n */\nexport function decryptFlowRequest(\n body: any,\n config: WabaConfigType,\n): {\n decryptedBody: FlowEndpointRequest;\n aesKeyBuffer: Buffer;\n initialVectorBuffer: Buffer;\n} {\n LOGGER.info('[decryptFlowRequest] Starting Flow request decryption');\n\n const crypto = requireNodeCrypto('decryptFlowRequest');\n\n // Validate required environment variables\n if (!config.FLOW_API_PRIVATE_PEM || config.FLOW_API_PRIVATE_PEM.trim() === '') {\n const error = new Error(\n 'Missing FLOW_API_PRIVATE_PEM. Please set the FLOW_API_PRIVATE_PEM environment variable or pass privatePem via config.',\n );\n LOGGER.error('[decryptFlowRequest] Configuration error:', error);\n throw error;\n }\n\n if (!config.FLOW_API_PASSPHRASE || config.FLOW_API_PASSPHRASE.trim() === '') {\n const error = new Error(\n 'Missing FLOW_API_PASSPHRASE. Please set the FLOW_API_PASSPHRASE environment variable or pass passphrase via config.',\n );\n LOGGER.error('[decryptFlowRequest] Configuration error:', error);\n throw error;\n }\n\n LOGGER.info('[decryptFlowRequest] Configuration validated');\n\n const { encrypted_aes_key, encrypted_flow_data, initial_vector } = body;\n\n if (!encrypted_aes_key || !encrypted_flow_data || !initial_vector) {\n LOGGER.error('[decryptFlowRequest] Missing required encryption properties in request body');\n throw new Error('Missing required encryption properties');\n }\n\n LOGGER.info('[decryptFlowRequest] Request body validated');\n\n // Handle both escaped and unescaped newlines\n let privatePem = config.FLOW_API_PRIVATE_PEM;\n if (privatePem.includes('\\\\n')) {\n privatePem = privatePem.replace(/\\\\n/g, '\\n');\n }\n\n const passphrase = config.FLOW_API_PASSPHRASE;\n\n const isPKCS1 = privatePem.includes('-----BEGIN RSA PRIVATE KEY-----');\n const isPKCS8 =\n privatePem.includes('-----BEGIN PRIVATE KEY-----') ||\n privatePem.includes('-----BEGIN ENCRYPTED PRIVATE KEY-----');\n\n LOGGER.info('[decryptFlowRequest] Loading private key', {\n format: isPKCS8 ? 'PKCS#8' : isPKCS1 ? 'PKCS#1' : 'Unknown',\n });\n\n let privateKey: KeyObject;\n try {\n // Try to create private key with passphrase\n if (passphrase) {\n privateKey = crypto.createPrivateKey({\n key: privatePem,\n format: 'pem',\n passphrase,\n });\n } else {\n privateKey = crypto.createPrivateKey(privatePem);\n }\n LOGGER.info('[decryptFlowRequest] Private key loaded successfully');\n } catch (error) {\n LOGGER.error('[decryptFlowRequest] Failed to load private key (first attempt):', {\n error: error instanceof Error ? error.message : error,\n hasPassphrase: !!passphrase,\n format: isPKCS8 ? 'PKCS#8' : isPKCS1 ? 'PKCS#1' : 'Unknown',\n });\n\n // If PKCS#1 key failed, try to convert it to PKCS#8 format automatically\n if (isPKCS1 && passphrase) {\n try {\n LOGGER.info('[decryptFlowRequest] Attempting to convert PKCS#1 to PKCS#8 format');\n\n // First, load the PKCS#1 key with passphrase\n const pkcs1Key = crypto.createPrivateKey({\n key: privatePem,\n format: 'pem',\n passphrase,\n });\n\n // Export it as PKCS#8 with the same passphrase\n const pkcs8Pem = pkcs1Key.export({\n type: 'pkcs8',\n format: 'pem',\n cipher: 'aes-256-cbc',\n passphrase,\n });\n\n // Now create the private key from PKCS#8 format\n privateKey = crypto.createPrivateKey({\n key: pkcs8Pem as string,\n format: 'pem',\n passphrase,\n });\n\n LOGGER.info('[decryptFlowRequest] Successfully converted PKCS#1 to PKCS#8 and loaded private key');\n } catch (conversionError) {\n LOGGER.error('[decryptFlowRequest] Failed to convert PKCS#1 to PKCS#8:', {\n error: conversionError instanceof Error ? conversionError.message : conversionError,\n });\n\n // Provide helpful error message\n let errorMessage = `Failed to parse private key. Error: ${error instanceof Error ? error.message : error}`;\n errorMessage += '\\n\\nYour key is in PKCS#1 format with unsupported encryption (DES-EDE3-CBC).';\n errorMessage += '\\nPlease convert it to PKCS#8 format using:';\n errorMessage += '\\n openssl pkcs8 -topk8 -inform PEM -outform PEM -in old_key.pem -out new_key.pem';\n\n throw new Error(errorMessage);\n }\n } else {\n // Provide helpful error message\n let errorMessage = `Failed to parse private key. Error: ${error instanceof Error ? error.message : error}`;\n\n if (isPKCS1) {\n errorMessage += '\\n\\nYour key is in PKCS#1 format (-----BEGIN RSA PRIVATE KEY-----).';\n errorMessage += '\\nPlease convert it to PKCS#8 format using:';\n errorMessage += '\\n openssl pkcs8 -topk8 -inform PEM -outform PEM -in old_key.pem -out new_key.pem';\n } else if (!isPKCS8) {\n errorMessage += '\\n\\nYour key format is not recognized. Please ensure it is in PKCS#8 format.';\n }\n\n throw new Error(errorMessage);\n }\n }\n\n let decryptedAesKey: Buffer;\n\n try {\n LOGGER.info('[decryptFlowRequest] Decrypting AES key with RSA private key');\n decryptedAesKey = crypto.privateDecrypt(\n {\n key: privateKey,\n padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,\n oaepHash: 'sha256',\n },\n Buffer.from(encrypted_aes_key, 'base64'),\n );\n LOGGER.info('[decryptFlowRequest] AES key decrypted successfully');\n } catch (error) {\n LOGGER.error('[decryptFlowRequest] Failed to decrypt AES key:', error);\n throw new Error('Failed to decrypt the request. Please verify your private key.');\n }\n\n const flowDataBuffer = Buffer.from(encrypted_flow_data, 'base64');\n const initialVectorBuffer = Buffer.from(initial_vector, 'base64');\n\n const TAG_LENGTH = 16;\n const encrypted_flow_data_body = flowDataBuffer.subarray(0, -TAG_LENGTH);\n const encrypted_flow_data_tag = flowDataBuffer.subarray(-TAG_LENGTH);\n\n LOGGER.info('[decryptFlowRequest] Decrypting flow data with AES-128-GCM');\n\n const decipher = crypto.createDecipheriv('aes-128-gcm', decryptedAesKey, initialVectorBuffer);\n decipher.setAuthTag(encrypted_flow_data_tag);\n\n const decryptedJSONString = Buffer.concat([decipher.update(encrypted_flow_data_body), decipher.final()]).toString(\n 'utf-8',\n );\n\n LOGGER.info('[decryptFlowRequest] Flow request decrypted successfully');\n\n return {\n decryptedBody: JSON.parse(decryptedJSONString),\n aesKeyBuffer: decryptedAesKey,\n initialVectorBuffer,\n };\n}\n\n/**\n * Encrypt a WhatsApp Flow response (Node.js only; see {@link encryptFlowResponseAsync} for every runtime)\n * @param response - Response object to encrypt\n * @param aesKeyBuffer - AES key buffer from the decrypted request\n * @param initialVectorBuffer - Initial vector buffer from the decrypted request\n * @returns Base64-encoded encrypted response\n * @throws {Error} If encryption fails\n */\nexport function encryptFlowResponse(response: any, aesKeyBuffer: Buffer, initialVectorBuffer: Buffer): string {\n LOGGER.info('[encryptFlowResponse] Starting Flow response encryption');\n\n const crypto = requireNodeCrypto('encryptFlowResponse');\n\n const flipped_iv: number[] = [];\n for (const pair of Array.from(initialVectorBuffer.entries())) {\n flipped_iv.push(~pair[1]);\n }\n\n try {\n LOGGER.info('[encryptFlowResponse] Encrypting response with AES-128-GCM');\n const cipher = crypto.createCipheriv('aes-128-gcm', aesKeyBuffer, Buffer.from(flipped_iv));\n const encryptedResponse = Buffer.concat([\n cipher.update(JSON.stringify(response || {}), 'utf-8'),\n cipher.final(),\n cipher.getAuthTag(),\n ]).toString('base64');\n\n LOGGER.info('[encryptFlowResponse] Flow response encrypted successfully');\n\n return encryptedResponse;\n } catch (error) {\n LOGGER.error('[encryptFlowResponse] Response encryption failed:', error);\n throw new Error('Failed to encrypt response. Internal server error.');\n }\n}\n\n/**\n * Result of {@link decryptFlowRequestAsync}. Pass `aesKeyBuffer` and\n * `initialVectorBuffer` to {@link encryptFlowResponseAsync}.\n */\nexport type DecryptedFlowRequest = {\n decryptedBody: FlowEndpointRequest;\n aesKeyBuffer: Uint8Array<ArrayBuffer>;\n initialVectorBuffer: Uint8Array<ArrayBuffer>;\n};\n\nconst PEM_PATTERN = /-----BEGIN ([A-Z ]+)-----([\\s\\S]*?)-----END \\1-----/;\n\nlet cachedPrivateKey: { pem: string; passphrase: string; key: Promise<CryptoKey> } | undefined;\n\n/**\n * Turn a PEM private key into PKCS#8 DER bytes that Web Crypto can import.\n * Unencrypted PKCS#8 (`BEGIN PRIVATE KEY`) works everywhere. Encrypted PKCS#8\n * and PKCS#1 keys need `node:crypto` to unwrap, because Web Crypto has no\n * passphrase support; on runtimes without it a descriptive error is thrown.\n */\nfunction privatePemToPkcs8Der(privatePem: string, passphrase: string): Uint8Array<ArrayBuffer> {\n const match = PEM_PATTERN.exec(privatePem);\n if (!match) {\n throw new Error('Failed to parse private key. Expected a PEM encoded PKCS#8 private key.');\n }\n const label = match[1];\n if (label === 'PRIVATE KEY') {\n return base64ToBytes((match[2] ?? '').replace(/\\s+/g, ''));\n }\n\n const crypto = getNodeCrypto();\n if (!crypto) {\n throw new Error(\n `Failed to parse private key. \"${label}\" keys need node:crypto, which this runtime lacks. ` +\n 'Convert the key to an unencrypted PKCS#8 key and keep it in a secret store:' +\n '\\n openssl pkcs8 -topk8 -nocrypt -in private.pem -out private-pkcs8.pem',\n );\n }\n try {\n const keyObject = crypto.createPrivateKey({\n key: privatePem,\n format: 'pem',\n passphrase: passphrase || undefined,\n });\n const der = keyObject.export({ type: 'pkcs8', format: 'der' });\n return new Uint8Array(der);\n } catch (error) {\n throw new Error(`Failed to parse private key. Error: ${error instanceof Error ? error.message : error}`);\n }\n}\n\nfunction importFlowPrivateKey(privatePem: string, passphrase: string): Promise<CryptoKey> {\n if (cachedPrivateKey && cachedPrivateKey.pem === privatePem && cachedPrivateKey.passphrase === passphrase) {\n return cachedPrivateKey.key;\n }\n const key = (async () =>\n getSubtle().importKey(\n 'pkcs8',\n privatePemToPkcs8Der(privatePem, passphrase),\n { name: 'RSA-OAEP', hash: 'SHA-256' },\n false,\n ['decrypt'],\n ))();\n cachedPrivateKey = { pem: privatePem, passphrase, key };\n // Do not keep a rejected promise around; a corrected config should retry.\n key.catch(() => {\n if (cachedPrivateKey?.key === key) cachedPrivateKey = undefined;\n });\n return key;\n}\n\n/**\n * Decrypt a WhatsApp Flow request with Web Crypto. Works on Node.js, Bun, Deno,\n * Cloudflare Workers and Vercel Edge.\n *\n * On runtimes without `node:crypto` the private key must be an unencrypted\n * PKCS#8 PEM (`-----BEGIN PRIVATE KEY-----`); the passphrase is then ignored.\n *\n * @param body - Encrypted request body containing encrypted_aes_key, encrypted_flow_data, and initial_vector\n * @param config - WABA configuration containing FLOW_API_PRIVATE_PEM and (for encrypted keys) FLOW_API_PASSPHRASE\n * @throws {Error} If required encryption properties are missing or decryption fails\n */\nexport async function decryptFlowRequestAsync(body: any, config: WabaConfigType): Promise<DecryptedFlowRequest> {\n if (!config.FLOW_API_PRIVATE_PEM || config.FLOW_API_PRIVATE_PEM.trim() === '') {\n throw new Error(\n 'Missing FLOW_API_PRIVATE_PEM. Please set the FLOW_API_PRIVATE_PEM environment variable or pass privatePem via config.',\n );\n }\n\n const { encrypted_aes_key, encrypted_flow_data, initial_vector } = body ?? {};\n if (!encrypted_aes_key || !encrypted_flow_data || !initial_vector) {\n throw new Error('Missing required encryption properties');\n }\n\n let privatePem = config.FLOW_API_PRIVATE_PEM;\n if (privatePem.includes('\\\\n')) {\n privatePem = privatePem.replace(/\\\\n/g, '\\n');\n }\n\n const subtle = getSubtle();\n const privateKey = await importFlowPrivateKey(privatePem, config.FLOW_API_PASSPHRASE || '');\n\n let aesKeyBuffer: Uint8Array<ArrayBuffer>;\n try {\n aesKeyBuffer = new Uint8Array(\n await subtle.decrypt({ name: 'RSA-OAEP' }, privateKey, base64ToBytes(encrypted_aes_key)),\n );\n } catch (error) {\n LOGGER.error('[decryptFlowRequestAsync] Failed to decrypt AES key:', error);\n throw new Error('Failed to decrypt the request. Please verify your private key.');\n }\n\n const initialVectorBuffer = base64ToBytes(initial_vector);\n const aesKey = await subtle.importKey('raw', aesKeyBuffer, { name: 'AES-GCM' }, false, ['decrypt']);\n // Meta sends ciphertext || 16-byte tag, which is exactly what Web Crypto expects.\n const decrypted = await subtle.decrypt(\n { name: 'AES-GCM', iv: initialVectorBuffer, tagLength: 128 },\n aesKey,\n base64ToBytes(encrypted_flow_data),\n );\n\n return {\n decryptedBody: JSON.parse(utf8Decode(new Uint8Array(decrypted))),\n aesKeyBuffer,\n initialVectorBuffer,\n };\n}\n\n/**\n * Encrypt a WhatsApp Flow response with Web Crypto. Works on every runtime.\n * @param response - Response object to encrypt\n * @param aesKeyBuffer - AES key from {@link decryptFlowRequestAsync} (a Node.js Buffer also works)\n * @param initialVectorBuffer - Initial vector from {@link decryptFlowRequestAsync} (a Node.js Buffer also works)\n * @returns Base64-encoded encrypted response\n */\nexport async function encryptFlowResponseAsync(\n response: any,\n aesKeyBuffer: Uint8Array,\n initialVectorBuffer: Uint8Array,\n): Promise<string> {\n const flippedIv = new Uint8Array(initialVectorBuffer.length);\n for (let i = 0; i < initialVectorBuffer.length; i++) {\n flippedIv[i] = ~(initialVectorBuffer[i] ?? 0) & 0xff;\n }\n\n try {\n const subtle = getSubtle();\n const aesKey = await subtle.importKey('raw', new Uint8Array(aesKeyBuffer), { name: 'AES-GCM' }, false, [\n 'encrypt',\n ]);\n const encrypted = await subtle.encrypt(\n { name: 'AES-GCM', iv: flippedIv, tagLength: 128 },\n aesKey,\n utf8Encode(JSON.stringify(response || {})),\n );\n return bytesToBase64(new Uint8Array(encrypted));\n } catch (error) {\n LOGGER.error('[encryptFlowResponseAsync] Response encryption failed:', error);\n throw new Error('Failed to encrypt response. Internal server error.');\n }\n}\n","import {\n FlowActionEnum,\n type FlowDataExchangeRequest,\n type FlowEndpointRequest,\n type FlowErrorNotificationRequest,\n type FlowHealthCheckRequest,\n} from '../api/flow/types';\n\n/**\n * Helper function to check if a value is an object\n * @param value The value to check\n * @returns True if the value is a non-null object\n */\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * Helper function to check if a value is a string\n * @param value The value to check\n * @returns True if the value is a string\n */\nfunction isString(value: unknown): value is string {\n return typeof value === 'string';\n}\n\n// Array of allowed action types for data exchange requests\nconst DATA_EXCHANGE_ACTIONS = [FlowActionEnum.DATA_EXCHANGE, FlowActionEnum.INIT, FlowActionEnum.BACK] as const;\n\n// Array of allowed action types for error notification requests\nconst ERROR_ACTIONS = [FlowActionEnum.DATA_EXCHANGE, FlowActionEnum.INIT] as const;\n\n/**\n * Type guard to check if a request is a Data Exchange request\n * Validates the request structure according to the Flow API specifications\n *\n * @param request The Flow endpoint request to check\n * @returns True if the request is a valid Data Exchange request, false otherwise\n */\nexport function isFlowDataExchangeRequest(request: FlowEndpointRequest): request is FlowDataExchangeRequest & {\n action: (typeof DATA_EXCHANGE_ACTIONS)[number];\n screen?: string;\n flow_token: string;\n data?: Record<string, any>;\n} {\n // Check for basic required fields\n if (!('flow_token' in request && isString(request.flow_token) && 'action' in request)) {\n return false;\n }\n\n const { action, version, screen, data } = request;\n\n // Validate API version\n const hasValidVersion = version === '3.0';\n\n // Check if the action is one of the allowed actions for data exchange\n const hasValidAction = DATA_EXCHANGE_ACTIONS.includes(action as any);\n\n // Screen is optional, but when present must be a string and not 'SUCCESS'\n const hasValidScreen = typeof screen === 'undefined' || (isString(screen) && screen !== 'SUCCESS');\n\n // Data is required except for DATA_EXCHANGE action\n const hasValidData = action === FlowActionEnum.DATA_EXCHANGE || isObject(data);\n\n // All conditions must be met for a valid data exchange request\n return hasValidVersion && hasValidAction && hasValidScreen && hasValidData;\n}\n\n/**\n * Type guard to check if a request is an Error Notification request\n * Validates the request structure according to the Flow API error specifications\n *\n * @param request The Flow endpoint request to check\n * @returns True if the request is a valid Error Notification request, false otherwise\n */\nexport function isFlowErrorRequest(request: FlowEndpointRequest): request is FlowErrorNotificationRequest & {\n action: (typeof ERROR_ACTIONS)[number];\n screen: string;\n flow_token: string;\n data: {\n error: string;\n error_message: string;\n };\n} {\n // Check for basic required fields\n if (!('flow_token' in request && isString(request.flow_token) && 'action' in request)) {\n return false;\n }\n\n const { action, screen, data } = request;\n\n // Check if the action is one of the allowed actions for error notifications\n const hasValidAction = ERROR_ACTIONS.includes(action as any);\n\n // Screen is required for error notifications\n const hasValidScreen = isString(screen);\n\n // Validate error data structure\n const hasValidData =\n isObject(data) &&\n 'error_key' in data &&\n isString(data.error) &&\n 'error_message' in data &&\n isString(data.error_message);\n\n // All conditions must be met for a valid error notification request\n return hasValidAction && hasValidScreen && hasValidData;\n}\n\n/**\n * Type guard to check if a request is a Ping (health check) request\n * Simple validation for health check endpoints in the Flow API\n *\n * @param request The Flow endpoint request to check\n * @returns True if the request is a Ping request, false otherwise\n */\nexport function isFlowPingRequest(request: FlowEndpointRequest): request is FlowHealthCheckRequest {\n // A ping request only requires the 'action' field with value 'ping'\n return 'action' in request && request.action === 'ping';\n}\n"],"mappings":"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"}
|