@prakashacharya/vendure-plugin-nepal-payments 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/CHANGELOG.md +32 -0
- package/LICENSE +21 -0
- package/NOTICE.md +9 -0
- package/README.md +223 -0
- package/dist/api/api-extensions.d.ts +1 -0
- package/dist/api/api-extensions.js +36 -0
- package/dist/api/api-extensions.js.map +1 -0
- package/dist/api/payment-callback.controller.d.ts +9 -0
- package/dist/api/payment-callback.controller.js +83 -0
- package/dist/api/payment-callback.controller.js.map +1 -0
- package/dist/api/shop.resolver.d.ts +9 -0
- package/dist/api/shop.resolver.js +41 -0
- package/dist/api/shop.resolver.js.map +1 -0
- package/dist/config.d.ts +56 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/entities/payment-attempt.entity.d.ts +29 -0
- package/dist/entities/payment-attempt.entity.js +102 -0
- package/dist/entities/payment-attempt.entity.js.map +1 -0
- package/dist/handlers/payment-handlers.d.ts +3 -0
- package/dist/handlers/payment-handlers.js +85 -0
- package/dist/handlers/payment-handlers.js.map +1 -0
- package/dist/handlers/payment-metadata.d.ts +7 -0
- package/dist/handlers/payment-metadata.js +13 -0
- package/dist/handlers/payment-metadata.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/nepal-payments.plugin.d.ts +29 -0
- package/dist/nepal-payments.plugin.js +91 -0
- package/dist/nepal-payments.plugin.js.map +1 -0
- package/dist/providers/amount.d.ts +2 -0
- package/dist/providers/amount.js +22 -0
- package/dist/providers/amount.js.map +1 -0
- package/dist/providers/esewa.provider.d.ts +15 -0
- package/dist/providers/esewa.provider.js +117 -0
- package/dist/providers/esewa.provider.js.map +1 -0
- package/dist/providers/http-client.d.ts +3 -0
- package/dist/providers/http-client.js +46 -0
- package/dist/providers/http-client.js.map +1 -0
- package/dist/providers/khalti.provider.d.ts +15 -0
- package/dist/providers/khalti.provider.js +91 -0
- package/dist/providers/khalti.provider.js.map +1 -0
- package/dist/providers/provider-error.d.ts +5 -0
- package/dist/providers/provider-error.js +13 -0
- package/dist/providers/provider-error.js.map +1 -0
- package/dist/providers/provider.factory.d.ts +2 -0
- package/dist/providers/provider.factory.js +18 -0
- package/dist/providers/provider.factory.js.map +1 -0
- package/dist/providers/sanitize-provider-data.d.ts +4 -0
- package/dist/providers/sanitize-provider-data.js +35 -0
- package/dist/providers/sanitize-provider-data.js.map +1 -0
- package/dist/providers/signing.d.ts +9 -0
- package/dist/providers/signing.js +18 -0
- package/dist/providers/signing.js.map +1 -0
- package/dist/services/payment-orchestrator.service.d.ts +18 -0
- package/dist/services/payment-orchestrator.service.js +188 -0
- package/dist/services/payment-orchestrator.service.js.map +1 -0
- package/dist/services/reconciliation.service.d.ts +11 -0
- package/dist/services/reconciliation.service.js +55 -0
- package/dist/services/reconciliation.service.js.map +1 -0
- package/dist/services/reconciliation.task.d.ts +2 -0
- package/dist/services/reconciliation.task.js +14 -0
- package/dist/services/reconciliation.task.js.map +1 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/docs/ADDING_A_PROVIDER.md +74 -0
- package/docs/ARCHITECTURE.md +75 -0
- package/docs/CONFIGURATION.md +49 -0
- package/docs/DATA_HANDLING.md +46 -0
- package/docs/INSTALLATION.md +132 -0
- package/docs/LICENSING.md +29 -0
- package/docs/PRODUCTION.md +50 -0
- package/docs/PROVIDERS.md +57 -0
- package/docs/README.md +15 -0
- package/docs/RELEASING.md +74 -0
- package/docs/STOREFRONT.md +111 -0
- package/docs/TROUBLESHOOTING.md +71 -0
- package/package.json +79 -0
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PAYMENT_ATTEMPT_STATUSES = exports.NEPAL_PAYMENT_PROVIDERS = void 0;
|
|
4
|
+
exports.NEPAL_PAYMENT_PROVIDERS = ['khalti', 'esewa', 'fonepay'];
|
|
5
|
+
exports.PAYMENT_ATTEMPT_STATUSES = [
|
|
6
|
+
'initiated',
|
|
7
|
+
'pending',
|
|
8
|
+
'settled',
|
|
9
|
+
'failed',
|
|
10
|
+
'cancelled',
|
|
11
|
+
'expired',
|
|
12
|
+
'partially-refunded',
|
|
13
|
+
'refunded',
|
|
14
|
+
'unknown',
|
|
15
|
+
];
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAEa,QAAA,uBAAuB,GAAG,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAU,CAAC;AAIlE,QAAA,wBAAwB,GAAG;IACtC,WAAW;IACX,SAAS;IACT,SAAS;IACT,QAAQ;IACR,WAAW;IACX,SAAS;IACT,oBAAoB;IACpB,UAAU;IACV,SAAS;CACD,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Adding a provider
|
|
2
|
+
|
|
3
|
+
Provider contributions are welcome when based on official, shareable documentation.
|
|
4
|
+
|
|
5
|
+
## 1. Extend the provider type
|
|
6
|
+
|
|
7
|
+
Add the provider code to `NEPAL_PAYMENT_PROVIDERS` in `src/types.ts`. Treat this as a public API change and update `CHANGELOG.md`.
|
|
8
|
+
|
|
9
|
+
## 2. Implement `NepalPaymentProvider`
|
|
10
|
+
|
|
11
|
+
Create `src/providers/<provider>.provider.ts` implementing:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
interface NepalPaymentProvider {
|
|
15
|
+
readonly code: NepalPaymentProviderCode;
|
|
16
|
+
initiate(input: InitiatePaymentInput): Promise<PaymentInitiation>;
|
|
17
|
+
verify(input: VerifyPaymentInput): Promise<VerifiedPayment>;
|
|
18
|
+
refund?(input: RefundPaymentInput): Promise<RefundResult>;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The adapter must:
|
|
23
|
+
|
|
24
|
+
- use fixed sandbox and production base URLs;
|
|
25
|
+
- keep credentials server-side;
|
|
26
|
+
- set bounded network timeouts;
|
|
27
|
+
- reject unexpected redirects;
|
|
28
|
+
- validate provider reference, merchant reference, exact amount, and currency where available;
|
|
29
|
+
- map only documented terminal success states to `settled`;
|
|
30
|
+
- preserve unknown states as `unknown` or `pending`;
|
|
31
|
+
- return sanitized response data suitable for restricted operational logs/storage.
|
|
32
|
+
|
|
33
|
+
Do not use floating-point money calculations.
|
|
34
|
+
|
|
35
|
+
## 3. Add configuration
|
|
36
|
+
|
|
37
|
+
Add a provider options interface in `src/config.ts`, validate required values at bootstrap, and document every option in `docs/CONFIGURATION.md` and `.env.example`.
|
|
38
|
+
|
|
39
|
+
## 4. Register the provider
|
|
40
|
+
|
|
41
|
+
Update `createProvider()` and add a dedicated Vendure `PaymentMethodHandler`. The handler must validate the settlement proof and perform its own provider lookup.
|
|
42
|
+
|
|
43
|
+
Refund support is optional. If no verified API exists, omit `createRefund` and document the manual process.
|
|
44
|
+
|
|
45
|
+
## 5. Add GraphQL and callback support
|
|
46
|
+
|
|
47
|
+
Update the GraphQL enum and ensure the provider can use the shared callback route. If a provider requires a webhook with different authentication, add a narrowly scoped controller and document it.
|
|
48
|
+
|
|
49
|
+
## 6. Test the contract
|
|
50
|
+
|
|
51
|
+
Unit tests must cover:
|
|
52
|
+
|
|
53
|
+
- initiation payload and authorization headers without revealing real credentials;
|
|
54
|
+
- successful verification;
|
|
55
|
+
- pending, failed, cancelled, expired, refunded, and unknown mappings;
|
|
56
|
+
- mismatched amount and references;
|
|
57
|
+
- malformed responses;
|
|
58
|
+
- network errors and timeouts;
|
|
59
|
+
- full and partial refunds, if supported.
|
|
60
|
+
|
|
61
|
+
An end-to-end sandbox test plan is required before marking the provider production-ready.
|
|
62
|
+
|
|
63
|
+
## 7. Document and release
|
|
64
|
+
|
|
65
|
+
Update:
|
|
66
|
+
|
|
67
|
+
- root `README.md` support matrix;
|
|
68
|
+
- `docs/PROVIDERS.md` with official links;
|
|
69
|
+
- `docs/INSTALLATION.md` payment method and environment setup;
|
|
70
|
+
- `docs/STOREFRONT.md` for any unique UI behavior;
|
|
71
|
+
- `CHANGELOG.md`;
|
|
72
|
+
- package keywords when appropriate.
|
|
73
|
+
|
|
74
|
+
Never commit private provider manuals unless their license expressly permits redistribution.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
The package contains one Vendure plugin with separate payment handlers and a shared provider contract.
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
Storefront
|
|
7
|
+
│ initiateNepalPayment(provider)
|
|
8
|
+
▼
|
|
9
|
+
PaymentOrchestratorService ── persists ── NepalPaymentAttempt
|
|
10
|
+
│ │
|
|
11
|
+
│ initiate │ idempotency/status
|
|
12
|
+
▼ │
|
|
13
|
+
Provider adapter │
|
|
14
|
+
│ redirect or signed form │
|
|
15
|
+
▼ │
|
|
16
|
+
Hosted provider checkout │
|
|
17
|
+
│ callback │
|
|
18
|
+
▼ │
|
|
19
|
+
PaymentCallbackController ───────────────┘
|
|
20
|
+
│ server lookup + exact validation
|
|
21
|
+
▼
|
|
22
|
+
Authenticated settlement proof
|
|
23
|
+
│
|
|
24
|
+
▼
|
|
25
|
+
Vendure PaymentMethodHandler
|
|
26
|
+
│ second provider lookup
|
|
27
|
+
▼
|
|
28
|
+
Settled Vendure Payment → order state transition
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Why separate payment handlers
|
|
32
|
+
|
|
33
|
+
Vendure payment methods are independently enabled, assigned to channels, checked for eligibility, displayed to customers, refunded, and reported. Keeping `nepal-khalti` and `nepal-esewa` separate preserves those native behaviors while sharing internal infrastructure.
|
|
34
|
+
|
|
35
|
+
## Why payment attempts are separate from Vendure payments
|
|
36
|
+
|
|
37
|
+
A redirect or QR initiation is not authorization or settlement. Creating an `Authorized` Vendure payment before the customer pays would misrepresent the financial state. `NepalPaymentAttempt` tracks the asynchronous provider lifecycle; the actual Vendure payment is created only after verification succeeds.
|
|
38
|
+
|
|
39
|
+
## Settlement proof
|
|
40
|
+
|
|
41
|
+
Vendure's standard `addPaymentToOrder` mutation accepts arbitrary metadata from the storefront. The handlers therefore do not trust an attempt ID or provider reference by itself. The callback orchestrator creates an HMAC proof binding:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
provider | attemptId | orderId | amount | providerReference
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The handler checks this proof using `internalSigningSecret` and then independently calls the provider lookup endpoint. This prevents a customer from attaching a known transaction for another order, channel, or amount.
|
|
48
|
+
|
|
49
|
+
## Idempotency
|
|
50
|
+
|
|
51
|
+
- Merchant references are UUIDs.
|
|
52
|
+
- Provider/merchant and provider/provider-reference pairs are unique.
|
|
53
|
+
- Callback processing atomically changes an eligible attempt to `verifying`.
|
|
54
|
+
- Already-settled callbacks return the existing attempt.
|
|
55
|
+
- Stale `verifying` attempts return to `pending` during reconciliation.
|
|
56
|
+
- Vendure creates a payment only after a successful provider lookup.
|
|
57
|
+
|
|
58
|
+
## Status normalization
|
|
59
|
+
|
|
60
|
+
Provider-specific statuses map to a conservative shared vocabulary:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
initiated, pending, settled, failed, cancelled, expired,
|
|
64
|
+
partially-refunded, refunded, unknown
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Only `settled` creates a Vendure payment. Unknown and ambiguous provider states never settle.
|
|
68
|
+
|
|
69
|
+
## Amounts
|
|
70
|
+
|
|
71
|
+
Vendure stores money as integer minor units. Khalti consumes paisa directly. eSewa consumes a canonical rupee decimal string. Conversion uses string/integer arithmetic and rejects unsafe or over-precise values.
|
|
72
|
+
|
|
73
|
+
## Reconciliation
|
|
74
|
+
|
|
75
|
+
The scheduled task checks old `initiated`, `pending`, and `unknown` attempts. It does not infer success; it calls the same provider verification and settlement path as a callback. This handles lost redirects, browser closure, and transient network errors.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Configuration reference
|
|
2
|
+
|
|
3
|
+
`NepalPaymentsPlugin.init(options)` validates configuration during Vendure bootstrap and fails early for unsafe or incomplete settings.
|
|
4
|
+
|
|
5
|
+
## Top-level options
|
|
6
|
+
|
|
7
|
+
| Option | Type | Required | Description |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| `publicServerUrl` | `string` | Yes | Public Vendure server origin used to build provider callbacks. HTTPS is required except on loopback hosts. |
|
|
10
|
+
| `storefrontResultUrl` | `string` | Yes | Storefront page receiving the final redirect. HTTPS is required except on loopback hosts. |
|
|
11
|
+
| `internalSigningSecret` | `string` | Yes | At least 32 characters. Authenticates internal settlement metadata. Do not reuse a provider secret. |
|
|
12
|
+
| `reconciliationSchedule` | cron string or `false` | No | Defaults to every five minutes (`*/5 * * * *`). `false` disables the scheduled task. |
|
|
13
|
+
| `khalti` | `KhaltiPluginOptions` | Conditional | Enables Khalti. |
|
|
14
|
+
| `esewa` | `EsewaPluginOptions` | Conditional | Enables eSewa. |
|
|
15
|
+
| `fonepay` | `FonepayPluginOptions` | No | Reserved API shape only; Fonepay initiation is not implemented yet. |
|
|
16
|
+
|
|
17
|
+
At least one of `khalti` or `esewa` is required.
|
|
18
|
+
|
|
19
|
+
## Khalti options
|
|
20
|
+
|
|
21
|
+
| Option | Type | Required | Description |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `secretKey` | `string` | Yes | Merchant secret key. It is used only server-side. |
|
|
24
|
+
| `websiteUrl` | `string` | Yes | Public storefront website URL registered with Khalti. |
|
|
25
|
+
| `environment` | `sandbox` or `production` | No | Defaults to `sandbox`. |
|
|
26
|
+
| `paymentMethodCode` | `string` | No | Vendure payment method code. Defaults to `khalti`. |
|
|
27
|
+
|
|
28
|
+
## eSewa options
|
|
29
|
+
|
|
30
|
+
| Option | Type | Required | Description |
|
|
31
|
+
| --- | --- | --- | --- |
|
|
32
|
+
| `productCode` | `string` | Yes | Merchant product code supplied by eSewa. |
|
|
33
|
+
| `secretKey` | `string` | Yes | HMAC secret supplied by eSewa. It is used only server-side. |
|
|
34
|
+
| `environment` | `sandbox` or `production` | No | Defaults to `sandbox`. |
|
|
35
|
+
| `paymentMethodCode` | `string` | No | Vendure payment method code. Defaults to `esewa`. |
|
|
36
|
+
|
|
37
|
+
## Environment separation
|
|
38
|
+
|
|
39
|
+
Create separate deployments or secret sets for sandbox and production. Never select production merely because `NODE_ENV=production`; the provider environment must be explicit so staging cannot accidentally charge real accounts.
|
|
40
|
+
|
|
41
|
+
## Multi-channel limitation
|
|
42
|
+
|
|
43
|
+
Version 0.1 uses one credential set per provider for the entire Vendure instance. Payment attempts record `channelId` and `channelToken`, but per-channel credential resolution is not implemented yet. Do not use this release when multiple channels require different merchant accounts for the same provider.
|
|
44
|
+
|
|
45
|
+
## Secret rotation
|
|
46
|
+
|
|
47
|
+
Rotating `internalSigningSecret` while callbacks are pending can prevent those attempts from settling. During rotation, stop new initiations, reconcile pending attempts, deploy the new value, and then resume checkout.
|
|
48
|
+
|
|
49
|
+
Provider-secret rotation follows the provider's merchant procedure. Existing attempts may require the old key for lookup, so coordinate rotation during a low-traffic window and reconcile first.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Data handling and privacy
|
|
2
|
+
|
|
3
|
+
The plugin processes payment and order identifiers and therefore should be included in the merchant's privacy, retention, access-control, and incident-response reviews.
|
|
4
|
+
|
|
5
|
+
## Stored payment-attempt fields
|
|
6
|
+
|
|
7
|
+
`NepalPaymentAttempt` stores:
|
|
8
|
+
|
|
9
|
+
- Vendure order ID and code;
|
|
10
|
+
- channel ID and token;
|
|
11
|
+
- provider and Vendure payment method code;
|
|
12
|
+
- generated merchant reference and provider reference;
|
|
13
|
+
- integer amount and currency code;
|
|
14
|
+
- normalized status and timestamps;
|
|
15
|
+
- provider transaction ID and resulting Vendure payment ID;
|
|
16
|
+
- a sanitized subset of provider response data for operations.
|
|
17
|
+
|
|
18
|
+
The plugin does not intentionally store wallet passwords, OTPs, PINs, card data, provider secret keys, or the internal signing secret in the database.
|
|
19
|
+
|
|
20
|
+
## Provider-response redaction
|
|
21
|
+
|
|
22
|
+
Before a provider response is stored, recursive redaction removes fields whose names indicate credentials, API keys, PINs, OTPs, customer details, phone/mobile numbers, email addresses, signatures, tokens, or signed payment/redirect URLs. Depth, array size, and string length are bounded.
|
|
23
|
+
|
|
24
|
+
This is defense in depth, not a substitute for reviewing every provider adapter. New adapters must return the smallest useful `raw` object and must add tests for provider-specific sensitive fields.
|
|
25
|
+
|
|
26
|
+
## Logs
|
|
27
|
+
|
|
28
|
+
The plugin does not intentionally log provider payloads or credentials. Host applications, reverse proxies, GraphQL instrumentation, error tracking, and HTTP debugging can still capture request data. Configure those systems to redact:
|
|
29
|
+
|
|
30
|
+
- `Authorization` headers and API keys;
|
|
31
|
+
- callback query/body payloads;
|
|
32
|
+
- phone numbers and email addresses;
|
|
33
|
+
- provider and merchant transaction references where not operationally required;
|
|
34
|
+
- GraphQL variables containing payment form fields.
|
|
35
|
+
|
|
36
|
+
## Retention
|
|
37
|
+
|
|
38
|
+
Version 0.1 does not automatically delete payment attempts. Merchants must define a retention policy balancing accounting, dispute, fraud, provider-contract, privacy, and Nepalese legal requirements. Do not add a generic cleanup job without confirming which financial records must be retained.
|
|
39
|
+
|
|
40
|
+
## Access
|
|
41
|
+
|
|
42
|
+
The entity is not exposed through a public Shop API query. Database and operational access should be limited to staff who need payment reconciliation capability. Future Admin API/Dashboard views must use Vendure order/payment permissions and avoid exposing raw provider responses by default.
|
|
43
|
+
|
|
44
|
+
## Telemetry
|
|
45
|
+
|
|
46
|
+
This plugin sends no analytics or project telemetry. It communicates only with the provider endpoints required for payment initiation, verification, and refunds.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Installing in Vendure
|
|
2
|
+
|
|
3
|
+
This guide installs the plugin into an existing Vendure 3.7 application. The plugin is a server plugin; it is not installed in the storefront package.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Vendure `>=3.7.0 <4.0.0`
|
|
8
|
+
- Node.js 22 or newer
|
|
9
|
+
- A Vendure SQL database
|
|
10
|
+
- A separately running Vendure worker for scheduled reconciliation in production
|
|
11
|
+
- Merchant sandbox credentials from at least one supported provider
|
|
12
|
+
- A publicly reachable HTTPS server URL for provider callbacks
|
|
13
|
+
|
|
14
|
+
## 1. Install the package
|
|
15
|
+
|
|
16
|
+
From the Vendure server project:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @prakashacharya/vendure-plugin-nepal-payments
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
When developing from a local clone before the first npm release:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# In the plugin repository
|
|
26
|
+
npm ci
|
|
27
|
+
npm run build
|
|
28
|
+
npm pack
|
|
29
|
+
|
|
30
|
+
# In the Vendure application; use the generated filename
|
|
31
|
+
npm install ../vendure-plugin-nepal-payments/pa-vendure-plugin-nepal-payments-0.1.0.tgz
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 2. Add environment variables
|
|
35
|
+
|
|
36
|
+
Copy the relevant names from [`.env.example`](../.env.example) into the Vendure application's environment configuration. Never commit real values.
|
|
37
|
+
|
|
38
|
+
Generate the internal signing secret separately from provider keys:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
openssl rand -base64 48
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The generated value is used only inside this plugin to bind a verified gateway transaction to a specific Vendure order.
|
|
45
|
+
|
|
46
|
+
## 3. Register the plugin
|
|
47
|
+
|
|
48
|
+
Add `NepalPaymentsPlugin.init()` to `vendure-config.ts`:
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { DefaultSchedulerPlugin, VendureConfig } from '@vendure/core';
|
|
52
|
+
import { NepalPaymentsPlugin } from '@prakashacharya/vendure-plugin-nepal-payments';
|
|
53
|
+
|
|
54
|
+
export const config: VendureConfig = {
|
|
55
|
+
// Existing database, API, auth, order and other configuration...
|
|
56
|
+
plugins: [
|
|
57
|
+
DefaultSchedulerPlugin.init(),
|
|
58
|
+
NepalPaymentsPlugin.init({
|
|
59
|
+
publicServerUrl: process.env.PUBLIC_SERVER_URL!,
|
|
60
|
+
storefrontResultUrl: process.env.STOREFRONT_PAYMENT_RESULT_URL!,
|
|
61
|
+
internalSigningSecret: process.env.NEPAL_PAYMENTS_INTERNAL_SECRET!,
|
|
62
|
+
khalti: {
|
|
63
|
+
environment: process.env.KHALTI_ENVIRONMENT === 'production' ? 'production' : 'sandbox',
|
|
64
|
+
secretKey: process.env.KHALTI_SECRET_KEY!,
|
|
65
|
+
websiteUrl: process.env.KHALTI_WEBSITE_URL!,
|
|
66
|
+
paymentMethodCode: 'khalti',
|
|
67
|
+
},
|
|
68
|
+
esewa: {
|
|
69
|
+
environment: process.env.ESEWA_ENVIRONMENT === 'production' ? 'production' : 'sandbox',
|
|
70
|
+
productCode: process.env.ESEWA_PRODUCT_CODE!,
|
|
71
|
+
secretKey: process.env.ESEWA_SECRET_KEY!,
|
|
72
|
+
paymentMethodCode: 'esewa',
|
|
73
|
+
},
|
|
74
|
+
}),
|
|
75
|
+
],
|
|
76
|
+
};
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Omit a provider block if that provider should not be enabled. At least one implemented provider must be configured.
|
|
80
|
+
|
|
81
|
+
`DefaultSchedulerPlugin` is required for automatic pending-payment reconciliation. Set `reconciliationSchedule: false` only when another process calls equivalent reconciliation logic.
|
|
82
|
+
|
|
83
|
+
## 4. Generate the database migration
|
|
84
|
+
|
|
85
|
+
The plugin adds a `NepalPaymentAttempt` entity. From the Vendure application, run:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx vendure migrate
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Choose **Generate a new migration**, inspect the generated SQL, then run the migration command again and choose **Run pending migrations**.
|
|
92
|
+
|
|
93
|
+
Commit the generated migration to the Vendure application repository. Do not enable TypeORM schema synchronization in production.
|
|
94
|
+
|
|
95
|
+
## 5. Create Vendure payment methods
|
|
96
|
+
|
|
97
|
+
Start the server and open the Vendure Dashboard:
|
|
98
|
+
|
|
99
|
+
1. Go to **Settings → Payment methods**.
|
|
100
|
+
2. Create a method with code `khalti`.
|
|
101
|
+
3. Select the **Khalti by IME** handler (`nepal-khalti`).
|
|
102
|
+
4. Enable it and assign it only to channels that use NPR.
|
|
103
|
+
5. Create a method with code `esewa`.
|
|
104
|
+
6. Select the **eSewa** handler (`nepal-esewa`).
|
|
105
|
+
7. Enable it and assign it only to channels that use NPR.
|
|
106
|
+
|
|
107
|
+
The payment method code must equal the matching `paymentMethodCode` in plugin configuration. The handler code and payment method code are different concepts.
|
|
108
|
+
|
|
109
|
+
| Provider | Payment method code | Handler code |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| Khalti by IME | `khalti` | `nepal-khalti` |
|
|
112
|
+
| eSewa | `esewa` | `nepal-esewa` |
|
|
113
|
+
|
|
114
|
+
## 6. Integrate the storefront
|
|
115
|
+
|
|
116
|
+
Follow [STOREFRONT.md](./STOREFRONT.md). The storefront must transition the order to `ArrangingPayment`, call `initiateNepalPayment`, then redirect to Khalti or submit the signed eSewa form.
|
|
117
|
+
|
|
118
|
+
Do not call Vendure's standard `addPaymentToOrder` mutation directly from the storefront for these providers. The callback orchestrator does that only after server verification.
|
|
119
|
+
|
|
120
|
+
## 7. Verify the installation
|
|
121
|
+
|
|
122
|
+
Before using real money:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npx vendure doctor --check dependencies config schema database
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Then complete the sandbox matrix in [PRODUCTION.md](./PRODUCTION.md), including duplicate callbacks, cancellations, altered amounts, timeouts, and delayed status changes.
|
|
129
|
+
|
|
130
|
+
## Upgrading
|
|
131
|
+
|
|
132
|
+
Read [`CHANGELOG.md`](../CHANGELOG.md) before every upgrade. Run `npx vendure migrate` when a release changes plugin entities. Public API breaking changes occur only in semver-major releases after 1.0; while the project is `0.x`, minor versions may contain breaking changes and will call them out prominently.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Licensing and trademarks
|
|
2
|
+
|
|
3
|
+
## Project license
|
|
4
|
+
|
|
5
|
+
The plugin's original source code is licensed under the [MIT License](../LICENSE). You may use, copy, modify, publish, and distribute it subject to that license's notice requirements and warranty disclaimer.
|
|
6
|
+
|
|
7
|
+
## Vendure compatibility
|
|
8
|
+
|
|
9
|
+
Vendure Core is GPLv3. Vendure's official [Publishing a Plugin](https://docs.vendure.io/current/core/how-to/publish-plugin) guide states that Vendure provides a special plugin exception allowing independently distributed plugins to use another license. This project relies on that published exception and uses MIT.
|
|
10
|
+
|
|
11
|
+
This explanation is informational and is not legal advice. Organizations with redistribution or embedded-product concerns should have counsel review their complete dependency and deployment model.
|
|
12
|
+
|
|
13
|
+
## Dependencies
|
|
14
|
+
|
|
15
|
+
Dependencies and peer dependencies retain their own licenses. npm consumers should run their normal software-composition analysis and preserve notices required by those projects. This repository does not relicense Vendure, NestJS, TypeORM, GraphQL, or provider services.
|
|
16
|
+
|
|
17
|
+
## Provider material
|
|
18
|
+
|
|
19
|
+
The repository does not include provider SDK source code, logos, private manuals, merchant credentials, or test accounts. API names and endpoints are implemented for interoperability. Provider APIs remain subject to their own merchant agreements and terms.
|
|
20
|
+
|
|
21
|
+
Contributors must not upload documents or assets they are not authorized to redistribute.
|
|
22
|
+
|
|
23
|
+
## Trademarks
|
|
24
|
+
|
|
25
|
+
Vendure, Khalti, IME Pay, eSewa, Fonepay, and other product names are trademarks of their respective owners. Their use does not imply endorsement. See [`NOTICE.md`](../NOTICE.md).
|
|
26
|
+
|
|
27
|
+
## Contributions
|
|
28
|
+
|
|
29
|
+
Contributions are accepted under the project's MIT License. There is no CLA at present. See [`CONTRIBUTING.md`](../CONTRIBUTING.md).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Security and production checklist
|
|
2
|
+
|
|
3
|
+
## Before sandbox testing
|
|
4
|
+
|
|
5
|
+
- [ ] Plugin and Vendure versions satisfy the compatibility range.
|
|
6
|
+
- [ ] The database migration is generated and reviewed.
|
|
7
|
+
- [ ] Provider payment methods are assigned only to NPR channels.
|
|
8
|
+
- [ ] Provider environment is explicitly `sandbox`.
|
|
9
|
+
- [ ] Secrets are loaded from a secret manager or local ignored `.env` file.
|
|
10
|
+
- [ ] The Vendure worker and scheduler are running.
|
|
11
|
+
|
|
12
|
+
## Sandbox test matrix
|
|
13
|
+
|
|
14
|
+
- [ ] Successful Khalti payment
|
|
15
|
+
- [ ] Successful eSewa payment
|
|
16
|
+
- [ ] Customer cancellation
|
|
17
|
+
- [ ] Expired checkout
|
|
18
|
+
- [ ] Provider pending/ambiguous status
|
|
19
|
+
- [ ] Browser closed before redirect
|
|
20
|
+
- [ ] Callback delivered twice
|
|
21
|
+
- [ ] Callback delivered concurrently
|
|
22
|
+
- [ ] Altered callback amount
|
|
23
|
+
- [ ] Altered provider reference
|
|
24
|
+
- [ ] Provider timeout during initiation
|
|
25
|
+
- [ ] Provider timeout during verification
|
|
26
|
+
- [ ] Reconciliation after a lost callback
|
|
27
|
+
- [ ] Full Khalti refund
|
|
28
|
+
- [ ] Partial Khalti refund
|
|
29
|
+
- [ ] Manual eSewa refund process
|
|
30
|
+
|
|
31
|
+
Verify in every case that fulfillment occurs only after the Vendure payment is `Settled`.
|
|
32
|
+
|
|
33
|
+
## Before production
|
|
34
|
+
|
|
35
|
+
- [ ] Merchant onboarding and KYC are complete for each provider.
|
|
36
|
+
- [ ] Production domains and callback URLs are approved by providers.
|
|
37
|
+
- [ ] Production keys are separate from sandbox keys.
|
|
38
|
+
- [ ] `publicServerUrl` and `storefrontResultUrl` use HTTPS.
|
|
39
|
+
- [ ] `internalSigningSecret` is unique, random, and at least 32 characters.
|
|
40
|
+
- [ ] Logs redact authorization headers, secrets, customer identifiers, and raw callbacks.
|
|
41
|
+
- [ ] Callback routes are protected by infrastructure rate limiting and request-size limits.
|
|
42
|
+
- [ ] Database backups and migration rollback procedures are tested.
|
|
43
|
+
- [ ] Alerts exist for old `pending`, `unknown`, and repeated verification failures.
|
|
44
|
+
- [ ] Operations staff can reconcile provider and Vendure transaction references.
|
|
45
|
+
- [ ] Refund roles and approval processes are defined.
|
|
46
|
+
- [ ] `npx vendure doctor --profile production --strict` passes in the host project.
|
|
47
|
+
|
|
48
|
+
## Operational rule
|
|
49
|
+
|
|
50
|
+
Never manually change a payment attempt or Vendure payment to settled based only on a screenshot, customer claim, redirect query parameter, or callback body. Confirm the transaction in the provider merchant system or through its server status API.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Provider support
|
|
2
|
+
|
|
3
|
+
Provider behavior and access can change. Confirm the current official documentation and merchant agreement before each production launch.
|
|
4
|
+
|
|
5
|
+
## Support matrix
|
|
6
|
+
|
|
7
|
+
| Provider | Initiation | Verification | Refund | Status |
|
|
8
|
+
| --- | --- | --- | --- | --- |
|
|
9
|
+
| Khalti by IME | KPG-2 server request and hosted redirect | `/epayment/lookup/` using `pidx` | Wallet full/partial; bank-funded refunds may need payer mobile/manual handling | Implemented with refund caveat |
|
|
10
|
+
| eSewa | ePay v2 signed HTML form | Signed callback plus transaction status API | No public refund call implemented | Implemented |
|
|
11
|
+
| Fonepay | Dynamic QR expected | Merchant documentation required | Unknown until onboarding | Reserved, disabled |
|
|
12
|
+
| IME Pay | — | — | — | No separate integration; migrated into Khalti by IME |
|
|
13
|
+
| connectIPS / NEPALPAY | Not implemented | Not implemented | Not implemented | Candidate future provider |
|
|
14
|
+
|
|
15
|
+
## Khalti by IME
|
|
16
|
+
|
|
17
|
+
Official documentation:
|
|
18
|
+
|
|
19
|
+
- [KPG-2 Web Checkout](https://docs.khalti.com/khalti-epayment/)
|
|
20
|
+
- [Refund API](https://docs.khalti.com/api/refund/)
|
|
21
|
+
- [Merchant support](https://docs.khalti.com/contact-us/)
|
|
22
|
+
|
|
23
|
+
The plugin sends Vendure's integer NPR minor-unit amount directly as Khalti paisa. Only the `Completed` lookup status settles a payment. Unknown or pending statuses remain unsettled.
|
|
24
|
+
|
|
25
|
+
The public Khalti refund API documents additional mobile data for some bank-funded refunds. Vendure's standard refund input does not collect that provider-specific value, so those cases may fail through the handler and should be completed in the Khalti merchant dashboard. Wallet refunds can use the implemented API path.
|
|
26
|
+
|
|
27
|
+
Khalti can expose multiple underlying payment sources. That does not change the plugin's provider code; Vendure records the payment under the Khalti payment method.
|
|
28
|
+
|
|
29
|
+
## eSewa
|
|
30
|
+
|
|
31
|
+
Official documentation:
|
|
32
|
+
|
|
33
|
+
- [eSewa ePay](https://developer.esewa.com.np/pages/Epay)
|
|
34
|
+
|
|
35
|
+
The plugin converts Vendure minor units into a two-decimal rupee string, signs the documented fields using HMAC-SHA256, verifies signed callback data when supplied, and performs an independent status lookup. Only `COMPLETE` or `SUCCESS` settles a payment.
|
|
36
|
+
|
|
37
|
+
Programmatic refunds are intentionally not advertised because the public ePay documentation does not provide a complete merchant refund request contract. Vendure administrators must follow their merchant agreement and settle refund records manually unless a future verified API is added.
|
|
38
|
+
|
|
39
|
+
## Fonepay
|
|
40
|
+
|
|
41
|
+
Fonepay advertises dynamic QR integration, but the implementation contract is merchant-specific and is not publicly complete. The project will not reproduce private documentation or implement unofficial signature recipes.
|
|
42
|
+
|
|
43
|
+
A contribution may enable Fonepay after maintainers can verify legally shareable details for:
|
|
44
|
+
|
|
45
|
+
- sandbox and production endpoints;
|
|
46
|
+
- merchant authentication and signature canonicalization;
|
|
47
|
+
- dynamic QR request/response fields;
|
|
48
|
+
- enquiry and terminal status mapping;
|
|
49
|
+
- callback authentication;
|
|
50
|
+
- expiry behavior;
|
|
51
|
+
- full and partial refunds.
|
|
52
|
+
|
|
53
|
+
Until then, `FONEPAY` exists in the GraphQL enum for forward compatibility but initiation fails explicitly.
|
|
54
|
+
|
|
55
|
+
## Provider terms and fees
|
|
56
|
+
|
|
57
|
+
This open-source package does not create merchant accounts, negotiate fees, certify an integration, or grant access to provider APIs. Each merchant is responsible for onboarding, KYC, commercial terms, limits, settlement, disputes, refunds, and compliance directly with the relevant provider.
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Documentation
|
|
2
|
+
|
|
3
|
+
- [Installation in an existing Vendure project](./INSTALLATION.md)
|
|
4
|
+
- [Configuration reference](./CONFIGURATION.md)
|
|
5
|
+
- [Storefront integration](./STOREFRONT.md)
|
|
6
|
+
- [Provider support and onboarding](./PROVIDERS.md)
|
|
7
|
+
- [Architecture and payment lifecycle](./ARCHITECTURE.md)
|
|
8
|
+
- [Adding another provider](./ADDING_A_PROVIDER.md)
|
|
9
|
+
- [Security and production checklist](./PRODUCTION.md)
|
|
10
|
+
- [Data handling and privacy](./DATA_HANDLING.md)
|
|
11
|
+
- [Troubleshooting](./TROUBLESHOOTING.md)
|
|
12
|
+
- [Licensing and trademarks](./LICENSING.md)
|
|
13
|
+
- [Maintainer release process](./RELEASING.md)
|
|
14
|
+
|
|
15
|
+
The root [`README.md`](../README.md) remains the primary npm and Vendure Hub landing page.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Maintainer release process
|
|
2
|
+
|
|
3
|
+
## One-time repository setup
|
|
4
|
+
|
|
5
|
+
Before the first public release:
|
|
6
|
+
|
|
7
|
+
1. Create the public GitHub repository.
|
|
8
|
+
2. Add `repository`, `homepage`, and `bugs` URLs to `package.json`.
|
|
9
|
+
3. Replace the repository link placeholders in `CHANGELOG.md`.
|
|
10
|
+
4. Confirm that the `@prakashacharya` npm scope belongs to the publishing user or organization and that maintainers have publish access. Otherwise choose a scope you control before the first release.
|
|
11
|
+
5. Enable GitHub private vulnerability reporting.
|
|
12
|
+
6. Create a short-lived npm granular access token for the initial publication:
|
|
13
|
+
- grant read and write access to the `@prakashacharya` scope;
|
|
14
|
+
- enable bypass 2FA because GitHub Actions cannot answer an interactive OTP prompt;
|
|
15
|
+
- use the shortest practical expiration;
|
|
16
|
+
- add it to the GitHub `npm` environment as an environment secret named `NPM_TOKEN`.
|
|
17
|
+
7. Enable branch protection requiring the CI workflow.
|
|
18
|
+
8. Add an npm README/profile link to the public repository.
|
|
19
|
+
|
|
20
|
+
`npm publish` intentionally runs `npm run check:release-metadata` and refuses to publish until these real public URLs are configured.
|
|
21
|
+
|
|
22
|
+
The npm token must only be stored as a GitHub Actions secret. Never commit it to this repository, place it directly in the workflow, or include it in an issue or log. The release workflow exposes it only to the credential check and `npm publish` steps as `NODE_AUTH_TOKEN`.
|
|
23
|
+
|
|
24
|
+
### Configure the first GitHub Actions publication
|
|
25
|
+
|
|
26
|
+
1. Sign in to npm with an account that can publish packages under `@prakashacharya`.
|
|
27
|
+
2. In npm account settings, create a granular access token with read and write access to the `@prakashacharya` scope and bypass 2FA enabled.
|
|
28
|
+
3. In GitHub, open **Settings > Environments > npm**. Create the environment if it does not exist.
|
|
29
|
+
4. Under **Environment secrets**, add a secret named `NPM_TOKEN` and paste the npm token as its value.
|
|
30
|
+
5. Optionally configure required reviewers on the `npm` environment so a maintainer must approve every publication.
|
|
31
|
+
6. Follow the release checklist below and publish the GitHub Release. The workflow publishes the package; maintainers do not run `npm publish` locally.
|
|
32
|
+
|
|
33
|
+
After the first package version exists on npm, replace token authentication with npm Trusted Publishing. Configure the package's trusted publisher for GitHub owner `pracharya2601`, repository `NPP`, workflow `release.yml`, and environment `npm`; then remove `NPM_TOKEN` from GitHub and remove the credential-check and `NODE_AUTH_TOKEN` configuration from the workflow. Trusted Publishing uses GitHub OIDC and does not require a stored publishing token.
|
|
34
|
+
|
|
35
|
+
Vendure recommends scoped plugin package names, a current changelog included in the npm package, full installation and storefront documentation, compatibility metadata, and tests before submission to Vendure Hub.
|
|
36
|
+
|
|
37
|
+
## Release checklist
|
|
38
|
+
|
|
39
|
+
1. Ensure CI passes on the default branch.
|
|
40
|
+
2. Update `CHANGELOG.md`, moving relevant Unreleased entries into a dated version.
|
|
41
|
+
3. Update the version without creating an automatic Git tag:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm version <patch|minor|major> --no-git-tag-version
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
4. Run:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm ci
|
|
51
|
+
npm run check
|
|
52
|
+
npm pack --dry-run
|
|
53
|
+
npm audit --omit=dev
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
5. Inspect the tarball file list. It must include `dist`, README, docs, changelog, license, and notices, and must exclude tests, credentials, local environment files, and private documentation.
|
|
57
|
+
6. Commit the version and changelog.
|
|
58
|
+
7. Create a signed tag `v<version>`.
|
|
59
|
+
8. Push the commit and tag.
|
|
60
|
+
9. Create a GitHub Release from the tag. The release workflow verifies that tag and package versions match, then publishes to npm with provenance using the protected `NPM_TOKEN` secret.
|
|
61
|
+
10. Verify installation in a clean Vendure project.
|
|
62
|
+
11. For a stable, documented release, submit the npm and GitHub URLs to Vendure Hub.
|
|
63
|
+
|
|
64
|
+
## Versioning
|
|
65
|
+
|
|
66
|
+
The package uses Semantic Versioning.
|
|
67
|
+
|
|
68
|
+
- Patch: backwards-compatible fixes and documentation.
|
|
69
|
+
- Minor: backwards-compatible provider/features after 1.0.
|
|
70
|
+
- Major: public API, configuration, GraphQL, database, or behavioral breaking changes.
|
|
71
|
+
|
|
72
|
+
Before 1.0, a minor version may be breaking. Such changes must be clearly labeled in the changelog and migration notes.
|
|
73
|
+
|
|
74
|
+
Provider-side API changes can require urgent plugin releases even when this project's TypeScript API is unchanged.
|