@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.
Files changed (80) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE.md +9 -0
  4. package/README.md +223 -0
  5. package/dist/api/api-extensions.d.ts +1 -0
  6. package/dist/api/api-extensions.js +36 -0
  7. package/dist/api/api-extensions.js.map +1 -0
  8. package/dist/api/payment-callback.controller.d.ts +9 -0
  9. package/dist/api/payment-callback.controller.js +83 -0
  10. package/dist/api/payment-callback.controller.js.map +1 -0
  11. package/dist/api/shop.resolver.d.ts +9 -0
  12. package/dist/api/shop.resolver.js +41 -0
  13. package/dist/api/shop.resolver.js.map +1 -0
  14. package/dist/config.d.ts +56 -0
  15. package/dist/config.js +52 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/entities/payment-attempt.entity.d.ts +29 -0
  18. package/dist/entities/payment-attempt.entity.js +102 -0
  19. package/dist/entities/payment-attempt.entity.js.map +1 -0
  20. package/dist/handlers/payment-handlers.d.ts +3 -0
  21. package/dist/handlers/payment-handlers.js +85 -0
  22. package/dist/handlers/payment-handlers.js.map +1 -0
  23. package/dist/handlers/payment-metadata.d.ts +7 -0
  24. package/dist/handlers/payment-metadata.js +13 -0
  25. package/dist/handlers/payment-metadata.js.map +1 -0
  26. package/dist/index.d.ts +5 -0
  27. package/dist/index.js +11 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/nepal-payments.plugin.d.ts +29 -0
  30. package/dist/nepal-payments.plugin.js +91 -0
  31. package/dist/nepal-payments.plugin.js.map +1 -0
  32. package/dist/providers/amount.d.ts +2 -0
  33. package/dist/providers/amount.js +22 -0
  34. package/dist/providers/amount.js.map +1 -0
  35. package/dist/providers/esewa.provider.d.ts +15 -0
  36. package/dist/providers/esewa.provider.js +117 -0
  37. package/dist/providers/esewa.provider.js.map +1 -0
  38. package/dist/providers/http-client.d.ts +3 -0
  39. package/dist/providers/http-client.js +46 -0
  40. package/dist/providers/http-client.js.map +1 -0
  41. package/dist/providers/khalti.provider.d.ts +15 -0
  42. package/dist/providers/khalti.provider.js +91 -0
  43. package/dist/providers/khalti.provider.js.map +1 -0
  44. package/dist/providers/provider-error.d.ts +5 -0
  45. package/dist/providers/provider-error.js +13 -0
  46. package/dist/providers/provider-error.js.map +1 -0
  47. package/dist/providers/provider.factory.d.ts +2 -0
  48. package/dist/providers/provider.factory.js +18 -0
  49. package/dist/providers/provider.factory.js.map +1 -0
  50. package/dist/providers/sanitize-provider-data.d.ts +4 -0
  51. package/dist/providers/sanitize-provider-data.js +35 -0
  52. package/dist/providers/sanitize-provider-data.js.map +1 -0
  53. package/dist/providers/signing.d.ts +9 -0
  54. package/dist/providers/signing.js +18 -0
  55. package/dist/providers/signing.js.map +1 -0
  56. package/dist/services/payment-orchestrator.service.d.ts +18 -0
  57. package/dist/services/payment-orchestrator.service.js +188 -0
  58. package/dist/services/payment-orchestrator.service.js.map +1 -0
  59. package/dist/services/reconciliation.service.d.ts +11 -0
  60. package/dist/services/reconciliation.service.js +55 -0
  61. package/dist/services/reconciliation.service.js.map +1 -0
  62. package/dist/services/reconciliation.task.d.ts +2 -0
  63. package/dist/services/reconciliation.task.js +14 -0
  64. package/dist/services/reconciliation.task.js.map +1 -0
  65. package/dist/types.d.ts +76 -0
  66. package/dist/types.js +16 -0
  67. package/dist/types.js.map +1 -0
  68. package/docs/ADDING_A_PROVIDER.md +74 -0
  69. package/docs/ARCHITECTURE.md +75 -0
  70. package/docs/CONFIGURATION.md +49 -0
  71. package/docs/DATA_HANDLING.md +46 -0
  72. package/docs/INSTALLATION.md +132 -0
  73. package/docs/LICENSING.md +29 -0
  74. package/docs/PRODUCTION.md +50 -0
  75. package/docs/PROVIDERS.md +57 -0
  76. package/docs/README.md +15 -0
  77. package/docs/RELEASING.md +74 -0
  78. package/docs/STOREFRONT.md +111 -0
  79. package/docs/TROUBLESHOOTING.md +71 -0
  80. package/package.json +79 -0
