@funnelfox/billing 0.1.0
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/LICENSE +21 -0
- package/README.md +548 -0
- package/dist/funnelfox-billing.cjs.d.ts +2 -0
- package/dist/funnelfox-billing.cjs.js +1513 -0
- package/dist/funnelfox-billing.d.ts +204 -0
- package/dist/funnelfox-billing.esm.d.ts +2 -0
- package/dist/funnelfox-billing.esm.js +1492 -0
- package/dist/funnelfox-billing.js +1519 -0
- package/dist/funnelfox-billing.min.js +1 -0
- package/package.json +80 -0
- package/src/types.d.ts +203 -0
- package/types.d.ts +203 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).FunnelfoxSDK={})}(this,function(e){"use strict";class t extends Error{constructor(e,r="SDK_ERROR",s=null){super(e),this.name="FunnefoxSDKError",this.code=r,this.details=s,Error.captureStackTrace&&Error.captureStackTrace(this,t)}}class r extends t{constructor(e,t,r=null){super(`Invalid ${e}: ${t}`,"VALIDATION_ERROR"),this.name="ValidationError",this.field=e,this.value=r}}class s extends t{constructor(e,t=null,r={}){super(e,r.errorCode||"API_ERROR"),this.name="APIError",this.statusCode=t,this.errorCode=r.errorCode||null,this.errorType=r.errorType||null,this.requestId=r.requestId||null,this.response=r.response||null}}class n extends t{constructor(e,t=null){super(e,"PRIMER_ERROR"),this.name="PrimerError",this.primerError=t}}class i extends t{constructor(e,t=null){super(e,"CHECKOUT_ERROR"),this.name="CheckoutError",this.phase=t}}class o extends t{constructor(e,t=null){super(e,"NETWORK_ERROR"),this.name="NetworkError",this.originalError=t}}const a={BASE_URL:"https://billing.funnelfox.com",REGION:"default",SANDBOX:!1,REQUEST_TIMEOUT:3e4,RETRY_ATTEMPTS:3,RETRY_BASE_DELAY:1e3};class c{constructor(){this._events=new Map}on(e,t){if("function"!=typeof t)throw new Error("Event handler must be a function");return this._events.has(e)||this._events.set(e,[]),this._events.get(e).push(t),this}once(e,t){if("function"!=typeof t)throw new Error("Event handler must be a function");const r=(...s)=>{this.off(e,r),t.apply(this,s)};return this.on(e,r)}off(e,t=null){if(!this._events.has(e))return this;if(null===t)return this._events.delete(e),this;const r=this._events.get(e),s=r.indexOf(t);return-1!==s&&(r.splice(s,1),0===r.length&&this._events.delete(e)),this}emit(e,...t){if(!this._events.has(e))return!1;const r=this._events.get(e).slice();for(const s of r)try{s.apply(this,t)}catch(t){console.warn(`Error in event handler for "${e}":`,t)}return!0}listenerCount(e){return this._events.has(e)?this._events.get(e).length:0}eventNames(){return Array.from(this._events.keys())}removeAllListeners(){return this._events.clear(),this}listeners(e){return this._events.has(e)?this._events.get(e).slice():[]}}function u(...e){const t={};for(const r of e)if(r&&"object"==typeof r)for(const e in r)Object.prototype.hasOwnProperty.call(r,e)&&("object"!=typeof r[e]||Array.isArray(r[e])||null===r[e]?t[e]=r[e]:t[e]=u(t[e]||{},r[e]));return t}function h(e){return new Promise(t=>setTimeout(t,e))}class l{constructor(){this.currentCheckout=null,this.isInitialized=!1}isPrimerAvailable(){return"undefined"!=typeof window&&window.Primer&&"function"==typeof window.Primer.showUniversalCheckout}ensurePrimerAvailable(){if(!this.isPrimerAvailable())throw new n("Primer SDK not found. Please include the Primer SDK script before initializing FunnefoxSDK.")}async showUniversalCheckout(e,t){this.ensurePrimerAvailable();const{onTokenizeSuccess:r,onResumeSuccess:s,container:i,...o}=t,a=u({clientToken:e,container:i,paymentHandling:"MANUAL",apiVersion:"2.4",paypal:{buttonColor:"blue",paymentFlow:"PREFER_VAULT"}},o);a.onTokenizeSuccess=this._wrapTokenizeHandler(r),a.onResumeSuccess=this._wrapResumeHandler(s);try{const t=await window.Primer.showUniversalCheckout(e,a);return this.currentCheckout=t,this.isInitialized=!0,t}catch(e){throw new n("Failed to initialize Primer checkout",e)}}_wrapTokenizeHandler(e){return async(t,r)=>{try{await e(t,r)}catch(e){console.error("Error in tokenize handler:",e),r.handleFailure("Payment processing failed. Please try again.")}}}_wrapResumeHandler(e){return async(t,r)=>{try{await e(t,r)}catch(e){console.error("Error in resume handler:",e),r.handleFailure("Payment processing failed. Please try again.")}}}async updateClientToken(e){if(!this.currentCheckout)throw new n("No active checkout to update");try{throw new n("Client token updates require checkout recreation")}catch(e){throw new n("Failed to update client token",e)}}async destroy(){if(this.currentCheckout)try{if("function"==typeof this.currentCheckout.destroy)await this.currentCheckout.destroy();else{const e=document.querySelector(this.currentCheckout.container);e&&(e.innerHTML="")}}catch(e){console.warn("Error destroying Primer checkout:",e)}finally{this.currentCheckout=null,this.isInitialized=!1}}createHandlers(e){return{handleSuccess:()=>{e.onSuccess&&e.onSuccess()},handleFailure:t=>{e.onError&&e.onError(new Error(t))},continueWithNewClientToken:t=>{e.onActionRequired&&e.onActionRequired(t)}}}getCurrentCheckout(){return this.currentCheckout}isActive(){return this.isInitialized&&null!==this.currentCheckout}validateContainer(e){const t=document.querySelector(e);if(!t)throw new n(`Checkout container not found: ${e}`);return"none"===window.getComputedStyle(t).display&&console.warn("Checkout container is hidden, this may cause display issues"),t}}var d=Object.freeze({__proto__:null,default:l});function p(e,t){var s;if(0===(null==(s=e)?"":String(s).trim()).length)throw new r(t,"must be a non-empty string",e);return!0}class y{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.orgId=e.orgId,this.timeout=e.timeout||3e4,this.retryAttempts=e.retryAttempts||3}async request(e,t={}){const r=`${this.baseUrl}/${this.orgId}${e}`,s={method:"GET",headers:{"Content-Type":"application/json",...t.headers},...t};try{return await async function(e,t=3,r=1e3){let s;for(let n=1;n<=t;n++)try{return await e()}catch(e){if(s=e,n===t)throw s;const i=r*Math.pow(2,n-1);await h(i)}throw s}(async()=>await function(e,t,r="Operation timed out"){const s=new Promise((e,s)=>{setTimeout(()=>s(new Error(r)),t)});return Promise.race([e,s])}(this._makeRequest(r,s),this.timeout,"Request timed out"),this.retryAttempts)}catch(e){if("APIError"===e.name)throw e;throw new o("Network request failed",e)}}async _makeRequest(e,t){let r,n;try{r=await fetch(e,t)}catch(e){throw new o("Network request failed",e)}try{n=await r.json()}catch(e){throw new s("Invalid JSON response",r.status,{})}if(!r.ok){const e=n.message||n.error||`HTTP ${r.status}`;throw new s(e,r.status,{response:n})}return n}async createClientSession(e){const t={region:e.region||"default",integration_type:"primer",pp_ident:e.priceId,external_id:e.externalId,email_address:e.email,client_metadata:e.clientMetadata||{}};return void 0!==e.countryCode&&(t.country_code=e.countryCode),await this.request("/v1/checkout/create_client_session",{method:"POST",body:JSON.stringify(t)})}async updateClientSession(e){const t={order_id:e.orderId,client_token:e.clientToken,pp_ident:e.priceId};return await this.request("/v1/checkout/update_client_session",{method:"POST",body:JSON.stringify(t)})}async createPayment(e){const t={order_id:e.orderId,payment_method_token:e.paymentMethodToken};return await this.request("/v1/checkout/create_payment",{method:"POST",body:JSON.stringify(t)})}async resumePayment(e){const t={order_id:e.orderId,resume_token:e.resumeToken};return await this.request("/v1/checkout/resume_payment",{method:"POST",body:JSON.stringify(t)})}async oneClickPayment(e){const t={external_id:e.externalId,pp_ident:e.priceId,client_metadata:e.clientMetadata||{}};return await this.request("/v1/checkout/one_click",{method:"POST",body:JSON.stringify(t)})}processSessionResponse(e){if("error"===e.status){const t=e.error?.[0];throw new s(t?.msg||"Session creation failed",null,{errorCode:t?.code,errorType:t?.type,requestId:e.req_id,response:e})}const t=e.data||e;return{type:"session_created",orderId:t.order_id,clientToken:t.client_token}}processPaymentResponse(e){if("error"===e.status){const t=e.error?.[0];throw new s(t?.msg||"Payment request failed",null,{errorCode:t?.code,errorType:t?.type,requestId:e.req_id,response:e})}const t=e.data||e;if(t.action_required_token)return{type:"action_required",orderId:t.order_id,clientToken:t.action_required_token};if(t.checkout_status)switch(t.checkout_status){case"succeeded":return{type:"success",orderId:t.order_id,status:"succeeded",transactionId:t.transaction_id};case"failed":throw new s(t.failed_message_for_user||"Payment failed",null,t);case"cancelled":throw new s("Payment was cancelled by user",null,t);case"processing":return{type:"processing",orderId:t.order_id,status:"processing"};default:throw new s(`Unhandled checkout status: ${t.checkout_status}`,null,t)}throw new s("Invalid payment response format",null,t)}processResponse(e){const t=e.data||e;if(t.client_token&&t.order_id&&!t.checkout_status)return this.processSessionResponse(e);if(t.checkout_status||t.action_required_token)return this.processPaymentResponse(e);throw new s("Unknown response format",null,e)}}class m extends c{constructor(e){super(),this.id=function(e=""){return`${e}${Date.now().toString(36)}_${Math.random().toString(36).substr(2,5)}`}("checkout_"),this.orgId=e.orgId,this.baseUrl=e.baseUrl,this.region=e.region,this.checkoutConfig={...e.checkoutConfig},this.callbacks={onSuccess:this.checkoutConfig.onSuccess,onError:this.checkoutConfig.onError,onStatusChange:this.checkoutConfig.onStatusChange,onDestroy:this.checkoutConfig.onDestroy},delete this.checkoutConfig.onSuccess,delete this.checkoutConfig.onError,delete this.checkoutConfig.onStatusChange,delete this.checkoutConfig.onDestroy,this.state="initializing",this.orderId=null,this.clientToken=null,this.primerWrapper=new l,this.isDestroyed=!1,this._setupCallbackBridges(),this._handleTokenizeSuccess=this._handleTokenizeSuccess.bind(this),this._handleResumeSuccess=this._handleResumeSuccess.bind(this)}_setupCallbackBridges(){this.callbacks.onSuccess&&this.on("success",this.callbacks.onSuccess),this.callbacks.onError&&this.on("error",this.callbacks.onError),this.callbacks.onStatusChange&&this.on("status-change",this.callbacks.onStatusChange),this.callbacks.onDestroy&&this.on("destroy",this.callbacks.onDestroy)}async initialize(){try{this._setState("initializing"),function(e){p(e,"container");const t=document.querySelector(e);if(!t)throw new r("container",`element not found: ${e}`,e)}(this.checkoutConfig.container),this.apiClient=new y({baseUrl:this.baseUrl||a.BASE_URL,orgId:this.orgId,timeout:a.REQUEST_TIMEOUT,retryAttempts:a.RETRY_ATTEMPTS});const e=await this.apiClient.createClientSession({priceId:this.checkoutConfig.priceId,externalId:this.checkoutConfig.customer.externalId,email:this.checkoutConfig.customer.email,region:this.region||a.REGION,clientMetadata:this.checkoutConfig.clientMetadata,countryCode:this.checkoutConfig.customer.countryCode}),t=this.apiClient.processSessionResponse(e);return this.orderId=t.orderId,this.clientToken=t.clientToken,await this._initializePrimerCheckout(),this._setState("ready"),this}catch(e){throw this._setState("error"),this.emit("error",e),e}}async _initializePrimerCheckout(){const e={container:this.checkoutConfig.container,onTokenizeSuccess:this._handleTokenizeSuccess,onResumeSuccess:this._handleResumeSuccess,...this.checkoutConfig.universalCheckoutOptions||{}};await this.primerWrapper.showUniversalCheckout(this.clientToken,e)}async _handleTokenizeSuccess(e,t){try{this._setState("processing");const r=await this.apiClient.createPayment({orderId:this.orderId,paymentMethodToken:e.token}),s=this.apiClient.processPaymentResponse(r);await this._processPaymentResult(s,t)}catch(e){this._setState("error"),this.emit("error",e),t.handleFailure(e.message||"Payment processing failed")}}async _handleResumeSuccess(e,t){try{this._setState("processing");const r=await this.apiClient.resumePayment({orderId:this.orderId,resumeToken:e.resumeToken}),s=this.apiClient.processPaymentResponse(r);await this._processPaymentResult(s,t)}catch(e){this._setState("error"),this.emit("error",e),t.handleFailure(e.message||"Payment processing failed")}}async _processPaymentResult(e,t){switch(e.type){case"success":this._setState("completed"),this.emit("success",{orderId:e.orderId,status:e.status,transactionId:e.transactionId,metadata:e.metadata}),t.handleSuccess();break;case"action_required":this._setState("action_required"),this.clientToken=e.clientToken,t.continueWithNewClientToken(e.clientToken);break;case"processing":this._setState("processing"),setTimeout(()=>{t.handleFailure("Payment is still processing. Please check back later.")},3e4);break;default:throw new i(`Unknown payment result type: ${e.type}`)}}async updatePrice(e){if(this._ensureNotDestroyed(),p(e,"priceId"),"processing"===this.state)throw new i("Cannot update price while payment is processing");try{this._setState("updating"),await this.apiClient.updateClientSession({orderId:this.orderId,clientToken:this.clientToken,priceId:e}),this.checkoutConfig.priceId=e,this._setState("ready"),this.emit("status-change","price-updated")}catch(e){throw this._setState("error"),this.emit("error",e),e}}getStatus(){return{id:this.id,state:this.state,orderId:this.orderId,priceId:this.checkoutConfig.priceId,isDestroyed:this.isDestroyed}}async destroy(){if(!this.isDestroyed)try{await this.primerWrapper.destroy(),this._setState("destroyed"),this.orderId=null,this.clientToken=null,this.isDestroyed=!0,this.emit("destroy"),this.removeAllListeners()}catch(e){console.warn("Error during checkout cleanup:",e)}}_setState(e){if(this.state!==e){const t=this.state;this.state=e,this.emit("status-change",e,t)}}_ensureNotDestroyed(){if(this.isDestroyed)throw new i("Checkout instance has been destroyed")}getContainer(){return document.querySelector(this.checkoutConfig.container)}isInState(e){return this.state===e}isReady(){return"ready"===this.state&&!this.isDestroyed}isProcessing(){return["processing","action_required"].includes(this.state)}}let _=null;function f(e){_=e}function k(e,t){const{orgId:r,apiConfig:s}=e,n=r||_?.orgId;if(!n)throw new Error(`orgId is required. Pass it to ${t}() or call configure() first.`);return{orgId:n,baseUrl:s?.baseUrl||_?.baseUrl||a.BASE_URL,region:s?.region||_?.region||a.REGION}}async function w(e){const{...t}=e;(new l).ensurePrimerAvailable();const r=k(e,"createCheckout"),s=new m({...r,checkoutConfig:t});return await s.initialize(),s}async function R(e,t){const{default:r}=await Promise.resolve().then(function(){return d}),s=new r;return await s.showUniversalCheckout(e,t)}async function g(e){const{priceId:t,externalId:r,email:s,clientMetadata:n,countryCode:i}=e,o=k(e,"createClientSession"),c=new y({baseUrl:o.baseUrl,orgId:o.orgId,timeout:a.REQUEST_TIMEOUT,retryAttempts:a.RETRY_ATTEMPTS}),u=await c.createClientSession({priceId:t,externalId:r,email:s,region:o.region,clientMetadata:n,countryCode:i});return c.processSessionResponse(u)}const C={configure:f,createCheckout:w,showUniversalCheckout:R,createClientSession:g};"undefined"!=typeof window&&(window.Billing=C),e.APIError=s,e.Billing=C,e.CHECKOUT_STATES={INITIALIZING:"initializing",READY:"ready",PROCESSING:"processing",ACTION_REQUIRED:"action_required",UPDATING:"updating",COMPLETED:"completed",ERROR:"error",DESTROYED:"destroyed"},e.CheckoutError=i,e.ConfigurationError=class extends t{constructor(e){super(e,"CONFIGURATION_ERROR"),this.name="ConfigurationError"}},e.DEFAULTS=a,e.ERROR_CODES={SDK_ERROR:"SDK_ERROR",VALIDATION_ERROR:"VALIDATION_ERROR",API_ERROR:"API_ERROR",PRIMER_ERROR:"PRIMER_ERROR",CHECKOUT_ERROR:"CHECKOUT_ERROR",CONFIGURATION_ERROR:"CONFIGURATION_ERROR",NETWORK_ERROR:"NETWORK_ERROR"},e.EVENTS={SUCCESS:"success",ERROR:"error",STATUS_CHANGE:"status-change",DESTROY:"destroy"},e.FunnefoxSDKError=t,e.NetworkError=o,e.PrimerError=n,e.SDK_VERSION="0.1.0",e.ValidationError=r,e.configure=f,e.createCheckout=w,e.createClientSession=g,e.default=C,e.showUniversalCheckout=R,Object.defineProperty(e,"__esModule",{value:!0})});
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@funnelfox/billing",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"author": "Funnelfox",
|
|
6
|
+
"description": "JavaScript SDK for Funnelfox billing with Primer integration",
|
|
7
|
+
"main": "dist/funnelfox-billing.js",
|
|
8
|
+
"module": "dist/funnelfox-billing.esm.js",
|
|
9
|
+
"types": "types.d.ts",
|
|
10
|
+
"sideEffects": false,
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./types.d.ts",
|
|
14
|
+
"import": "./dist/funnelfox-billing.esm.js",
|
|
15
|
+
"require": "./dist/funnelfox-billing.cjs.js",
|
|
16
|
+
"default": "./dist/funnelfox-billing.js"
|
|
17
|
+
},
|
|
18
|
+
"./types": {
|
|
19
|
+
"types": "./types.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist/",
|
|
24
|
+
"src/types.d.ts",
|
|
25
|
+
"types.d.ts"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "rollup -c",
|
|
29
|
+
"build:watch": "rollup -c -w",
|
|
30
|
+
"dev": "rollup -c -w",
|
|
31
|
+
"lint": "eslint src/**/*.js",
|
|
32
|
+
"lint:fix": "eslint src/**/*.js --fix",
|
|
33
|
+
"format": "prettier --write \"src/**/*.js\" \"*.{js,json,md}\"",
|
|
34
|
+
"format:check": "prettier --check \"src/**/*.js\" \"*.{js,json,md}\"",
|
|
35
|
+
"typecheck": "tsc --noEmit",
|
|
36
|
+
"test": "jest",
|
|
37
|
+
"test:watch": "jest --watch",
|
|
38
|
+
"test:coverage": "jest --coverage",
|
|
39
|
+
"validate": "npm run lint && npm run format:check && npm run typecheck && npm run test",
|
|
40
|
+
"prepublishOnly": "npm run validate && npm run build"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"payments",
|
|
44
|
+
"billing",
|
|
45
|
+
"checkout",
|
|
46
|
+
"subscription",
|
|
47
|
+
"primer",
|
|
48
|
+
"sdk",
|
|
49
|
+
"javascript",
|
|
50
|
+
"funnelfox"
|
|
51
|
+
],
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@primer-io/checkout-web": "^2.x"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@babel/core": "^7.23.0",
|
|
57
|
+
"@babel/preset-env": "^7.23.0",
|
|
58
|
+
"@rollup/plugin-babel": "^6.0.0",
|
|
59
|
+
"@rollup/plugin-node-resolve": "^15.2.0",
|
|
60
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
61
|
+
"babel-jest": "^29.7.0",
|
|
62
|
+
"eslint": "^8.52.0",
|
|
63
|
+
"jest": "^29.7.0",
|
|
64
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
65
|
+
"prettier": "^3.0.0",
|
|
66
|
+
"rollup": "^4.0.0",
|
|
67
|
+
"typescript": "^5.2.0"
|
|
68
|
+
},
|
|
69
|
+
"engines": {
|
|
70
|
+
"node": ">=14.0.0"
|
|
71
|
+
},
|
|
72
|
+
"repository": {
|
|
73
|
+
"type": "git",
|
|
74
|
+
"url": "https://github.com/funnelfox/billing-sdk.git"
|
|
75
|
+
},
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/funnelfox/billing-sdk/issues"
|
|
78
|
+
},
|
|
79
|
+
"homepage": "https://github.com/funnelfox/billing-sdk#readme"
|
|
80
|
+
}
|
package/src/types.d.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript definitions for @funnelfox/billing
|
|
3
|
+
* These types are importable by users and used internally via JSDoc
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface SDKConfig {
|
|
7
|
+
orgId: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
region?: string;
|
|
10
|
+
sandbox?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface APIConfig {
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
region?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Customer {
|
|
19
|
+
email: string;
|
|
20
|
+
externalId: string;
|
|
21
|
+
countryCode?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CheckoutConfig {
|
|
25
|
+
customer: Customer;
|
|
26
|
+
priceId: string;
|
|
27
|
+
container: string;
|
|
28
|
+
clientMetadata?: Record<string, any>;
|
|
29
|
+
universalCheckoutOptions?: PrimerCheckoutOptions;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface CheckoutConfigWithCallbacks extends CheckoutConfig {
|
|
33
|
+
onSuccess?: (result: PaymentResult) => void;
|
|
34
|
+
onError?: (error: Error) => void;
|
|
35
|
+
onStatusChange?: (newState: CheckoutState, oldState?: CheckoutState) => void;
|
|
36
|
+
onDestroy?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CreateCheckoutOptions extends CheckoutConfigWithCallbacks {
|
|
40
|
+
orgId?: string;
|
|
41
|
+
apiConfig?: APIConfig;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PrimerCheckoutOptions {
|
|
45
|
+
paymentHandling?: 'MANUAL' | 'AUTO';
|
|
46
|
+
apiVersion?: string;
|
|
47
|
+
paypal?: {
|
|
48
|
+
buttonColor?: 'blue' | 'gold' | 'silver' | 'white' | 'black';
|
|
49
|
+
paymentFlow?: 'PREFER_VAULT' | 'VAULT_ONLY' | 'CHECKOUT_ONLY';
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface PaymentResult {
|
|
54
|
+
orderId: string;
|
|
55
|
+
status: 'succeeded' | 'failed' | 'cancelled' | 'processing';
|
|
56
|
+
transactionId?: string;
|
|
57
|
+
failureReason?: string;
|
|
58
|
+
metadata?: Record<string, any>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type CheckoutState =
|
|
62
|
+
| 'initializing'
|
|
63
|
+
| 'ready'
|
|
64
|
+
| 'processing'
|
|
65
|
+
| 'action_required'
|
|
66
|
+
| 'updating'
|
|
67
|
+
| 'completed'
|
|
68
|
+
| 'error'
|
|
69
|
+
| 'destroyed';
|
|
70
|
+
|
|
71
|
+
export type CheckoutEventName = 'success' | 'error' | 'status-change' | 'destroy';
|
|
72
|
+
|
|
73
|
+
export interface CheckoutStatus {
|
|
74
|
+
id: string;
|
|
75
|
+
state: CheckoutState;
|
|
76
|
+
orderId: string | null;
|
|
77
|
+
priceId: string;
|
|
78
|
+
isDestroyed: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CheckoutInstance {
|
|
82
|
+
readonly id: string;
|
|
83
|
+
readonly state: CheckoutState;
|
|
84
|
+
readonly orderId: string | null;
|
|
85
|
+
readonly isDestroyed: boolean;
|
|
86
|
+
|
|
87
|
+
updatePrice(newPriceId: string): Promise<void>;
|
|
88
|
+
getStatus(): CheckoutStatus;
|
|
89
|
+
destroy(): Promise<void>;
|
|
90
|
+
getContainer(): Element | null;
|
|
91
|
+
isInState(state: CheckoutState): boolean;
|
|
92
|
+
isReady(): boolean;
|
|
93
|
+
isProcessing(): boolean;
|
|
94
|
+
|
|
95
|
+
on(eventName: 'success', handler: (result: PaymentResult) => void): this;
|
|
96
|
+
on(eventName: 'error', handler: (error: Error) => void): this;
|
|
97
|
+
on(eventName: 'status-change', handler: (newState: CheckoutState, oldState?: CheckoutState) => void): this;
|
|
98
|
+
on(eventName: 'destroy', handler: () => void): this;
|
|
99
|
+
on(eventName: CheckoutEventName, handler: (...args: any[]) => void): this;
|
|
100
|
+
|
|
101
|
+
off(eventName: CheckoutEventName, handler?: Function): this;
|
|
102
|
+
once(eventName: CheckoutEventName, handler: Function): this;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// API Response types
|
|
106
|
+
export interface ClientSessionResponse {
|
|
107
|
+
status: 'success' | 'error';
|
|
108
|
+
data: {
|
|
109
|
+
client_token: string;
|
|
110
|
+
order_id: string;
|
|
111
|
+
action_required_token?: string;
|
|
112
|
+
checkout_status?: 'succeeded' | 'failed' | 'cancelled' | 'processing';
|
|
113
|
+
failed_message_for_user?: string;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface PaymentMethodTokenData {
|
|
118
|
+
token: string;
|
|
119
|
+
metadata?: Record<string, any>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface ResumeTokenData {
|
|
123
|
+
resumeToken: string;
|
|
124
|
+
metadata?: Record<string, any>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface PrimerHandler {
|
|
128
|
+
handleSuccess(): void;
|
|
129
|
+
handleFailure(message: string): void;
|
|
130
|
+
continueWithNewClientToken(token: string): void;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Error types
|
|
134
|
+
export interface FunnefoxSDKError extends Error {
|
|
135
|
+
code: string;
|
|
136
|
+
details: any;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface ValidationError extends FunnefoxSDKError {
|
|
140
|
+
field: string;
|
|
141
|
+
value: any;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface APIError extends FunnefoxSDKError {
|
|
145
|
+
statusCode: number | null;
|
|
146
|
+
errorCode: string | null;
|
|
147
|
+
errorType: string | null;
|
|
148
|
+
requestId: string | null;
|
|
149
|
+
response: any;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface PrimerError extends FunnefoxSDKError {
|
|
153
|
+
primerError: any;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface CheckoutError extends FunnefoxSDKError {
|
|
157
|
+
phase: string | null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ConfigurationError extends FunnefoxSDKError {}
|
|
161
|
+
|
|
162
|
+
export interface NetworkError extends FunnefoxSDKError {
|
|
163
|
+
originalError: any;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Function signatures
|
|
167
|
+
export declare function configure(config: SDKConfig): void;
|
|
168
|
+
|
|
169
|
+
export declare function createCheckout(options: CreateCheckoutOptions): Promise<CheckoutInstance>;
|
|
170
|
+
|
|
171
|
+
export declare function showUniversalCheckout(clientToken: string, options: any): Promise<any>;
|
|
172
|
+
|
|
173
|
+
export interface CreateClientSessionOptions {
|
|
174
|
+
priceId: string;
|
|
175
|
+
externalId: string;
|
|
176
|
+
email: string;
|
|
177
|
+
orgId?: string;
|
|
178
|
+
apiConfig?: APIConfig;
|
|
179
|
+
clientMetadata?: Record<string, any>;
|
|
180
|
+
countryCode?: string;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface ClientSessionData {
|
|
184
|
+
clientToken: string;
|
|
185
|
+
orderId: string;
|
|
186
|
+
type: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export declare function createClientSession(params: CreateClientSessionOptions): Promise<ClientSessionData>;
|
|
190
|
+
|
|
191
|
+
// Billing namespace
|
|
192
|
+
export declare const Billing: {
|
|
193
|
+
configure: typeof configure;
|
|
194
|
+
createCheckout: typeof createCheckout;
|
|
195
|
+
showUniversalCheckout: typeof showUniversalCheckout;
|
|
196
|
+
createClientSession: typeof createClientSession;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Constants
|
|
200
|
+
export declare const SDK_VERSION: string;
|
|
201
|
+
export declare const CHECKOUT_STATES: Record<string, CheckoutState>;
|
|
202
|
+
export declare const EVENTS: Record<string, CheckoutEventName>;
|
|
203
|
+
export declare const ERROR_CODES: Record<string, string>;
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript definitions for @funnelfox/billing
|
|
3
|
+
* These types are importable by users and used internally via JSDoc
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface SDKConfig {
|
|
7
|
+
orgId: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
region?: string;
|
|
10
|
+
sandbox?: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface APIConfig {
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
region?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Customer {
|
|
19
|
+
email: string;
|
|
20
|
+
externalId: string;
|
|
21
|
+
countryCode?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface CheckoutConfig {
|
|
25
|
+
customer: Customer;
|
|
26
|
+
priceId: string;
|
|
27
|
+
container: string;
|
|
28
|
+
clientMetadata?: Record<string, any>;
|
|
29
|
+
universalCheckoutOptions?: PrimerCheckoutOptions;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface CheckoutConfigWithCallbacks extends CheckoutConfig {
|
|
33
|
+
onSuccess?: (result: PaymentResult) => void;
|
|
34
|
+
onError?: (error: Error) => void;
|
|
35
|
+
onStatusChange?: (newState: CheckoutState, oldState?: CheckoutState) => void;
|
|
36
|
+
onDestroy?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface CreateCheckoutOptions extends CheckoutConfigWithCallbacks {
|
|
40
|
+
orgId?: string;
|
|
41
|
+
apiConfig?: APIConfig;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PrimerCheckoutOptions {
|
|
45
|
+
paymentHandling?: 'MANUAL' | 'AUTO';
|
|
46
|
+
apiVersion?: string;
|
|
47
|
+
paypal?: {
|
|
48
|
+
buttonColor?: 'blue' | 'gold' | 'silver' | 'white' | 'black';
|
|
49
|
+
paymentFlow?: 'PREFER_VAULT' | 'VAULT_ONLY' | 'CHECKOUT_ONLY';
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface PaymentResult {
|
|
54
|
+
orderId: string;
|
|
55
|
+
status: 'succeeded' | 'failed' | 'cancelled' | 'processing';
|
|
56
|
+
transactionId?: string;
|
|
57
|
+
failureReason?: string;
|
|
58
|
+
metadata?: Record<string, any>;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type CheckoutState =
|
|
62
|
+
| 'initializing'
|
|
63
|
+
| 'ready'
|
|
64
|
+
| 'processing'
|
|
65
|
+
| 'action_required'
|
|
66
|
+
| 'updating'
|
|
67
|
+
| 'completed'
|
|
68
|
+
| 'error'
|
|
69
|
+
| 'destroyed';
|
|
70
|
+
|
|
71
|
+
export type CheckoutEventName = 'success' | 'error' | 'status-change' | 'destroy';
|
|
72
|
+
|
|
73
|
+
export interface CheckoutStatus {
|
|
74
|
+
id: string;
|
|
75
|
+
state: CheckoutState;
|
|
76
|
+
orderId: string | null;
|
|
77
|
+
priceId: string;
|
|
78
|
+
isDestroyed: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface CheckoutInstance {
|
|
82
|
+
readonly id: string;
|
|
83
|
+
readonly state: CheckoutState;
|
|
84
|
+
readonly orderId: string | null;
|
|
85
|
+
readonly isDestroyed: boolean;
|
|
86
|
+
|
|
87
|
+
updatePrice(newPriceId: string): Promise<void>;
|
|
88
|
+
getStatus(): CheckoutStatus;
|
|
89
|
+
destroy(): Promise<void>;
|
|
90
|
+
getContainer(): Element | null;
|
|
91
|
+
isInState(state: CheckoutState): boolean;
|
|
92
|
+
isReady(): boolean;
|
|
93
|
+
isProcessing(): boolean;
|
|
94
|
+
|
|
95
|
+
on(eventName: 'success', handler: (result: PaymentResult) => void): this;
|
|
96
|
+
on(eventName: 'error', handler: (error: Error) => void): this;
|
|
97
|
+
on(eventName: 'status-change', handler: (newState: CheckoutState, oldState?: CheckoutState) => void): this;
|
|
98
|
+
on(eventName: 'destroy', handler: () => void): this;
|
|
99
|
+
on(eventName: CheckoutEventName, handler: (...args: any[]) => void): this;
|
|
100
|
+
|
|
101
|
+
off(eventName: CheckoutEventName, handler?: Function): this;
|
|
102
|
+
once(eventName: CheckoutEventName, handler: Function): this;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// API Response types
|
|
106
|
+
export interface ClientSessionResponse {
|
|
107
|
+
status: 'success' | 'error';
|
|
108
|
+
data: {
|
|
109
|
+
client_token: string;
|
|
110
|
+
order_id: string;
|
|
111
|
+
action_required_token?: string;
|
|
112
|
+
checkout_status?: 'succeeded' | 'failed' | 'cancelled' | 'processing';
|
|
113
|
+
failed_message_for_user?: string;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface PaymentMethodTokenData {
|
|
118
|
+
token: string;
|
|
119
|
+
metadata?: Record<string, any>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export interface ResumeTokenData {
|
|
123
|
+
resumeToken: string;
|
|
124
|
+
metadata?: Record<string, any>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export interface PrimerHandler {
|
|
128
|
+
handleSuccess(): void;
|
|
129
|
+
handleFailure(message: string): void;
|
|
130
|
+
continueWithNewClientToken(token: string): void;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Error types
|
|
134
|
+
export interface FunnefoxSDKError extends Error {
|
|
135
|
+
code: string;
|
|
136
|
+
details: any;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export interface ValidationError extends FunnefoxSDKError {
|
|
140
|
+
field: string;
|
|
141
|
+
value: any;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface APIError extends FunnefoxSDKError {
|
|
145
|
+
statusCode: number | null;
|
|
146
|
+
errorCode: string | null;
|
|
147
|
+
errorType: string | null;
|
|
148
|
+
requestId: string | null;
|
|
149
|
+
response: any;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface PrimerError extends FunnefoxSDKError {
|
|
153
|
+
primerError: any;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface CheckoutError extends FunnefoxSDKError {
|
|
157
|
+
phase: string | null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ConfigurationError extends FunnefoxSDKError {}
|
|
161
|
+
|
|
162
|
+
export interface NetworkError extends FunnefoxSDKError {
|
|
163
|
+
originalError: any;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Function signatures
|
|
167
|
+
export declare function configure(config: SDKConfig): void;
|
|
168
|
+
|
|
169
|
+
export declare function createCheckout(options: CreateCheckoutOptions): Promise<CheckoutInstance>;
|
|
170
|
+
|
|
171
|
+
export declare function showUniversalCheckout(clientToken: string, options: any): Promise<any>;
|
|
172
|
+
|
|
173
|
+
export interface CreateClientSessionOptions {
|
|
174
|
+
priceId: string;
|
|
175
|
+
externalId: string;
|
|
176
|
+
email: string;
|
|
177
|
+
orgId?: string;
|
|
178
|
+
apiConfig?: APIConfig;
|
|
179
|
+
clientMetadata?: Record<string, any>;
|
|
180
|
+
countryCode?: string;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface ClientSessionData {
|
|
184
|
+
clientToken: string;
|
|
185
|
+
orderId: string;
|
|
186
|
+
type: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export declare function createClientSession(params: CreateClientSessionOptions): Promise<ClientSessionData>;
|
|
190
|
+
|
|
191
|
+
// Billing namespace
|
|
192
|
+
export declare const Billing: {
|
|
193
|
+
configure: typeof configure;
|
|
194
|
+
createCheckout: typeof createCheckout;
|
|
195
|
+
showUniversalCheckout: typeof showUniversalCheckout;
|
|
196
|
+
createClientSession: typeof createClientSession;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Constants
|
|
200
|
+
export declare const SDK_VERSION: string;
|
|
201
|
+
export declare const CHECKOUT_STATES: Record<string, CheckoutState>;
|
|
202
|
+
export declare const EVENTS: Record<string, CheckoutEventName>;
|
|
203
|
+
export declare const ERROR_CODES: Record<string, string>;
|