bkash-client 0.0.0-stage → 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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -2
  3. package/dist/angular.cjs +149 -0
  4. package/dist/angular.cjs.map +1 -0
  5. package/dist/angular.d.cts +21 -0
  6. package/dist/angular.d.ts +21 -0
  7. package/dist/angular.js +29 -0
  8. package/dist/angular.js.map +1 -0
  9. package/dist/bkash-client.browser.global.js +149 -0
  10. package/dist/bkash-client.browser.global.js.map +1 -0
  11. package/dist/chunk-DGUM43GV.js +10 -0
  12. package/dist/chunk-DGUM43GV.js.map +1 -0
  13. package/dist/chunk-FXLW32P4.js +124 -0
  14. package/dist/chunk-FXLW32P4.js.map +1 -0
  15. package/dist/index.cjs +126 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.cts +70 -0
  18. package/dist/index.d.ts +70 -0
  19. package/dist/index.js +4 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/react-native.cjs +68 -0
  22. package/dist/react-native.cjs.map +1 -0
  23. package/dist/react-native.d.cts +35 -0
  24. package/dist/react-native.d.ts +35 -0
  25. package/dist/react-native.js +61 -0
  26. package/dist/react-native.js.map +1 -0
  27. package/dist/react.cjs +190 -0
  28. package/dist/react.cjs.map +1 -0
  29. package/dist/react.d.cts +27 -0
  30. package/dist/react.d.ts +27 -0
  31. package/dist/react.js +65 -0
  32. package/dist/react.js.map +1 -0
  33. package/dist/svelte.cjs +141 -0
  34. package/dist/svelte.cjs.map +1 -0
  35. package/dist/svelte.d.cts +16 -0
  36. package/dist/svelte.d.ts +16 -0
  37. package/dist/svelte.js +21 -0
  38. package/dist/svelte.js.map +1 -0
  39. package/dist/vue.cjs +169 -0
  40. package/dist/vue.cjs.map +1 -0
  41. package/dist/vue.d.cts +21 -0
  42. package/dist/vue.d.ts +21 -0
  43. package/dist/vue.js +45 -0
  44. package/dist/vue.js.map +1 -0
  45. package/package.json +159 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Open Source & Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,63 @@