@@ -0,0 +1,111 @@
1
+ # Storefront integration
2
+
3
+ The plugin adds one Shop API mutation. It does not add UI components, so any Vendure-compatible storefront can use it.
4
+
5
+ ## Checkout sequence
6
+
7
+ 1. Build the cart, addresses, shipping method, and customer details normally.
8
+ 2. Transition the active order to `ArrangingPayment`.
9
+ 3. Query eligible payment methods and show only methods returned by Vendure.
10
+ 4. Call `initiateNepalPayment` with the selected provider.
11
+ 5. Redirect to Khalti or submit the returned eSewa form.
12
+ 6. The provider returns to the plugin callback controller.
13
+ 7. The plugin verifies server-to-server and creates a settled Vendure payment.
14
+ 8. The plugin redirects to the configured storefront result page.
15
+ 9. The result page queries Vendure for the authoritative order state.
16
+
17
+ ## GraphQL mutation
18
+
19
+ ```graphql
20
+ mutation InitiateNepalPayment($provider: NepalPaymentProviderCode!) {
21
+ initiateNepalPayment(provider: $provider) {
22
+ attemptId
23
+ provider
24
+ status
25
+ redirectUrl
26
+ qrPayload
27
+ expiresAt
28
+ form {
29
+ action
30
+ fields {
31
+ name
32
+ value
33
+ }
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ Variables:
40
+
41
+ ```json
42
+ { "provider": "KHALTI" }
43
+ ```
44
+
45
+ or:
46
+
47
+ ```json
48
+ { "provider": "ESEWA" }
49
+ ```
50
+
51
+ The request must carry the same Vendure session token/cookie used for the active order.
52
+
53
+ ## Khalti response
54
+
55
+ Khalti returns `redirectUrl`. Navigate the top-level browser to that URL:
56
+
57
+ ```ts
58
+ const payment = result.data.initiateNepalPayment;
59
+ if (!payment.redirectUrl) throw new Error('Khalti redirect URL was not returned');
60
+ window.location.assign(payment.redirectUrl);
61
+ ```
62
+
63
+ Do not open checkout in an iframe unless Khalti's current merchant documentation explicitly supports it.
64
+
65
+ ## eSewa response
66
+
67
+ eSewa requires an HTML POST. Submit the exact returned field names and values:
68
+
69
+ ```ts
70
+ function submitPaymentForm(form: {
71
+ action: string;
72
+ fields: Array<{ name: string; value: string }>;
73
+ }) {
74
+ const element = document.createElement('form');
75
+ element.method = 'POST';
76
+ element.action = form.action;
77
+
78
+ for (const field of form.fields) {
79
+ const input = document.createElement('input');
80
+ input.type = 'hidden';
81
+ input.name = field.name;
82
+ input.value = field.value;
83
+ element.appendChild(input);
84
+ }
85
+
86
+ document.body.appendChild(element);
87
+ element.submit();
88
+ }
89
+ ```
90
+
91
+ Do not recalculate, reformat, translate, or round any signed eSewa field.
92
+
93
+ ## Result page
94
+
95
+ The callback controller redirects to `storefrontResultUrl` with:
96
+
97
+ ```text
98
+ ?attemptId=<uuid>&provider=<provider>&status=<status>
99
+ ```
100
+
101
+ Possible status values include `settled`, `pending`, `failed`, `cancelled`, `expired`, and `unknown`.
102
+
103
+ These query parameters are presentation hints, not authorization or fulfillment proof. The storefront must query Vendure and use the order/payment state as authoritative. For `pending`, show a waiting state and poll with backoff; the reconciliation worker may settle the payment later.
104
+
105
+ ## Preventing duplicate initiation
106
+
107
+ Disable the payment button while the mutation is running. The server also rejects another active attempt for the same order and provider. Do not automatically retry an initiation after a network timeout; first allow the callback/reconciliation flow to determine whether the provider created the transaction.
108
+
109
+ ## Do not expose secrets
110
+
111
+ The storefront needs no secret keys, signatures, provider lookup APIs, or settlement proofs. If any provider secret appears in browser code, browser network responses, analytics, or source maps, the integration is incorrect.
@@ -0,0 +1,71 @@
1
+ # Troubleshooting
2
+
3
+ ## Plugin fails during bootstrap
4
+
5
+ Common causes:
6
+
7
+ - `NepalPaymentsPlugin` was added without calling `.init()`;
8
+ - the internal signing secret is shorter than 32 characters;
9
+ - a public URL uses HTTP outside localhost;
10
+ - neither Khalti nor eSewa is configured;
11
+ - a required provider credential is empty;
12
+ - Vendure is outside the plugin compatibility range.
13
+
14
+ Run:
15
+
16
+ ```bash
17
+ npx vendure doctor --check dependencies config
18
+ ```
19
+
20
+ ## Payment method is not eligible
21
+
22
+ Confirm that:
23
+
24
+ - the payment method code exactly matches `paymentMethodCode`;
25
+ - the method is enabled;
26
+ - it is assigned to the active channel;
27
+ - the channel currency is NPR;
28
+ - any custom eligibility checker accepts the order;
29
+ - the order is in `ArrangingPayment`.
30
+
31
+ ## Database table is missing
32
+
33
+ Generate and run the host Vendure application's migration after registering the plugin:
34
+
35
+ ```bash
36
+ npx vendure migrate
37
+ ```
38
+
39
+ Do not fix production by enabling schema synchronization.
40
+
41
+ ## Callback returns `pending`
42
+
43
+ This can be normal for provider processing or a temporary lookup failure. Confirm that the Vendure worker and scheduler are running. Review the payment attempt and provider merchant dashboard using the merchant/provider references. Do not fulfill the order until Vendure records a settled payment.
44
+
45
+ ## eSewa signature failure
46
+
47
+ Check that:
48
+
49
+ - the correct sandbox or production secret is configured;
50
+ - form fields were submitted without reformatting;
51
+ - the storefront did not parse and reconstruct decimal amounts;
52
+ - `productCode` matches the merchant environment;
53
+ - proxies preserve the callback query/body.
54
+
55
+ The reconciliation task can still perform a trusted server status lookup, but a malformed callback itself is never accepted.
56
+
57
+ ## Khalti lookup reference mismatch
58
+
59
+ The `pidx` returned by lookup must equal the stored provider reference. Confirm that the callback URL and attempt ID were not reused or modified. Treat a mismatch as a security event rather than editing the database.
60
+
61
+ ## Duplicate payment attempt
62
+
63
+ The plugin permits only one non-expired active attempt per provider and order. Let the existing attempt complete, expire, or be reconciled. Do not generate repeated payment requests automatically after browser/network errors.
64
+
65
+ ## Refund fails
66
+
67
+ Confirm that the provider transaction is refundable, the merchant account has permission, and the correct production/sandbox key is active. Khalti bank-funded refunds may require payer mobile information depending on the merchant contract; the current Vendure handler does not collect that value, so such refunds may need the merchant dashboard.
68
+
69
+ ## Getting help
70
+
71
+ Use GitHub Discussions for integration questions and GitHub Issues for reproducible bugs. Redact all sensitive data as described in [`SECURITY.md`](../SECURITY.md).
package/package.json ADDED
@@ -0,0 +1,79 @@
1
+ {
2
+ "name": "@prakashacharya/vendure-plugin-nepal-payments",
3
+ "version": "0.1.0",
4
+ "description": "Open-source Vendure payment integrations for Khalti by IME, eSewa, and other Nepalese providers",
5
+ "license": "MIT",
6
+ "author": "NPP Contributors",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/pracharya2601/NPP.git"
10
+ },
11
+ "homepage": "https://github.com/pracharya2601/NPP#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/pracharya2601/NPP/issues"
14
+ },
15
+ "keywords": [
16
+ "vendure",
17
+ "vendure-plugin",
18
+ "payments",
19
+ "nepal",
20
+ "khalti",
21
+ "esewa",
22
+ "fonepay",
23
+ "ecommerce"
24
+ ],
25
+ "type": "commonjs",
26
+ "main": "dist/index.js",
27
+ "types": "dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "require": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
35
+ "files": [
36
+ "dist",
37
+ "docs",
38
+ "README.md",
39
+ "CHANGELOG.md",
40
+ "LICENSE",
41
+ "NOTICE.md"
42
+ ],
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.build.json",
45
+ "clean": "node -e \"require('fs').rmSync('dist', { recursive: true, force: true })\"",
46
+ "check": "npm run typecheck && npm test && npm run build",
47
+ "check:release-metadata": "node scripts/check-release-metadata.js",
48
+ "typecheck": "tsc -p tsconfig.json --noEmit",
49
+ "test": "vitest run",
50
+ "test:watch": "vitest",
51
+ "prepack": "npm run clean && npm run check",
52
+ "prepublishOnly": "npm run check:release-metadata && npm run check"
53
+ },
54
+ "engines": {
55
+ "node": ">=22"
56
+ },
57
+ "dependencies": {
58
+ "graphql-tag": "^2.12.6"
59
+ },
60
+ "peerDependencies": {
61
+ "@nestjs/common": "^11.0.0",
62
+ "@nestjs/graphql": "^13.1.0",
63
+ "@vendure/core": "^3.7.0",
64
+ "typeorm": "^0.3.21"
65
+ },
66
+ "devDependencies": {
67
+ "@types/node": "^22.15.0",
68
+ "@nestjs/common": "^11.0.12",
69
+ "@nestjs/graphql": "^13.1.0",
70
+ "@vendure/core": "3.7.0",
71
+ "typeorm": "^0.3.21",
72
+ "typescript": "5.8.2",
73
+ "vitest": "^3.2.4"
74
+ },
75
+ "publishConfig": {
76
+ "access": "public",
77
+ "provenance": true
78
+ }
79
+ }