1
- # Temporary Holding Version
1
+ # bkash-client
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Headless checkout bindings for [bKash](https://www.bkash.com) payments: React, React Native, Vue 3, Svelte, Angular and plain JavaScript. Pairs with [`bkash-server`](https://www.npmjs.com/package/bkash-server).
4
+
5
+ [![CI](https://github.com/iamtashanto/Bkash/actions/workflows/ci.yml/badge.svg)](https://github.com/iamtashanto/Bkash/actions/workflows/ci.yml)
6
+ [![npm](https://img.shields.io/npm/v/bkash-client)](https://www.npmjs.com/package/bkash-client)
7
+ [![license](https://img.shields.io/npm/l/bkash-client)](https://github.com/iamtashanto/Bkash/blob/main/LICENSE)
8
+
9
+ > **Unofficial.** Not affiliated with, endorsed by, or sponsored by bKash Limited. "bKash" is a trademark of bKash Limited.
10
+
11
+ **Documentation:** <https://bkash-sdk.tashanto.com/docs/client-guide/> · **Issues:** <https://github.com/iamtashanto/Bkash/issues>
12
+
13
+ ## Why
14
+
15
+ - **Never holds secrets or prices.** It only calls your own `/create` route; the server decides the amount.
16
+ - **States that tell the truth.** `idle`, `creating`, `awaiting_user`, `verifying`, `success`, `pending`, `timeout`, `offline`, `cancelled`, `error`. An unknown outcome shows "payment pending, do not pay again", not a failure.
17
+ - **Headless.** No CSS, no modal: you own the markup and the brand.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ npm install bkash-client
23
+ ```
24
+
25
+ Optional peers: `react`, `vue`, `react-native` and `react-native-webview` (only for the matching binding).
26
+
27
+ ## Quickstart (React)
28
+
29
+ ```tsx
30
+ import { useBkash, BkashButton } from 'bkash-client/react';
31
+
32
+ export function CheckoutPage() {
33
+ const { state, error } = useBkash({ createUrl: '/api/bkash/create' });
34
+ return (
35
+ <div>
36
+ <BkashButton>Pay with bKash</BkashButton>
37
+ {state === 'pending' && <p>Payment pending. Do not pay again.</p>}
38
+ {error && <p>{error.message}</p>}
39
+ </div>
40
+ );
41
+ }
42
+ ```
43
+
44
+ Other bindings (React Native, Vue, Svelte, Angular, vanilla) are in the [client guide](https://bkash-sdk.tashanto.com/docs/client-guide/).
45
+
46
+ ## What is supported
47
+
48
+ <!-- status:start -->
49
+ <!-- Generated from website/src/data/status.json. Do not edit by hand. -->
50
+ | Feature | Status | Evidence |
51
+ | --- | --- | --- |
52
+ | React hook and button | Beta | automated tests (React Testing Library) |
53
+ | Vue 3 composable | Beta | automated tests (Vue Test Utils) |
54
+ | Svelte store | Beta | automated tests |
55
+ | Angular service | Beta | automated tests |
56
+ | React Native WebView checkout | Experimental | automated tests (React Native Testing Library); NOT TESTED on a device |
57
+ <!-- status:end -->
58
+
59
+ > **Android back button:** `BkashCheckout` does not handle the hardware back button yet. Confirm with your navigation library before leaving a payment in progress.
60
+
61
+ ## License
62
+
63
+ MIT
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ // src/index.ts
4
+ var BkashClient = class {
5
+ state = "idle";
6
+ options;
7
+ currentPaymentId = null;
8
+ listeners = /* @__PURE__ */ new Set();
9
+ constructor(options) {
10
+ this.options = {
11
+ createUrl: "/api/bkash/create",
12
+ ...options
13
+ };
14
+ }
15
+ getState() {
16
+ return this.state;
17
+ }
18
+ getPaymentId() {
19
+ return this.currentPaymentId;
20
+ }
21
+ /**
22
+ * Returns human-readable UI guidance for the current client state.
23
+ * Specifically guarantees that unknown or timed-out outcomes are presented as
24
+ * "payment pending, do not pay again" rather than a false failure.
25
+ */
26
+ getStateMessage() {
27
+ switch (this.state) {
28
+ case "idle":
29
+ return "Ready to initiate checkout.";
30
+ case "creating":
31
+ return "Initializing payment session with bKash...";
32
+ case "awaiting_user":
33
+ return "Redirecting to bKash secure payment page...";
34
+ case "verifying":
35
+ return "Verifying payment with bKash...";
36
+ case "success":
37
+ return "Payment completed successfully!";
38
+ case "pending":
39
+ case "timeout":
40
+ return "Payment pending, do not pay again. Please wait while your transaction is reconciled with bKash.";
41
+ case "cancelled":
42
+ return "Payment was cancelled.";
43
+ case "offline":
44
+ return "Device is offline. Please check your internet connection before retrying.";
45
+ case "error":
46
+ return "An error occurred during checkout.";
47
+ default:
48
+ return "";
49
+ }
50
+ }
51
+ subscribe(listener) {
52
+ this.listeners.add(listener);
53
+ return () => this.listeners.delete(listener);
54
+ }
55
+ cancel() {
56
+ this.setState("cancelled");
57
+ this.options.onCancel?.();
58
+ }
59
+ setPending(paymentId) {
60
+ if (paymentId) this.currentPaymentId = paymentId;
61
+ this.setState("pending");
62
+ }
63
+ setState(newState) {
64
+ this.state = newState;
65
+ this.options.onStateChange?.(newState);
66
+ this.listeners.forEach((fn) => fn(newState));
67
+ }
68
+ /**
69
+ * Initiates payment flow by calling the merchant backend,
70
+ * obtaining the gateway URL, and redirecting the customer.
71
+ */
72
+ async checkout(params = {}) {
73
+ if (typeof navigator !== "undefined" && navigator.onLine === false) {
74
+ this.setState("offline");
75
+ const offlineErr = new Error("Device is offline. Please check your internet connection.");
76
+ this.options.onError?.(offlineErr);
77
+ throw offlineErr;
78
+ }
79
+ try {
80
+ this.setState("creating");
81
+ const defaultCallback = typeof window !== "undefined" ? window.location?.href : "";
82
+ const res = await fetch(this.options.createUrl, {
83
+ method: "POST",
84
+ headers: { "Content-Type": "application/json" },
85
+ body: JSON.stringify({
86
+ amount: params.amount,
87
+ invoiceNumber: params.invoiceNumber,
88
+ orderId: params.orderId,
89
+ callbackUrl: this.options.callbackUrl || defaultCallback,
90
+ payerReference: params.payerReference,
91
+ metadata: params.metadata
92
+ })
93
+ });
94
+ if (!res.ok) {
95
+ throw new Error(`Failed to create payment session: HTTP ${res.status}`);
96
+ }
97
+ const data = await res.json();
98
+ if (!data.redirectUrl || !data.paymentId) {
99
+ throw new Error(data.error || "Invalid session response from payment server.");
100
+ }
101
+ this.currentPaymentId = data.paymentId;
102
+ this.setState("awaiting_user");
103
+ if (typeof window !== "undefined" && window.location) {
104
+ window.location.href = data.redirectUrl;
105
+ }
106
+ } catch (err) {
107
+ const error = err instanceof Error ? err : new Error(String(err));
108
+ const isTimeout = error.name === "AbortError" || error.name === "TimeoutError" || /timeout|abort/i.test(error.message);
109
+ if (isTimeout) {
110
+ this.setState("pending");
111
+ } else {
112
+ this.setState("error");
113
+ }
114
+ this.options.onError?.(error);
115
+ throw error;
116
+ }
117
+ }
118
+ reset() {
119
+ this.currentPaymentId = null;
120
+ this.setState("idle");
121
+ }
122
+ };
123
+
124
+ // src/angular.ts
125
+ var BkashService = class {
126
+ client;
127
+ constructor(options) {
128
+ this.client = new BkashClient(options);
129
+ }
130
+ getState() {
131
+ return this.client.getState();
132
+ }
133
+ getPaymentId() {
134
+ return this.client.getPaymentId();
135
+ }
136
+ subscribe(listener) {
137
+ return this.client.subscribe(listener);
138
+ }
139
+ checkout(params) {
140
+ return this.client.checkout(params);
141
+ }
142
+ reset() {
143
+ this.client.reset();
144
+ }
145
+ };
146
+
147
+ exports.BkashService = BkashService;
148
+ //# sourceMappingURL=angular.cjs.map
149
+ //# sourceMappingURL=angular.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/angular.ts"],"names":[],"mappings":"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","file":"angular.cjs","sourcesContent":["/**\n * @bkash/client\n * Universal, headless client SDK for bKash payment integrations.\n */\n\nexport type BkashClientState =\n | 'idle'\n | 'creating'\n | 'awaiting_user'\n | 'verifying'\n | 'success'\n | 'pending'\n | 'cancelled'\n | 'timeout'\n | 'offline'\n | 'error';\n\nexport interface BkashClientOptions {\n /**\n * Endpoint on merchant backend to create payment session.\n * Defaults to \"/api/bkash/create\".\n */\n createUrl?: string;\n /**\n * Callback URL registered with merchant backend.\n */\n callbackUrl?: string;\n /**\n * Hook triggered on state transition.\n */\n onStateChange?: (state: BkashClientState) => void;\n /**\n * Hook triggered when payment completes successfully.\n */\n onSuccess?: (paymentId: string) => void;\n /**\n * Hook triggered on payment error.\n */\n onError?: (error: Error) => void;\n /**\n * Hook triggered if user cancels payment.\n */\n onCancel?: () => void;\n}\n\n/**\n * All fields are optional hints. bkash-server decides the amount and invoice from its own\n * data and ignores any amount or invoice sent from the browser.\n */\nexport interface InitiateCheckoutParams {\n amount?: number | string;\n invoiceNumber?: string;\n orderId?: string;\n payerReference?: string;\n metadata?: Record<string, string>;\n}\n\nexport class BkashClient {\n private state: BkashClientState = 'idle';\n private options: BkashClientOptions;\n private currentPaymentId: string | null = null;\n private listeners = new Set<(state: BkashClientState) => void>();\n\n constructor(options?: BkashClientOptions) {\n this.options = {\n createUrl: '/api/bkash/create',\n ...options,\n };\n }\n\n public getState(): BkashClientState {\n return this.state;\n }\n\n public getPaymentId(): string | null {\n return this.currentPaymentId;\n }\n\n /**\n * Returns human-readable UI guidance for the current client state.\n * Specifically guarantees that unknown or timed-out outcomes are presented as\n * \"payment pending, do not pay again\" rather than a false failure.\n */\n public getStateMessage(): string {\n switch (this.state) {\n case 'idle':\n return 'Ready to initiate checkout.';\n case 'creating':\n return 'Initializing payment session with bKash...';\n case 'awaiting_user':\n return 'Redirecting to bKash secure payment page...';\n case 'verifying':\n return 'Verifying payment with bKash...';\n case 'success':\n return 'Payment completed successfully!';\n case 'pending':\n case 'timeout':\n return 'Payment pending, do not pay again. Please wait while your transaction is reconciled with bKash.';\n case 'cancelled':\n return 'Payment was cancelled.';\n case 'offline':\n return 'Device is offline. Please check your internet connection before retrying.';\n case 'error':\n return 'An error occurred during checkout.';\n default:\n return '';\n }\n }\n\n public subscribe(listener: (state: BkashClientState) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n public cancel(): void {\n this.setState('cancelled');\n this.options.onCancel?.();\n }\n\n public setPending(paymentId?: string): void {\n if (paymentId) this.currentPaymentId = paymentId;\n this.setState('pending');\n }\n\n private setState(newState: BkashClientState): void {\n this.state = newState;\n this.options.onStateChange?.(newState);\n this.listeners.forEach((fn) => fn(newState));\n }\n\n /**\n * Initiates payment flow by calling the merchant backend,\n * obtaining the gateway URL, and redirecting the customer.\n */\n public async checkout(params: InitiateCheckoutParams = {}): Promise<void> {\n // Offline pre-check\n if (typeof navigator !== 'undefined' && navigator.onLine === false) {\n this.setState('offline');\n const offlineErr = new Error('Device is offline. Please check your internet connection.');\n this.options.onError?.(offlineErr);\n throw offlineErr;\n }\n\n try {\n this.setState('creating');\n\n const defaultCallback = typeof window !== 'undefined' ? window.location?.href : '';\n const res = await fetch(this.options.createUrl!, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n amount: params.amount,\n invoiceNumber: params.invoiceNumber,\n orderId: params.orderId,\n callbackUrl: this.options.callbackUrl || defaultCallback,\n payerReference: params.payerReference,\n metadata: params.metadata,\n }),\n });\n\n if (!res.ok) {\n throw new Error(`Failed to create payment session: HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as {\n redirectUrl?: string;\n paymentId?: string;\n error?: string;\n };\n if (!data.redirectUrl || !data.paymentId) {\n throw new Error(data.error || 'Invalid session response from payment server.');\n }\n\n this.currentPaymentId = data.paymentId;\n this.setState('awaiting_user');\n\n // Launch bKash Hosted Checkout\n if (typeof window !== 'undefined' && window.location) {\n window.location.href = data.redirectUrl;\n }\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isTimeout =\n error.name === 'AbortError' ||\n error.name === 'TimeoutError' ||\n /timeout|abort/i.test(error.message);\n\n if (isTimeout) {\n // Under AUD-08: timeout / unknown outcome MUST display pending (\"do not pay again\")\n this.setState('pending');\n } else {\n this.setState('error');\n }\n\n this.options.onError?.(error);\n throw error;\n }\n }\n\n public reset(): void {\n this.currentPaymentId = null;\n this.setState('idle');\n }\n}\n","import {\n BkashClient,\n type BkashClientOptions,\n type BkashClientState,\n type InitiateCheckoutParams,\n} from './index.js';\n\n/**\n * Plain TypeScript Service for Angular applications.\n *\n * Design Decision & Justification:\n * Modern Angular (16+) seamlessly imports standard TypeScript services directly\n * without requiring the heavy complexity of ng-packagr / Angular Package Format (APF),\n * ensuring broad compatibility across Angular 16, 17, 18, and 19 without version pinning.\n */\nexport class BkashService {\n private client: BkashClient;\n\n constructor(options?: BkashClientOptions) {\n this.client = new BkashClient(options);\n }\n\n public getState(): BkashClientState {\n return this.client.getState();\n }\n\n public getPaymentId(): string | null {\n return this.client.getPaymentId();\n }\n\n public subscribe(listener: (state: BkashClientState) => void): () => void {\n return this.client.subscribe(listener);\n }\n\n public checkout(params: InitiateCheckoutParams): Promise<void> {\n return this.client.checkout(params);\n }\n\n public reset(): void {\n this.client.reset();\n }\n}\n"]}
@@ -0,0 +1,21 @@
1
+ import { BkashClientOptions, BkashClientState, InitiateCheckoutParams } from './index.cjs';
2
+
3
+ /**
4
+ * Plain TypeScript Service for Angular applications.
5
+ *
6
+ * Design Decision & Justification:
7
+ * Modern Angular (16+) seamlessly imports standard TypeScript services directly
8
+ * without requiring the heavy complexity of ng-packagr / Angular Package Format (APF),
9
+ * ensuring broad compatibility across Angular 16, 17, 18, and 19 without version pinning.
10
+ */
11
+ declare class BkashService {
12
+ private client;
13
+ constructor(options?: BkashClientOptions);
14
+ getState(): BkashClientState;
15
+ getPaymentId(): string | null;
16
+ subscribe(listener: (state: BkashClientState) => void): () => void;
17
+ checkout(params: InitiateCheckoutParams): Promise<void>;
18
+ reset(): void;
19
+ }
20
+
21
+ export { BkashService };
@@ -0,0 +1,21 @@
1
+ import { BkashClientOptions, BkashClientState, InitiateCheckoutParams } from './index.js';
2
+
3
+ /**
4
+ * Plain TypeScript Service for Angular applications.
5
+ *
6
+ * Design Decision & Justification:
7
+ * Modern Angular (16+) seamlessly imports standard TypeScript services directly
8
+ * without requiring the heavy complexity of ng-packagr / Angular Package Format (APF),
9
+ * ensuring broad compatibility across Angular 16, 17, 18, and 19 without version pinning.
10
+ */
11
+ declare class BkashService {
12
+ private client;
13
+ constructor(options?: BkashClientOptions);
14
+ getState(): BkashClientState;
15
+ getPaymentId(): string | null;
16
+ subscribe(listener: (state: BkashClientState) => void): () => void;
17
+ checkout(params: InitiateCheckoutParams): Promise<void>;
18
+ reset(): void;
19
+ }
20
+
21
+ export { BkashService };
@@ -0,0 +1,29 @@
1
+ import { BkashClient } from './chunk-FXLW32P4.js';
2
+ import './chunk-DGUM43GV.js';
3
+
4
+ // src/angular.ts
5
+ var BkashService = class {
6
+ client;
7
+ constructor(options) {
8
+ this.client = new BkashClient(options);
9
+ }
10
+ getState() {
11
+ return this.client.getState();
12
+ }
13
+ getPaymentId() {
14
+ return this.client.getPaymentId();
15
+ }
16
+ subscribe(listener) {
17
+ return this.client.subscribe(listener);
18
+ }
19
+ checkout(params) {
20
+ return this.client.checkout(params);
21
+ }
22
+ reset() {
23
+ this.client.reset();
24
+ }
25
+ };
26
+
27
+ export { BkashService };
28
+ //# sourceMappingURL=angular.js.map
29
+ //# sourceMappingURL=angular.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/angular.ts"],"names":[],"mappings":";;;;AAeO,IAAM,eAAN,MAAmB;AAAA,EAChB,MAAA;AAAA,EAER,YAAY,OAAA,EAA8B;AACxC,IAAA,IAAA,CAAK,MAAA,GAAS,IAAI,WAAA,CAAY,OAAO,CAAA;AAAA,EACvC;AAAA,EAEO,QAAA,GAA6B;AAClC,IAAA,OAAO,IAAA,CAAK,OAAO,QAAA,EAAS;AAAA,EAC9B;AAAA,EAEO,YAAA,GAA8B;AACnC,IAAA,OAAO,IAAA,CAAK,OAAO,YAAA,EAAa;AAAA,EAClC;AAAA,EAEO,UAAU,QAAA,EAAyD;AACxE,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,SAAA,CAAU,QAAQ,CAAA;AAAA,EACvC;AAAA,EAEO,SAAS,MAAA,EAA+C;AAC7D,IAAA,OAAO,IAAA,CAAK,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA;AAAA,EACpC;AAAA,EAEO,KAAA,GAAc;AACnB,IAAA,IAAA,CAAK,OAAO,KAAA,EAAM;AAAA,EACpB;AACF","file":"angular.js","sourcesContent":["import {\n BkashClient,\n type BkashClientOptions,\n type BkashClientState,\n type InitiateCheckoutParams,\n} from './index.js';\n\n/**\n * Plain TypeScript Service for Angular applications.\n *\n * Design Decision & Justification:\n * Modern Angular (16+) seamlessly imports standard TypeScript services directly\n * without requiring the heavy complexity of ng-packagr / Angular Package Format (APF),\n * ensuring broad compatibility across Angular 16, 17, 18, and 19 without version pinning.\n */\nexport class BkashService {\n private client: BkashClient;\n\n constructor(options?: BkashClientOptions) {\n this.client = new BkashClient(options);\n }\n\n public getState(): BkashClientState {\n return this.client.getState();\n }\n\n public getPaymentId(): string | null {\n return this.client.getPaymentId();\n }\n\n public subscribe(listener: (state: BkashClientState) => void): () => void {\n return this.client.subscribe(listener);\n }\n\n public checkout(params: InitiateCheckoutParams): Promise<void> {\n return this.client.checkout(params);\n }\n\n public reset(): void {\n this.client.reset();\n }\n}\n"]}
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var BkashClient = (() => {
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
+
23
+ // src/index.ts
24
+ var src_exports = {};
25
+ __export(src_exports, {
26
+ BkashClient: () => BkashClient
27
+ });
28
+ var BkashClient = class {
29
+ constructor(options) {
30
+ __publicField(this, "state", "idle");
31
+ __publicField(this, "options");
32
+ __publicField(this, "currentPaymentId", null);
33
+ __publicField(this, "listeners", /* @__PURE__ */ new Set());
34
+ this.options = {
35
+ createUrl: "/api/bkash/create",
36
+ ...options
37
+ };
38
+ }
39
+ getState() {
40
+ return this.state;
41
+ }
42
+ getPaymentId() {
43
+ return this.currentPaymentId;
44
+ }
45
+ /**
46
+ * Returns human-readable UI guidance for the current client state.
47
+ * Specifically guarantees that unknown or timed-out outcomes are presented as
48
+ * "payment pending, do not pay again" rather than a false failure.
49
+ */
50
+ getStateMessage() {
51
+ switch (this.state) {
52
+ case "idle":
53
+ return "Ready to initiate checkout.";
54
+ case "creating":
55
+ return "Initializing payment session with bKash...";
56
+ case "awaiting_user":
57
+ return "Redirecting to bKash secure payment page...";
58
+ case "verifying":
59
+ return "Verifying payment with bKash...";
60
+ case "success":
61
+ return "Payment completed successfully!";
62
+ case "pending":
63
+ case "timeout":
64
+ return "Payment pending, do not pay again. Please wait while your transaction is reconciled with bKash.";
65
+ case "cancelled":
66
+ return "Payment was cancelled.";
67
+ case "offline":
68
+ return "Device is offline. Please check your internet connection before retrying.";
69
+ case "error":
70
+ return "An error occurred during checkout.";
71
+ default:
72
+ return "";
73
+ }
74
+ }
75
+ subscribe(listener) {
76
+ this.listeners.add(listener);
77
+ return () => this.listeners.delete(listener);
78
+ }
79
+ cancel() {
80
+ this.setState("cancelled");
81
+ this.options.onCancel?.();
82
+ }
83
+ setPending(paymentId) {
84
+ if (paymentId) this.currentPaymentId = paymentId;
85
+ this.setState("pending");
86
+ }
87
+ setState(newState) {
88
+ this.state = newState;
89
+ this.options.onStateChange?.(newState);
90
+ this.listeners.forEach((fn) => fn(newState));
91
+ }
92
+ /**
93
+ * Initiates payment flow by calling the merchant backend,
94
+ * obtaining the gateway URL, and redirecting the customer.
95
+ */
96
+ async checkout(params = {}) {
97
+ if (typeof navigator !== "undefined" && navigator.onLine === false) {
98
+ this.setState("offline");
99
+ const offlineErr = new Error("Device is offline. Please check your internet connection.");
100
+ this.options.onError?.(offlineErr);
101
+ throw offlineErr;
102
+ }
103
+ try {
104
+ this.setState("creating");
105
+ const defaultCallback = typeof window !== "undefined" ? window.location?.href : "";
106
+ const res = await fetch(this.options.createUrl, {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ body: JSON.stringify({
110
+ amount: params.amount,
111
+ invoiceNumber: params.invoiceNumber,
112
+ orderId: params.orderId,
113
+ callbackUrl: this.options.callbackUrl || defaultCallback,
114
+ payerReference: params.payerReference,
115
+ metadata: params.metadata
116
+ })
117
+ });
118
+ if (!res.ok) {
119
+ throw new Error(`Failed to create payment session: HTTP ${res.status}`);
120
+ }
121
+ const data = await res.json();
122
+ if (!data.redirectUrl || !data.paymentId) {
123
+ throw new Error(data.error || "Invalid session response from payment server.");
124
+ }
125
+ this.currentPaymentId = data.paymentId;
126
+ this.setState("awaiting_user");
127
+ if (typeof window !== "undefined" && window.location) {
128
+ window.location.href = data.redirectUrl;
129
+ }
130
+ } catch (err) {
131
+ const error = err instanceof Error ? err : new Error(String(err));
132
+ const isTimeout = error.name === "AbortError" || error.name === "TimeoutError" || /timeout|abort/i.test(error.message);
133
+ if (isTimeout) {
134
+ this.setState("pending");
135
+ } else {
136
+ this.setState("error");
137
+ }
138
+ this.options.onError?.(error);
139
+ throw error;
140
+ }
141
+ }
142
+ reset() {
143
+ this.currentPaymentId = null;
144
+ this.setState("idle");
145
+ }
146
+ };
147
+ return __toCommonJS(src_exports);
148
+ })();
149
+ //# sourceMappingURL=bkash-client.browser.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @bkash/client\n * Universal, headless client SDK for bKash payment integrations.\n */\n\nexport type BkashClientState =\n | 'idle'\n | 'creating'\n | 'awaiting_user'\n | 'verifying'\n | 'success'\n | 'pending'\n | 'cancelled'\n | 'timeout'\n | 'offline'\n | 'error';\n\nexport interface BkashClientOptions {\n /**\n * Endpoint on merchant backend to create payment session.\n * Defaults to \"/api/bkash/create\".\n */\n createUrl?: string;\n /**\n * Callback URL registered with merchant backend.\n */\n callbackUrl?: string;\n /**\n * Hook triggered on state transition.\n */\n onStateChange?: (state: BkashClientState) => void;\n /**\n * Hook triggered when payment completes successfully.\n */\n onSuccess?: (paymentId: string) => void;\n /**\n * Hook triggered on payment error.\n */\n onError?: (error: Error) => void;\n /**\n * Hook triggered if user cancels payment.\n */\n onCancel?: () => void;\n}\n\n/**\n * All fields are optional hints. bkash-server decides the amount and invoice from its own\n * data and ignores any amount or invoice sent from the browser.\n */\nexport interface InitiateCheckoutParams {\n amount?: number | string;\n invoiceNumber?: string;\n orderId?: string;\n payerReference?: string;\n metadata?: Record<string, string>;\n}\n\nexport class BkashClient {\n private state: BkashClientState = 'idle';\n private options: BkashClientOptions;\n private currentPaymentId: string | null = null;\n private listeners = new Set<(state: BkashClientState) => void>();\n\n constructor(options?: BkashClientOptions) {\n this.options = {\n createUrl: '/api/bkash/create',\n ...options,\n };\n }\n\n public getState(): BkashClientState {\n return this.state;\n }\n\n public getPaymentId(): string | null {\n return this.currentPaymentId;\n }\n\n /**\n * Returns human-readable UI guidance for the current client state.\n * Specifically guarantees that unknown or timed-out outcomes are presented as\n * \"payment pending, do not pay again\" rather than a false failure.\n */\n public getStateMessage(): string {\n switch (this.state) {\n case 'idle':\n return 'Ready to initiate checkout.';\n case 'creating':\n return 'Initializing payment session with bKash...';\n case 'awaiting_user':\n return 'Redirecting to bKash secure payment page...';\n case 'verifying':\n return 'Verifying payment with bKash...';\n case 'success':\n return 'Payment completed successfully!';\n case 'pending':\n case 'timeout':\n return 'Payment pending, do not pay again. Please wait while your transaction is reconciled with bKash.';\n case 'cancelled':\n return 'Payment was cancelled.';\n case 'offline':\n return 'Device is offline. Please check your internet connection before retrying.';\n case 'error':\n return 'An error occurred during checkout.';\n default:\n return '';\n }\n }\n\n public subscribe(listener: (state: BkashClientState) => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n public cancel(): void {\n this.setState('cancelled');\n this.options.onCancel?.();\n }\n\n public setPending(paymentId?: string): void {\n if (paymentId) this.currentPaymentId = paymentId;\n this.setState('pending');\n }\n\n private setState(newState: BkashClientState): void {\n this.state = newState;\n this.options.onStateChange?.(newState);\n this.listeners.forEach((fn) => fn(newState));\n }\n\n /**\n * Initiates payment flow by calling the merchant backend,\n * obtaining the gateway URL, and redirecting the customer.\n */\n public async checkout(params: InitiateCheckoutParams = {}): Promise<void> {\n // Offline pre-check\n if (typeof navigator !== 'undefined' && navigator.onLine === false) {\n this.setState('offline');\n const offlineErr = new Error('Device is offline. Please check your internet connection.');\n this.options.onError?.(offlineErr);\n throw offlineErr;\n }\n\n try {\n this.setState('creating');\n\n const defaultCallback = typeof window !== 'undefined' ? window.location?.href : '';\n const res = await fetch(this.options.createUrl!, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n amount: params.amount,\n invoiceNumber: params.invoiceNumber,\n orderId: params.orderId,\n callbackUrl: this.options.callbackUrl || defaultCallback,\n payerReference: params.payerReference,\n metadata: params.metadata,\n }),\n });\n\n if (!res.ok) {\n throw new Error(`Failed to create payment session: HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as {\n redirectUrl?: string;\n paymentId?: string;\n error?: string;\n };\n if (!data.redirectUrl || !data.paymentId) {\n throw new Error(data.error || 'Invalid session response from payment server.');\n }\n\n this.currentPaymentId = data.paymentId;\n this.setState('awaiting_user');\n\n // Launch bKash Hosted Checkout\n if (typeof window !== 'undefined' && window.location) {\n window.location.href = data.redirectUrl;\n }\n } catch (err: unknown) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isTimeout =\n error.name === 'AbortError' ||\n error.name === 'TimeoutError' ||\n /timeout|abort/i.test(error.message);\n\n if (isTimeout) {\n // Under AUD-08: timeout / unknown outcome MUST display pending (\"do not pay again\")\n this.setState('pending');\n } else {\n this.setState('error');\n }\n\n this.options.onError?.(error);\n throw error;\n }\n }\n\n public reset(): void {\n this.currentPaymentId = null;\n this.setState('idle');\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ export { __require };
9
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
10
+ //# sourceMappingURL=chunk-DGUM43GV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-DGUM43GV.js"}
@@ -0,0 +1,124 @@
1
+ // src/index.ts
2
+ var BkashClient = class {
3
+ state = "idle";
4
+ options;
5
+ currentPaymentId = null;
6
+ listeners = /* @__PURE__ */ new Set();
7
+ constructor(options) {
8
+ this.options = {
9
+ createUrl: "/api/bkash/create",
10
+ ...options
11
+ };
12
+ }
13
+ getState() {
14
+ return this.state;
15
+ }
16
+ getPaymentId() {
17
+ return this.currentPaymentId;
18
+ }
19
+ /**
20
+ * Returns human-readable UI guidance for the current client state.
21
+ * Specifically guarantees that unknown or timed-out outcomes are presented as
22
+ * "payment pending, do not pay again" rather than a false failure.
23
+ */
24
+ getStateMessage() {
25
+ switch (this.state) {
26
+ case "idle":
27
+ return "Ready to initiate checkout.";
28
+ case "creating":
29
+ return "Initializing payment session with bKash...";
30
+ case "awaiting_user":
31
+ return "Redirecting to bKash secure payment page...";
32
+ case "verifying":
33
+ return "Verifying payment with bKash...";
34
+ case "success":
35
+ return "Payment completed successfully!";
36
+ case "pending":
37
+ case "timeout":
38
+ return "Payment pending, do not pay again. Please wait while your transaction is reconciled with bKash.";
39
+ case "cancelled":
40
+ return "Payment was cancelled.";
41
+ case "offline":
42
+ return "Device is offline. Please check your internet connection before retrying.";
43
+ case "error":
44
+ return "An error occurred during checkout.";
45
+ default:
46
+ return "";
47
+ }
48
+ }
49
+ subscribe(listener) {
50
+ this.listeners.add(listener);
51
+ return () => this.listeners.delete(listener);
52
+ }
53
+ cancel() {
54
+ this.setState("cancelled");
55
+ this.options.onCancel?.();
56
+ }
57
+ setPending(paymentId) {
58
+ if (paymentId) this.currentPaymentId = paymentId;
59
+ this.setState("pending");
60
+ }
61
+ setState(newState) {
62
+ this.state = newState;
63
+ this.options.onStateChange?.(newState);
64
+ this.listeners.forEach((fn) => fn(newState));
65
+ }
66
+ /**
67
+ * Initiates payment flow by calling the merchant backend,
68
+ * obtaining the gateway URL, and redirecting the customer.
69
+ */
70
+ async checkout(params = {}) {
71
+ if (typeof navigator !== "undefined" && navigator.onLine === false) {
72
+ this.setState("offline");
73
+ const offlineErr = new Error("Device is offline. Please check your internet connection.");
74
+ this.options.onError?.(offlineErr);
75
+ throw offlineErr;
76
+ }
77
+ try {
78
+ this.setState("creating");
79
+ const defaultCallback = typeof window !== "undefined" ? window.location?.href : "";
80
+ const res = await fetch(this.options.createUrl, {
81
+ method: "POST",
82
+ headers: { "Content-Type": "application/json" },
83
+ body: JSON.stringify({
84
+ amount: params.amount,
85
+ invoiceNumber: params.invoiceNumber,
86
+ orderId: params.orderId,
87
+ callbackUrl: this.options.callbackUrl || defaultCallback,
88
+ payerReference: params.payerReference,
89
+ metadata: params.metadata
90
+ })
91
+ });
92
+ if (!res.ok) {
93
+ throw new Error(`Failed to create payment session: HTTP ${res.status}`);
94
+ }
95
+ const data = await res.json();
96
+ if (!data.redirectUrl || !data.paymentId) {
97
+ throw new Error(data.error || "Invalid session response from payment server.");
98
+ }
99
+ this.currentPaymentId = data.paymentId;
100
+ this.setState("awaiting_user");
101
+ if (typeof window !== "undefined" && window.location) {
102
+ window.location.href = data.redirectUrl;
103
+ }
104
+ } catch (err) {
105
+ const error = err instanceof Error ? err : new Error(String(err));
106
+ const isTimeout = error.name === "AbortError" || error.name === "TimeoutError" || /timeout|abort/i.test(error.message);
107
+ if (isTimeout) {
108
+ this.setState("pending");
109
+ } else {
110
+ this.setState("error");
111
+ }
112
+ this.options.onError?.(error);
113
+ throw error;
114
+ }
115
+ }
116
+ reset() {
117
+ this.currentPaymentId = null;
118
+ this.setState("idle");
119
+ }
120
+ };
121
+
122
+ export { BkashClient };
123
+ //# sourceMappingURL=chunk-FXLW32P4.js.map
124
+ //# sourceMappingURL=chunk-FXLW32P4.js.map