@atbas/m-mcp 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 +364 -0
- package/dist/builder/transaction-builder.d.ts +53 -0
- package/dist/builder/transaction-builder.d.ts.map +1 -0
- package/dist/builder/transaction-builder.js +159 -0
- package/dist/builder/transaction-builder.js.map +1 -0
- package/dist/catalogue/default-catalogue.d.ts +18 -0
- package/dist/catalogue/default-catalogue.d.ts.map +1 -0
- package/dist/catalogue/default-catalogue.js +21 -0
- package/dist/catalogue/default-catalogue.js.map +1 -0
- package/dist/catalogue/endpoints.d.ts +22 -0
- package/dist/catalogue/endpoints.d.ts.map +1 -0
- package/dist/catalogue/endpoints.js +24 -0
- package/dist/catalogue/endpoints.js.map +1 -0
- package/dist/catalogue/flows.d.ts +32 -0
- package/dist/catalogue/flows.d.ts.map +1 -0
- package/dist/catalogue/flows.js +64 -0
- package/dist/catalogue/flows.js.map +1 -0
- package/dist/catalogue/hash-options.d.ts +112 -0
- package/dist/catalogue/hash-options.d.ts.map +1 -0
- package/dist/catalogue/hash-options.js +151 -0
- package/dist/catalogue/hash-options.js.map +1 -0
- package/dist/catalogue/types.d.ts +279 -0
- package/dist/catalogue/types.d.ts.map +1 -0
- package/dist/catalogue/types.js +360 -0
- package/dist/catalogue/types.js.map +1 -0
- package/dist/codegen/generate.d.ts +14 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/generate.js +490 -0
- package/dist/codegen/generate.js.map +1 -0
- package/dist/codegen/languages/node.d.ts +3 -0
- package/dist/codegen/languages/node.d.ts.map +1 -0
- package/dist/codegen/languages/node.js +32 -0
- package/dist/codegen/languages/node.js.map +1 -0
- package/dist/codegen/languages/php.d.ts +3 -0
- package/dist/codegen/languages/php.d.ts.map +1 -0
- package/dist/codegen/languages/php.js +27 -0
- package/dist/codegen/languages/php.js.map +1 -0
- package/dist/codegen/languages/python.d.ts +3 -0
- package/dist/codegen/languages/python.d.ts.map +1 -0
- package/dist/codegen/languages/python.js +27 -0
- package/dist/codegen/languages/python.js.map +1 -0
- package/dist/codegen/renderer.d.ts +24 -0
- package/dist/codegen/renderer.d.ts.map +1 -0
- package/dist/codegen/renderer.js +59 -0
- package/dist/codegen/renderer.js.map +1 -0
- package/dist/codegen/types.d.ts +50 -0
- package/dist/codegen/types.d.ts.map +1 -0
- package/dist/codegen/types.js +5 -0
- package/dist/codegen/types.js.map +1 -0
- package/dist/config/credentials.d.ts +64 -0
- package/dist/config/credentials.d.ts.map +1 -0
- package/dist/config/credentials.js +216 -0
- package/dist/config/credentials.js.map +1 -0
- package/dist/config/environment.d.ts +23 -0
- package/dist/config/environment.d.ts.map +1 -0
- package/dist/config/environment.js +54 -0
- package/dist/config/environment.js.map +1 -0
- package/dist/core/dependencies.d.ts +43 -0
- package/dist/core/dependencies.d.ts.map +1 -0
- package/dist/core/dependencies.js +2 -0
- package/dist/core/dependencies.js.map +1 -0
- package/dist/core/registry.d.ts +33 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +13 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/server.d.ts +61 -0
- package/dist/core/server.d.ts.map +1 -0
- package/dist/core/server.js +90 -0
- package/dist/core/server.js.map +1 -0
- package/dist/dependencies.d.ts +28 -0
- package/dist/dependencies.d.ts.map +1 -0
- package/dist/dependencies.js +2 -0
- package/dist/dependencies.js.map +1 -0
- package/dist/diagnostics/diagnose.d.ts +43 -0
- package/dist/diagnostics/diagnose.d.ts.map +1 -0
- package/dist/diagnostics/diagnose.js +121 -0
- package/dist/diagnostics/diagnose.js.map +1 -0
- package/dist/domain/amount.d.ts +157 -0
- package/dist/domain/amount.d.ts.map +1 -0
- package/dist/domain/amount.js +275 -0
- package/dist/domain/amount.js.map +1 -0
- package/dist/domain/datetime.d.ts +95 -0
- package/dist/domain/datetime.d.ts.map +1 -0
- package/dist/domain/datetime.js +211 -0
- package/dist/domain/datetime.js.map +1 -0
- package/dist/domain/response-codes.d.ts +116 -0
- package/dist/domain/response-codes.d.ts.map +1 -0
- package/dist/domain/response-codes.js +380 -0
- package/dist/domain/response-codes.js.map +1 -0
- package/dist/domain/secure-hash.d.ts +78 -0
- package/dist/domain/secure-hash.d.ts.map +1 -0
- package/dist/domain/secure-hash.js +69 -0
- package/dist/domain/secure-hash.js.map +1 -0
- package/dist/domain/signature/jazzcash.d.ts +56 -0
- package/dist/domain/signature/jazzcash.d.ts.map +1 -0
- package/dist/domain/signature/jazzcash.js +214 -0
- package/dist/domain/signature/jazzcash.js.map +1 -0
- package/dist/domain/signature/registry.d.ts +69 -0
- package/dist/domain/signature/registry.d.ts.map +1 -0
- package/dist/domain/signature/registry.js +92 -0
- package/dist/domain/signature/registry.js.map +1 -0
- package/dist/domain/signature/scheme.d.ts +349 -0
- package/dist/domain/signature/scheme.d.ts.map +1 -0
- package/dist/domain/signature/scheme.js +398 -0
- package/dist/domain/signature/scheme.js.map +1 -0
- package/dist/domain/txn-ref.d.ts +76 -0
- package/dist/domain/txn-ref.d.ts.map +1 -0
- package/dist/domain/txn-ref.js +126 -0
- package/dist/domain/txn-ref.js.map +1 -0
- package/dist/domain/types.d.ts +45 -0
- package/dist/domain/types.d.ts.map +1 -0
- package/dist/domain/types.js +70 -0
- package/dist/domain/types.js.map +1 -0
- package/dist/errors.d.ts +84 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +87 -0
- package/dist/errors.js.map +1 -0
- package/dist/gateway/checkout-form.d.ts +16 -0
- package/dist/gateway/checkout-form.d.ts.map +1 -0
- package/dist/gateway/checkout-form.js +103 -0
- package/dist/gateway/checkout-form.js.map +1 -0
- package/dist/gateway/checkout-output.d.ts +70 -0
- package/dist/gateway/checkout-output.d.ts.map +1 -0
- package/dist/gateway/checkout-output.js +199 -0
- package/dist/gateway/checkout-output.js.map +1 -0
- package/dist/gateway/guards.d.ts +37 -0
- package/dist/gateway/guards.d.ts.map +1 -0
- package/dist/gateway/guards.js +44 -0
- package/dist/gateway/guards.js.map +1 -0
- package/dist/gateway/http-client.d.ts +42 -0
- package/dist/gateway/http-client.d.ts.map +1 -0
- package/dist/gateway/http-client.js +153 -0
- package/dist/gateway/http-client.js.map +1 -0
- package/dist/gateway/rest-client.d.ts +42 -0
- package/dist/gateway/rest-client.d.ts.map +1 -0
- package/dist/gateway/rest-client.js +241 -0
- package/dist/gateway/rest-client.js.map +1 -0
- package/dist/gateway/transport.d.ts +31 -0
- package/dist/gateway/transport.d.ts.map +1 -0
- package/dist/gateway/transport.js +73 -0
- package/dist/gateway/transport.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +75 -0
- package/dist/index.js.map +1 -0
- package/dist/install/cli.d.ts +38 -0
- package/dist/install/cli.d.ts.map +1 -0
- package/dist/install/cli.js +274 -0
- package/dist/install/cli.js.map +1 -0
- package/dist/install/harnesses.d.ts +74 -0
- package/dist/install/harnesses.d.ts.map +1 -0
- package/dist/install/harnesses.js +263 -0
- package/dist/install/harnesses.js.map +1 -0
- package/dist/knowledge/corpus.d.ts +15 -0
- package/dist/knowledge/corpus.d.ts.map +1 -0
- package/dist/knowledge/corpus.js +129 -0
- package/dist/knowledge/corpus.js.map +1 -0
- package/dist/knowledge/search.d.ts +29 -0
- package/dist/knowledge/search.d.ts.map +1 -0
- package/dist/knowledge/search.js +181 -0
- package/dist/knowledge/search.js.map +1 -0
- package/dist/knowledge/source.d.ts +60 -0
- package/dist/knowledge/source.d.ts.map +1 -0
- package/dist/knowledge/source.js +91 -0
- package/dist/knowledge/source.js.map +1 -0
- package/dist/knowledge/types.d.ts +40 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +19 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/paths.d.ts +26 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +106 -0
- package/dist/paths.js.map +1 -0
- package/dist/prompts/integration-walkthrough.d.ts +11 -0
- package/dist/prompts/integration-walkthrough.d.ts.map +1 -0
- package/dist/prompts/integration-walkthrough.js +52 -0
- package/dist/prompts/integration-walkthrough.js.map +1 -0
- package/dist/prompts/register.d.ts +4 -0
- package/dist/prompts/register.d.ts.map +1 -0
- package/dist/prompts/register.js +4 -0
- package/dist/prompts/register.js.map +1 -0
- package/dist/registry.d.ts +14 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +2 -0
- package/dist/registry.js.map +1 -0
- package/dist/resources/knowledge-resources.d.ts +5 -0
- package/dist/resources/knowledge-resources.d.ts.map +1 -0
- package/dist/resources/knowledge-resources.js +121 -0
- package/dist/resources/knowledge-resources.js.map +1 -0
- package/dist/resources/register.d.ts +4 -0
- package/dist/resources/register.d.ts.map +1 -0
- package/dist/resources/register.js +8 -0
- package/dist/resources/register.js.map +1 -0
- package/dist/server.d.ts +40 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +56 -0
- package/dist/server.js.map +1 -0
- package/dist/telemetry/logger.d.ts +31 -0
- package/dist/telemetry/logger.d.ts.map +1 -0
- package/dist/telemetry/logger.js +67 -0
- package/dist/telemetry/logger.js.map +1 -0
- package/dist/telemetry/redaction.d.ts +88 -0
- package/dist/telemetry/redaction.d.ts.map +1 -0
- package/dist/telemetry/redaction.js +238 -0
- package/dist/telemetry/redaction.js.map +1 -0
- package/dist/tools/build-transaction-parameters.d.ts +10 -0
- package/dist/tools/build-transaction-parameters.d.ts.map +1 -0
- package/dist/tools/build-transaction-parameters.js +154 -0
- package/dist/tools/build-transaction-parameters.js.map +1 -0
- package/dist/tools/call-context.d.ts +47 -0
- package/dist/tools/call-context.d.ts.map +1 -0
- package/dist/tools/call-context.js +15 -0
- package/dist/tools/call-context.js.map +1 -0
- package/dist/tools/codegen-tools.d.ts +4 -0
- package/dist/tools/codegen-tools.d.ts.map +1 -0
- package/dist/tools/codegen-tools.js +131 -0
- package/dist/tools/codegen-tools.js.map +1 -0
- package/dist/tools/credential-tools.d.ts +32 -0
- package/dist/tools/credential-tools.d.ts.map +1 -0
- package/dist/tools/credential-tools.js +65 -0
- package/dist/tools/credential-tools.js.map +1 -0
- package/dist/tools/descriptor.d.ts +52 -0
- package/dist/tools/descriptor.d.ts.map +1 -0
- package/dist/tools/descriptor.js +2 -0
- package/dist/tools/descriptor.js.map +1 -0
- package/dist/tools/diagnostic-tools.d.ts +3 -0
- package/dist/tools/diagnostic-tools.d.ts.map +1 -0
- package/dist/tools/diagnostic-tools.js +128 -0
- package/dist/tools/diagnostic-tools.js.map +1 -0
- package/dist/tools/gateway-tools.d.ts +6 -0
- package/dist/tools/gateway-tools.d.ts.map +1 -0
- package/dist/tools/gateway-tools.js +381 -0
- package/dist/tools/gateway-tools.js.map +1 -0
- package/dist/tools/hash-tools.d.ts +5 -0
- package/dist/tools/hash-tools.d.ts.map +1 -0
- package/dist/tools/hash-tools.js +238 -0
- package/dist/tools/hash-tools.js.map +1 -0
- package/dist/tools/knowledge-tools.d.ts +7 -0
- package/dist/tools/knowledge-tools.d.ts.map +1 -0
- package/dist/tools/knowledge-tools.js +247 -0
- package/dist/tools/knowledge-tools.js.map +1 -0
- package/dist/tools/onboarding-checklist.d.ts +3 -0
- package/dist/tools/onboarding-checklist.d.ts.map +1 -0
- package/dist/tools/onboarding-checklist.js +141 -0
- package/dist/tools/onboarding-checklist.js.map +1 -0
- package/dist/tools/register.d.ts +60 -0
- package/dist/tools/register.d.ts.map +1 -0
- package/dist/tools/register.js +145 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/tools/tool-kit.d.ts +88 -0
- package/dist/tools/tool-kit.d.ts.map +1 -0
- package/dist/tools/tool-kit.js +297 -0
- package/dist/tools/tool-kit.js.map +1 -0
- package/dist/validation/payload-validator.d.ts +29 -0
- package/dist/validation/payload-validator.d.ts.map +1 -0
- package/dist/validation/payload-validator.js +79 -0
- package/dist/validation/payload-validator.js.map +1 -0
- package/dist/validation/rules/amount.d.ts +3 -0
- package/dist/validation/rules/amount.d.ts.map +1 -0
- package/dist/validation/rules/amount.js +77 -0
- package/dist/validation/rules/amount.js.map +1 -0
- package/dist/validation/rules/bill-reference.d.ts +10 -0
- package/dist/validation/rules/bill-reference.d.ts.map +1 -0
- package/dist/validation/rules/bill-reference.js +34 -0
- package/dist/validation/rules/bill-reference.js.map +1 -0
- package/dist/validation/rules/cnic.d.ts +3 -0
- package/dist/validation/rules/cnic.d.ts.map +1 -0
- package/dist/validation/rules/cnic.js +42 -0
- package/dist/validation/rules/cnic.js.map +1 -0
- package/dist/validation/rules/constants.d.ts +9 -0
- package/dist/validation/rules/constants.d.ts.map +1 -0
- package/dist/validation/rules/constants.js +28 -0
- package/dist/validation/rules/constants.js.map +1 -0
- package/dist/validation/rules/constraints.d.ts +3 -0
- package/dist/validation/rules/constraints.d.ts.map +1 -0
- package/dist/validation/rules/constraints.js +113 -0
- package/dist/validation/rules/constraints.js.map +1 -0
- package/dist/validation/rules/datetime.d.ts +3 -0
- package/dist/validation/rules/datetime.d.ts.map +1 -0
- package/dist/validation/rules/datetime.js +49 -0
- package/dist/validation/rules/datetime.js.map +1 -0
- package/dist/validation/rules/empty-string.d.ts +13 -0
- package/dist/validation/rules/empty-string.d.ts.map +1 -0
- package/dist/validation/rules/empty-string.js +32 -0
- package/dist/validation/rules/empty-string.js.map +1 -0
- package/dist/validation/rules/expiry.d.ts +3 -0
- package/dist/validation/rules/expiry.d.ts.map +1 -0
- package/dist/validation/rules/expiry.js +52 -0
- package/dist/validation/rules/expiry.js.map +1 -0
- package/dist/validation/rules/msisdn.d.ts +3 -0
- package/dist/validation/rules/msisdn.d.ts.map +1 -0
- package/dist/validation/rules/msisdn.js +45 -0
- package/dist/validation/rules/msisdn.js.map +1 -0
- package/dist/validation/rules/presence.d.ts +3 -0
- package/dist/validation/rules/presence.d.ts.map +1 -0
- package/dist/validation/rules/presence.js +90 -0
- package/dist/validation/rules/presence.js.map +1 -0
- package/dist/validation/rules/return-url.d.ts +14 -0
- package/dist/validation/rules/return-url.d.ts.map +1 -0
- package/dist/validation/rules/return-url.js +58 -0
- package/dist/validation/rules/return-url.js.map +1 -0
- package/dist/validation/rules/tool-argument.d.ts +16 -0
- package/dist/validation/rules/tool-argument.d.ts.map +1 -0
- package/dist/validation/rules/tool-argument.js +38 -0
- package/dist/validation/rules/tool-argument.js.map +1 -0
- package/dist/validation/rules/txn-ref.d.ts +3 -0
- package/dist/validation/rules/txn-ref.d.ts.map +1 -0
- package/dist/validation/rules/txn-ref.js +47 -0
- package/dist/validation/rules/txn-ref.js.map +1 -0
- package/dist/validation/rules/unknown-fields.d.ts +10 -0
- package/dist/validation/rules/unknown-fields.d.ts.map +1 -0
- package/dist/validation/rules/unknown-fields.js +29 -0
- package/dist/validation/rules/unknown-fields.js.map +1 -0
- package/dist/validation/types.d.ts +36 -0
- package/dist/validation/types.d.ts.map +1 -0
- package/dist/validation/types.js +12 -0
- package/dist/validation/types.js.map +1 -0
- package/dist/version.d.ts +23 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +23 -0
- package/dist/version.js.map +1 -0
- package/knowledge/diagnostics/symptoms.json +321 -0
- package/knowledge/docs/bnpl-guide.md +77 -0
- package/knowledge/docs/card-page-redirection.md +67 -0
- package/knowledge/docs/card-refund.md +91 -0
- package/knowledge/docs/hmac-sha256-calculation.md +72 -0
- package/knowledge/docs/index.json +189 -0
- package/knowledge/docs/ipn-implementation.md +89 -0
- package/knowledge/docs/mwallet-recurring.md +117 -0
- package/knowledge/docs/mwallet-refund.md +65 -0
- package/knowledge/docs/mwallet-rest-v1-1.md +126 -0
- package/knowledge/docs/mwallet-rest-v2-0-cnic.md +113 -0
- package/knowledge/docs/portal-guide.md +45 -0
- package/knowledge/docs/shopify-guide.md +74 -0
- package/knowledge/docs/status-inquiry-2025-26.md +32 -0
- package/knowledge/docs/status-inquiry.md +111 -0
- package/knowledge/docs/wordpress-guide.md +49 -0
- package/knowledge/flow.schema.json +390 -0
- package/knowledge/flows/bnpl-page-redirection-v1.1.json +211 -0
- package/knowledge/flows/card-page-redirection-v1.1.json +211 -0
- package/knowledge/flows/mwallet-rest-v1.1.json +187 -0
- package/knowledge/flows/mwallet-rest-v2.0-cnic.json +197 -0
- package/knowledge/flows/mwallet-token-pay-v4.0.json +130 -0
- package/knowledge/flows/refund-bnpl.json +105 -0
- package/knowledge/flows/refund-card-v1.1.json +112 -0
- package/knowledge/flows/refund-card-v2.0.json +121 -0
- package/knowledge/flows/refund-mwallet-v1.1.json +106 -0
- package/knowledge/flows/status-inquiry-v1.1.json +102 -0
- package/knowledge/flows/status-inquiry-v2.0.json +103 -0
- package/knowledge/flows/token-delete-v1.json +85 -0
- package/knowledge/flows/token-inquiry-v1.json +85 -0
- package/knowledge/flows/wallet-linking-portal.json +103 -0
- package/knowledge/templates/node/checkout-redirect.tmpl +166 -0
- package/knowledge/templates/node/ipn-handler.tmpl +108 -0
- package/knowledge/templates/node/rest-client.tmpl +197 -0
- package/knowledge/templates/node/wallet-linking.tmpl +147 -0
- package/knowledge/templates/php/checkout-redirect.tmpl +149 -0
- package/knowledge/templates/php/ipn-handler.tmpl +105 -0
- package/knowledge/templates/php/rest-client.tmpl +191 -0
- package/knowledge/templates/php/wallet-linking.tmpl +137 -0
- package/knowledge/templates/python/checkout-redirect.tmpl +148 -0
- package/knowledge/templates/python/ipn-handler.tmpl +110 -0
- package/knowledge/templates/python/rest-client.tmpl +179 -0
- package/knowledge/templates/python/wallet-linking.tmpl +133 -0
- package/package.json +84 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { FlowResponseSpec } from '../catalogue/types.js';
|
|
2
|
+
import type { DocRef } from '../errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* Response code interpretation.
|
|
5
|
+
*
|
|
6
|
+
* The 2026 corpus documents exactly three codes and one status literal:
|
|
7
|
+
*
|
|
8
|
+
* - `pp_ResponseCode` `000` — the API operation was performed successfully.
|
|
9
|
+
* - `pp_PaymentResponseCode` `121` — the transaction completed and the amount
|
|
10
|
+
* was debited.
|
|
11
|
+
* - `199`, `999` and "others" — failed transactions (IPN guide).
|
|
12
|
+
* - `pp_Status` `Completed`.
|
|
13
|
+
*
|
|
14
|
+
* Anything else is reported as `unknown`. Inventing a plausible meaning for an
|
|
15
|
+
* undocumented code is worse than admitting the corpus does not cover it: a
|
|
16
|
+
* merchant who is told "probably a timeout" will stop investigating.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Which question a code answers.
|
|
20
|
+
*
|
|
21
|
+
* `settlement` is the acquirer's own verdict, which some providers report
|
|
22
|
+
* alongside a service-level code. It answers "did the card issuer approve
|
|
23
|
+
* this?", a different question from "was the request processed?".
|
|
24
|
+
*/
|
|
25
|
+
export type CodeFamily = 'api-operation' | 'payment-status' | 'settlement';
|
|
26
|
+
export type CodeOutcome = 'success' | 'failure' | 'unknown';
|
|
27
|
+
export interface ResponseCodeInfo {
|
|
28
|
+
readonly code: string;
|
|
29
|
+
readonly family: CodeFamily;
|
|
30
|
+
/**
|
|
31
|
+
* True when the code's meaning comes from a document rather than a guess:
|
|
32
|
+
* the 2026 JazzCash guides, or the success value a flow specification
|
|
33
|
+
* transcribes from its own provider's guide.
|
|
34
|
+
*/
|
|
35
|
+
readonly documented: boolean;
|
|
36
|
+
readonly meaning: string;
|
|
37
|
+
readonly outcome: CodeOutcome;
|
|
38
|
+
readonly action: string;
|
|
39
|
+
readonly docRefs: readonly DocRef[];
|
|
40
|
+
}
|
|
41
|
+
export declare const API_SUCCESS_CODE = "000";
|
|
42
|
+
export declare const PAYMENT_COMPLETED_CODE = "121";
|
|
43
|
+
/** Failure codes named explicitly in the IPN guide. */
|
|
44
|
+
export declare const DOCUMENTED_PAYMENT_FAILURE_CODES: readonly string[];
|
|
45
|
+
/** Describe a `pp_ResponseCode` / `ResponseCode` value: did the API call work? */
|
|
46
|
+
export declare function describeApiResponseCode(code: string): ResponseCodeInfo;
|
|
47
|
+
/** Describe a `pp_PaymentResponseCode` value: did the payment succeed? */
|
|
48
|
+
export declare function describePaymentResponseCode(code: string): ResponseCodeInfo;
|
|
49
|
+
export type TransactionClassification = 'completed' | 'failed' | 'pending' | 'unknown';
|
|
50
|
+
/**
|
|
51
|
+
* Which API produced the response.
|
|
52
|
+
*
|
|
53
|
+
* This changes what the codes mean. A direct payment API reports the payment
|
|
54
|
+
* outcome in `pp_ResponseCode`; Status Inquiry reports the API outcome there and
|
|
55
|
+
* the payment outcome in `pp_PaymentResponseCode`; an inbound IPN notification
|
|
56
|
+
* carries the payment outcome in `pp_ResponseCode`.
|
|
57
|
+
*/
|
|
58
|
+
export type ResponseContext = 'payment' | 'inquiry' | 'refund' | 'ipn' | 'token';
|
|
59
|
+
export interface ClassifiedResponse {
|
|
60
|
+
readonly classification: TransactionClassification;
|
|
61
|
+
readonly reason: string;
|
|
62
|
+
readonly apiOperation: ResponseCodeInfo | undefined;
|
|
63
|
+
readonly paymentStatus: ResponseCodeInfo | undefined;
|
|
64
|
+
/** The acquirer's verdict, where the flow declares a settlement level. */
|
|
65
|
+
readonly settlement?: ResponseCodeInfo | undefined;
|
|
66
|
+
readonly statusLiteral: string | undefined;
|
|
67
|
+
readonly message: string | undefined;
|
|
68
|
+
readonly nextSteps: readonly string[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The success rule a flow specification declares, for codes this module does
|
|
72
|
+
* not document.
|
|
73
|
+
*
|
|
74
|
+
* Derived from the catalogue's own inferred flow type rather than restated, so
|
|
75
|
+
* renaming a field in `responseSpecBase` fails this module at compile time.
|
|
76
|
+
* Hand-declaring the same three members compiled happily against a schema that
|
|
77
|
+
* no longer produced them, which turns a rename into a runtime surprise on the
|
|
78
|
+
* path that decides whether a card was approved.
|
|
79
|
+
*
|
|
80
|
+
* It is the `response` section of a flow, so a caller passes `flow.response` and
|
|
81
|
+
* cannot assemble a contract from one flow's field name and another's success
|
|
82
|
+
* value. The codes themselves are compared literally: this module holds no table
|
|
83
|
+
* for a provider whose guides it has not transcribed, and a guessed meaning is
|
|
84
|
+
* worse than an admitted gap.
|
|
85
|
+
*/
|
|
86
|
+
export type ResponseSuccessContract = Pick<FlowResponseSpec, 'successField' | 'successValue' | 'settlement'>;
|
|
87
|
+
/**
|
|
88
|
+
* The acquirer level of a two-level success rule.
|
|
89
|
+
*
|
|
90
|
+
* A gateway that answers a card sale at two levels reports first that it
|
|
91
|
+
* accepted and processed the request, and separately whether the card issuer
|
|
92
|
+
* approved it. The second answer is the one that says whether money moved.
|
|
93
|
+
*/
|
|
94
|
+
export type SettlementContract = NonNullable<ResponseSuccessContract['settlement']>;
|
|
95
|
+
/**
|
|
96
|
+
* Classify a gateway response into a single actionable outcome.
|
|
97
|
+
*
|
|
98
|
+
* `contract` is the flow's own `response` section. Supplied, it names the field
|
|
99
|
+
* carrying the outcome and, where the provider answers at two levels, the
|
|
100
|
+
* acquirer field that says whether the card was actually approved. Passed as
|
|
101
|
+
* `undefined` — as it is for an inbound IPN, which arrives without a flow — the
|
|
102
|
+
* JazzCash tables above are used, which is what this server shipped with.
|
|
103
|
+
*
|
|
104
|
+
* Required rather than optional, and that is the point. While it was optional,
|
|
105
|
+
* two of the three call sites simply left it off: one of them had `flow` in
|
|
106
|
+
* scope on the same line. Both then reported a DECLINED card as a service-level
|
|
107
|
+
* success, because the settlement veto is carried by the contract. A call site
|
|
108
|
+
* that genuinely has no flow must now say so in writing.
|
|
109
|
+
*
|
|
110
|
+
* A contract naming one of the documented JazzCash success fields still takes
|
|
111
|
+
* the documented path: those codes have meanings, a pending state and a
|
|
112
|
+
* separate payment code, and a literal comparison against `000` would throw all
|
|
113
|
+
* of that away.
|
|
114
|
+
*/
|
|
115
|
+
export declare function classifyResponse(response: Readonly<Record<string, unknown>>, context: ResponseContext, contract: ResponseSuccessContract | undefined): ClassifiedResponse;
|
|
116
|
+
//# sourceMappingURL=response-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-codes.d.ts","sourceRoot":"","sources":["../../src/domain/response-codes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;;;;;;;;;GAcG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,gBAAgB,GAAG,YAAY,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE5D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC,eAAO,MAAM,sBAAsB,QAAQ,CAAC;AAE5C,uDAAuD;AACvD,eAAO,MAAM,gCAAgC,EAAE,SAAS,MAAM,EAAmB,CAAC;AAkBlF,kFAAkF;AAClF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CActE;AAED,0EAA0E;AAC1E,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAyB1E;AAMD,MAAM,MAAM,yBAAyB,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAEvF;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAC;AAEjF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,cAAc,EAAE,yBAAyB,CAAC;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,aAAa,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACrD,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAyMD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,gBAAgB,EAAE,cAAc,GAAG,cAAc,GAAG,YAAY,CAAC,CAAC;AAE7G;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,uBAAuB,CAAC,YAAY,CAAC,CAAC,CAAC;AA6JpF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAC3C,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,uBAAuB,GAAG,SAAS,GAC5C,kBAAkB,CAOpB"}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
export const API_SUCCESS_CODE = '000';
|
|
2
|
+
export const PAYMENT_COMPLETED_CODE = '121';
|
|
3
|
+
/** Failure codes named explicitly in the IPN guide. */
|
|
4
|
+
export const DOCUMENTED_PAYMENT_FAILURE_CODES = ['199', '999'];
|
|
5
|
+
const STATUS_INQUIRY_REF = { docId: 'status-inquiry', sectionId: 'introduction' };
|
|
6
|
+
const IPN_REF = { docId: 'ipn-implementation', sectionId: 'expected-ipn-response' };
|
|
7
|
+
function unknownCode(code, family) {
|
|
8
|
+
return {
|
|
9
|
+
code,
|
|
10
|
+
family,
|
|
11
|
+
documented: false,
|
|
12
|
+
meaning: `Code ${code} is not documented in the 2026 JazzCash integration guides.`,
|
|
13
|
+
outcome: 'unknown',
|
|
14
|
+
action: "Read the accompanying pp_ResponseMessage, which carries the gateway's own description, then confirm the meaning with JazzCash support before treating the transaction as settled or failed.",
|
|
15
|
+
docRefs: [STATUS_INQUIRY_REF],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/** Describe a `pp_ResponseCode` / `ResponseCode` value: did the API call work? */
|
|
19
|
+
export function describeApiResponseCode(code) {
|
|
20
|
+
if (code === API_SUCCESS_CODE) {
|
|
21
|
+
return {
|
|
22
|
+
code,
|
|
23
|
+
family: 'api-operation',
|
|
24
|
+
documented: true,
|
|
25
|
+
meaning: 'The API operation was performed successfully.',
|
|
26
|
+
outcome: 'success',
|
|
27
|
+
action: 'For a direct payment or refund call this also means the transaction succeeded. For Status Inquiry it means only that the enquiry worked — read pp_PaymentResponseCode for the payment outcome.',
|
|
28
|
+
docRefs: [STATUS_INQUIRY_REF],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return unknownCode(code, 'api-operation');
|
|
32
|
+
}
|
|
33
|
+
/** Describe a `pp_PaymentResponseCode` value: did the payment succeed? */
|
|
34
|
+
export function describePaymentResponseCode(code) {
|
|
35
|
+
if (code === PAYMENT_COMPLETED_CODE) {
|
|
36
|
+
return {
|
|
37
|
+
code,
|
|
38
|
+
family: 'payment-status',
|
|
39
|
+
documented: true,
|
|
40
|
+
meaning: 'The transaction is completed and the amount has been debited.',
|
|
41
|
+
outcome: 'success',
|
|
42
|
+
action: 'Mark the order as paid and acknowledge the notification with pp_ResponseCode "000".',
|
|
43
|
+
docRefs: [STATUS_INQUIRY_REF, IPN_REF],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (DOCUMENTED_PAYMENT_FAILURE_CODES.includes(code)) {
|
|
47
|
+
return {
|
|
48
|
+
code,
|
|
49
|
+
family: 'payment-status',
|
|
50
|
+
documented: true,
|
|
51
|
+
meaning: 'The transaction failed.',
|
|
52
|
+
outcome: 'failure',
|
|
53
|
+
action: 'Do not release goods. Read pp_PaymentResponseMessage for the reason, and re-run Status Inquiry at least ten minutes after initiation if the outcome was previously pending.',
|
|
54
|
+
docRefs: [IPN_REF],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return unknownCode(code, 'payment-status');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read a field that JazzCash spells inconsistently.
|
|
61
|
+
*
|
|
62
|
+
* Card and BNPL refund responses use bare `ResponseCode` / `ResponseMessage` /
|
|
63
|
+
* `SecureHash`; every other documented response prefixes them with `pp_`.
|
|
64
|
+
*
|
|
65
|
+
* A JSON number is accepted as well as a string because a service-level code is
|
|
66
|
+
* commonly `0`, not `"0"`; requiring a string would read every such response as
|
|
67
|
+
* carrying no code at all and classify a plain success as unresolved. The value
|
|
68
|
+
* is compared as written, so a provider that sends a zero-padded `0` where the
|
|
69
|
+
* flow declares `"00"` reads as a decline rather than as an approval — the safe
|
|
70
|
+
* direction, and a reason to transcribe the value exactly as the guide prints it.
|
|
71
|
+
*
|
|
72
|
+
* One reader for every path, deliberately. Two readers with different tolerance
|
|
73
|
+
* meant the same `pp_ResponseCode: 0` was "no recognisable response code" to the
|
|
74
|
+
* documented classifier and a success to the declared one.
|
|
75
|
+
*/
|
|
76
|
+
function readField(response, ...names) {
|
|
77
|
+
for (const name of names) {
|
|
78
|
+
const value = response[name];
|
|
79
|
+
if (typeof value === 'number' && Number.isFinite(value)) {
|
|
80
|
+
return String(value);
|
|
81
|
+
}
|
|
82
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
83
|
+
return value.trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
/** The message fields the corpus documents; absent for a provider it does not cover. */
|
|
89
|
+
function readMessage(response) {
|
|
90
|
+
return readField(response, 'pp_PaymentResponseMessage', 'pp_ResponseMessage', 'ResponseMessage');
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* What `pp_Status` may contribute when the payment code is undocumented.
|
|
94
|
+
*
|
|
95
|
+
* `Completed` is deliberately NOT honoured here. An undocumented code beside it
|
|
96
|
+
* is exactly the case whose own advice is to confirm the meaning with JazzCash
|
|
97
|
+
* before treating the transaction as settled, and automation reads the
|
|
98
|
+
* classification rather than the advice: promoting it to `completed` releases
|
|
99
|
+
* goods on a code nobody in this repository can explain. The literals that are
|
|
100
|
+
* honoured all steer a merchant AWAY from releasing goods, so the fallback can
|
|
101
|
+
* delay a decision but never make one.
|
|
102
|
+
*/
|
|
103
|
+
function fallbackFromStatusLiteral(status) {
|
|
104
|
+
const normalised = status.toLowerCase();
|
|
105
|
+
if (normalised.includes('pending') || normalised.includes('progress')) {
|
|
106
|
+
return 'pending';
|
|
107
|
+
}
|
|
108
|
+
if (normalised.includes('fail') || normalised.includes('unsuccessful') || normalised.includes('cancel')) {
|
|
109
|
+
return 'failed';
|
|
110
|
+
}
|
|
111
|
+
return 'unknown';
|
|
112
|
+
}
|
|
113
|
+
const PENDING_STEPS = [
|
|
114
|
+
'Wait at least ten minutes from the transaction time, then call the Status Inquiry API again.',
|
|
115
|
+
'Do not release goods and do not re-charge the customer while the outcome is pending.',
|
|
116
|
+
];
|
|
117
|
+
/**
|
|
118
|
+
* Advice for an outcome nobody can name yet.
|
|
119
|
+
*
|
|
120
|
+
* The opening sentence is the one that matters and is the same wherever the
|
|
121
|
+
* response came from: an unresolved transaction is not a failed one, and a
|
|
122
|
+
* merchant who reads it as failed re-charges a customer who may already have
|
|
123
|
+
* paid. Only the escalation route differs, so it is the only part a caller
|
|
124
|
+
* supplies — two hand-written arrays drifted apart on the shared line before.
|
|
125
|
+
*/
|
|
126
|
+
function unresolvedSteps(...escalation) {
|
|
127
|
+
return ['Treat the transaction as unresolved rather than failed.', ...escalation];
|
|
128
|
+
}
|
|
129
|
+
const UNKNOWN_STEPS = unresolvedSteps('Call the Status Inquiry API to obtain an authoritative outcome.', 'If the code remains undocumented, escalate to JazzCash with the pp_TxnRefNo and pp_RetrievalReferenceNo.');
|
|
130
|
+
function classificationFromOutcome(outcome) {
|
|
131
|
+
if (outcome === 'success') {
|
|
132
|
+
return 'completed';
|
|
133
|
+
}
|
|
134
|
+
return outcome === 'failure' ? 'failed' : 'unknown';
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Which code carries the PAYMENT outcome for this context.
|
|
138
|
+
*
|
|
139
|
+
* A Status Inquiry reports it in `pp_PaymentResponseCode`. An inbound IPN has no
|
|
140
|
+
* such field and reports it in `pp_ResponseCode` instead. Every other context
|
|
141
|
+
* has no separate payment code at all.
|
|
142
|
+
*/
|
|
143
|
+
function resolvePaymentInfo(context, apiCode, paymentCode) {
|
|
144
|
+
if (paymentCode !== undefined) {
|
|
145
|
+
return describePaymentResponseCode(paymentCode);
|
|
146
|
+
}
|
|
147
|
+
if (context === 'ipn' && apiCode !== undefined) {
|
|
148
|
+
return describePaymentResponseCode(apiCode);
|
|
149
|
+
}
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
/** Advice for a classification. `action` is the code-specific step, where one applies. */
|
|
153
|
+
function nextStepsFor(classification, action) {
|
|
154
|
+
switch (classification) {
|
|
155
|
+
case 'completed':
|
|
156
|
+
case 'failed':
|
|
157
|
+
return [action];
|
|
158
|
+
case 'pending':
|
|
159
|
+
return PENDING_STEPS;
|
|
160
|
+
case 'unknown':
|
|
161
|
+
return UNKNOWN_STEPS;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const NO_RECOGNISABLE_CODE = {
|
|
165
|
+
classification: 'unknown',
|
|
166
|
+
reason: 'The response carries no recognisable response code field.',
|
|
167
|
+
apiOperation: undefined,
|
|
168
|
+
paymentStatus: undefined,
|
|
169
|
+
statusLiteral: undefined,
|
|
170
|
+
message: undefined,
|
|
171
|
+
nextSteps: UNKNOWN_STEPS,
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Classify a response whose codes the 2026 JazzCash guides document.
|
|
175
|
+
*
|
|
176
|
+
* Precedence is deliberate: the explicit payment code outranks the API code,
|
|
177
|
+
* because a Status Inquiry that succeeds (`000`) tells you nothing about whether
|
|
178
|
+
* the money moved. `pp_Status` is used only to distinguish pending from unknown,
|
|
179
|
+
* since `Completed` is the sole literal the guides document.
|
|
180
|
+
*/
|
|
181
|
+
function classifyDocumentedResponse(response, context) {
|
|
182
|
+
const apiCode = readField(response, 'pp_ResponseCode', 'ResponseCode');
|
|
183
|
+
const paymentCode = readField(response, 'pp_PaymentResponseCode');
|
|
184
|
+
const statusLiteral = readField(response, 'pp_Status');
|
|
185
|
+
const message = readMessage(response);
|
|
186
|
+
const apiOperation = apiCode === undefined ? undefined : describeApiResponseCode(apiCode);
|
|
187
|
+
const paymentInfo = resolvePaymentInfo(context, apiCode, paymentCode);
|
|
188
|
+
if (paymentInfo !== undefined) {
|
|
189
|
+
// An undocumented payment code falls back to pp_Status, which is the only
|
|
190
|
+
// other signal the guides define — and only as far as pending or failed.
|
|
191
|
+
const classification = paymentInfo.outcome === 'unknown' && statusLiteral !== undefined
|
|
192
|
+
? fallbackFromStatusLiteral(statusLiteral)
|
|
193
|
+
: classificationFromOutcome(paymentInfo.outcome);
|
|
194
|
+
return {
|
|
195
|
+
classification,
|
|
196
|
+
reason: paymentInfo.meaning,
|
|
197
|
+
// An IPN's pp_ResponseCode has already been read as the payment outcome;
|
|
198
|
+
// reporting it a second time as an API outcome would be misleading.
|
|
199
|
+
apiOperation: context === 'ipn' ? undefined : apiOperation,
|
|
200
|
+
paymentStatus: paymentInfo,
|
|
201
|
+
statusLiteral,
|
|
202
|
+
message,
|
|
203
|
+
nextSteps: nextStepsFor(classification, paymentInfo.action),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (apiOperation === undefined) {
|
|
207
|
+
return { ...NO_RECOGNISABLE_CODE, statusLiteral, message };
|
|
208
|
+
}
|
|
209
|
+
// Direct payment, refund and token APIs report the outcome of the operation
|
|
210
|
+
// itself in pp_ResponseCode; there is no separate payment code to consult.
|
|
211
|
+
// A Status Inquiry without a payment code is not yet resolved.
|
|
212
|
+
const inquiryAwaitingOutcome = context === 'inquiry' && apiOperation.outcome === 'success';
|
|
213
|
+
const classification = inquiryAwaitingOutcome ? 'pending' : classificationFromOutcome(apiOperation.outcome);
|
|
214
|
+
return {
|
|
215
|
+
classification,
|
|
216
|
+
reason: inquiryAwaitingOutcome
|
|
217
|
+
? 'The Status Inquiry call succeeded but returned no pp_PaymentResponseCode, so the payment outcome is not yet determined.'
|
|
218
|
+
: apiOperation.meaning,
|
|
219
|
+
apiOperation,
|
|
220
|
+
paymentStatus: undefined,
|
|
221
|
+
statusLiteral,
|
|
222
|
+
message,
|
|
223
|
+
nextSteps: nextStepsFor(classification, apiOperation.action),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** Success fields whose codes the tables above actually describe. */
|
|
227
|
+
const DOCUMENTED_SUCCESS_FIELDS = ['pp_ResponseCode', 'ResponseCode'];
|
|
228
|
+
const DECLARED_UNKNOWN_STEPS = unresolvedSteps("Query the provider's own status API for an authoritative outcome.", 'Do not release goods and do not charge the customer again while the outcome is unresolved.');
|
|
229
|
+
/** Classify against a declared success field whose codes carry no documented table. */
|
|
230
|
+
function classifyDeclaredContract(response, contract) {
|
|
231
|
+
const message = readMessage(response);
|
|
232
|
+
const code = readField(response, contract.successField);
|
|
233
|
+
if (code === undefined) {
|
|
234
|
+
return {
|
|
235
|
+
...NO_RECOGNISABLE_CODE,
|
|
236
|
+
reason: `The response carries no ${contract.successField}, which is the field this flow declares as its outcome.`,
|
|
237
|
+
message,
|
|
238
|
+
nextSteps: DECLARED_UNKNOWN_STEPS,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (code !== contract.successValue) {
|
|
242
|
+
// Not the declared success value means NOT a success. It does not mean a
|
|
243
|
+
// known failure: the value may name a timeout or an in-progress state, and
|
|
244
|
+
// reporting that as failed invites a second charge for a payment that may
|
|
245
|
+
// already have gone through.
|
|
246
|
+
const info = {
|
|
247
|
+
code,
|
|
248
|
+
family: 'api-operation',
|
|
249
|
+
documented: false,
|
|
250
|
+
meaning: `${contract.successField} is "${code}", not the success value "${contract.successValue}" this flow declares.`,
|
|
251
|
+
outcome: 'unknown',
|
|
252
|
+
action: `Read the provider's own response message, then confirm what ${contract.successField} "${code}" means with the provider before treating the transaction as settled or failed.`,
|
|
253
|
+
docRefs: [],
|
|
254
|
+
};
|
|
255
|
+
return {
|
|
256
|
+
classification: 'unknown',
|
|
257
|
+
reason: info.meaning,
|
|
258
|
+
apiOperation: info,
|
|
259
|
+
paymentStatus: undefined,
|
|
260
|
+
statusLiteral: undefined,
|
|
261
|
+
message,
|
|
262
|
+
nextSteps: DECLARED_UNKNOWN_STEPS,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
const info = {
|
|
266
|
+
code,
|
|
267
|
+
family: 'api-operation',
|
|
268
|
+
documented: true,
|
|
269
|
+
meaning: `${contract.successField} is "${code}", the success value this flow declares.`,
|
|
270
|
+
outcome: 'success',
|
|
271
|
+
action: "Record the provider's own reference for the transaction and reconcile it against the provider's settlement report.",
|
|
272
|
+
docRefs: [],
|
|
273
|
+
};
|
|
274
|
+
return {
|
|
275
|
+
classification: 'completed',
|
|
276
|
+
reason: info.meaning,
|
|
277
|
+
apiOperation: info,
|
|
278
|
+
paymentStatus: undefined,
|
|
279
|
+
statusLiteral: undefined,
|
|
280
|
+
message,
|
|
281
|
+
nextSteps: [info.action],
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Apply the settlement level on top of a service-level result.
|
|
286
|
+
*
|
|
287
|
+
* The two levels answer different questions, and a contract that checks only
|
|
288
|
+
* the first classifies a DECLINED card as a successful payment: the gateway
|
|
289
|
+
* accepted and processed the request exactly as asked, and the issuer refused
|
|
290
|
+
* it. A merchant who releases goods on that classification is never paid.
|
|
291
|
+
*
|
|
292
|
+
* The settlement check can only VETO a success. It never promotes a
|
|
293
|
+
* service-level failure or an unresolved outcome into a completed payment: an
|
|
294
|
+
* approval code beside a request the gateway says it did not process describes
|
|
295
|
+
* an authorisation for something else, or a response being read wrongly, and
|
|
296
|
+
* neither is evidence that this transaction completed.
|
|
297
|
+
*/
|
|
298
|
+
function applySettlementLevel(base, response, settlement) {
|
|
299
|
+
if (settlement === undefined || base.classification !== 'completed') {
|
|
300
|
+
return base;
|
|
301
|
+
}
|
|
302
|
+
const code = readField(response, settlement.field);
|
|
303
|
+
if (code === undefined) {
|
|
304
|
+
const info = {
|
|
305
|
+
// Empty because there genuinely was no code. Reported rather than omitted,
|
|
306
|
+
// so a caller can see that the settlement level was consulted and came
|
|
307
|
+
// back with nothing — which is not the same as a flow that has no such
|
|
308
|
+
// level at all.
|
|
309
|
+
code: '',
|
|
310
|
+
family: 'settlement',
|
|
311
|
+
documented: false,
|
|
312
|
+
meaning: `The response carries no ${settlement.field}, so the acquirer's verdict is missing from a call that declares one.`,
|
|
313
|
+
outcome: 'unknown',
|
|
314
|
+
action: `Ask the provider for the ${settlement.field} of this transaction before releasing goods. A service-level success on its own does not say the card was approved.`,
|
|
315
|
+
docRefs: [],
|
|
316
|
+
};
|
|
317
|
+
return {
|
|
318
|
+
...base,
|
|
319
|
+
classification: 'unknown',
|
|
320
|
+
reason: info.meaning,
|
|
321
|
+
settlement: info,
|
|
322
|
+
nextSteps: DECLARED_UNKNOWN_STEPS,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (code === settlement.successValue) {
|
|
326
|
+
const info = {
|
|
327
|
+
code,
|
|
328
|
+
family: 'settlement',
|
|
329
|
+
documented: true,
|
|
330
|
+
meaning: `${settlement.field} is "${code}", the approval value this flow declares.`,
|
|
331
|
+
outcome: 'success',
|
|
332
|
+
action: base.nextSteps[0] ?? "Reconcile the transaction against the provider's settlement report.",
|
|
333
|
+
docRefs: [],
|
|
334
|
+
};
|
|
335
|
+
return { ...base, settlement: info };
|
|
336
|
+
}
|
|
337
|
+
const info = {
|
|
338
|
+
code,
|
|
339
|
+
family: 'settlement',
|
|
340
|
+
documented: false,
|
|
341
|
+
meaning: `${settlement.field} is "${code}", not the approval value "${settlement.successValue}". The gateway processed the request, and the card was NOT approved: no money moved.`,
|
|
342
|
+
outcome: 'failure',
|
|
343
|
+
action: `Do not release goods. Read the provider's settlement message for the reason, ask the customer for another payment method, and quote ${settlement.field} "${code}" if you raise it with the provider.`,
|
|
344
|
+
docRefs: [],
|
|
345
|
+
};
|
|
346
|
+
return {
|
|
347
|
+
...base,
|
|
348
|
+
classification: 'failed',
|
|
349
|
+
reason: info.meaning,
|
|
350
|
+
settlement: info,
|
|
351
|
+
nextSteps: [info.action],
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Classify a gateway response into a single actionable outcome.
|
|
356
|
+
*
|
|
357
|
+
* `contract` is the flow's own `response` section. Supplied, it names the field
|
|
358
|
+
* carrying the outcome and, where the provider answers at two levels, the
|
|
359
|
+
* acquirer field that says whether the card was actually approved. Passed as
|
|
360
|
+
* `undefined` — as it is for an inbound IPN, which arrives without a flow — the
|
|
361
|
+
* JazzCash tables above are used, which is what this server shipped with.
|
|
362
|
+
*
|
|
363
|
+
* Required rather than optional, and that is the point. While it was optional,
|
|
364
|
+
* two of the three call sites simply left it off: one of them had `flow` in
|
|
365
|
+
* scope on the same line. Both then reported a DECLINED card as a service-level
|
|
366
|
+
* success, because the settlement veto is carried by the contract. A call site
|
|
367
|
+
* that genuinely has no flow must now say so in writing.
|
|
368
|
+
*
|
|
369
|
+
* A contract naming one of the documented JazzCash success fields still takes
|
|
370
|
+
* the documented path: those codes have meanings, a pending state and a
|
|
371
|
+
* separate payment code, and a literal comparison against `000` would throw all
|
|
372
|
+
* of that away.
|
|
373
|
+
*/
|
|
374
|
+
export function classifyResponse(response, context, contract) {
|
|
375
|
+
const serviceLevel = contract !== undefined && !DOCUMENTED_SUCCESS_FIELDS.includes(contract.successField)
|
|
376
|
+
? classifyDeclaredContract(response, contract)
|
|
377
|
+
: classifyDocumentedResponse(response, context);
|
|
378
|
+
return applySettlementLevel(serviceLevel, response, contract?.settlement);
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=response-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-codes.js","sourceRoot":"","sources":["../../src/domain/response-codes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type SignatureOptions } from './signature/registry.js';
|
|
2
|
+
import { type JazzCashSignatureSettings } from './signature/jazzcash.js';
|
|
3
|
+
import type { SchemeProvenance, SignatureBreakdown, SignatureDiagnosis, SignatureVariant, SignatureVerification } from './signature/scheme.js';
|
|
4
|
+
import type { RawParameters } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* `pp_SecureHash` construction, verification and mismatch diagnosis.
|
|
7
|
+
*
|
|
8
|
+
* The construction itself, the JazzCash forensic table and the engine that runs
|
|
9
|
+
* them live in `./signature/`. This module is the JazzCash-named entry point the
|
|
10
|
+
* builder, the gateway client and the tools were written against, kept so that
|
|
11
|
+
* naming a second scheme is a change to the options a call site passes rather
|
|
12
|
+
* than a rewrite of every call site at once. A half-migrated call site would
|
|
13
|
+
* sign with the wrong construction and report the resulting rejection as a
|
|
14
|
+
* merchant bug.
|
|
15
|
+
*
|
|
16
|
+
* Only the names with importers are re-exported. An alias nobody uses reads as
|
|
17
|
+
* a supported entry point, and the next module reaches for it instead of the
|
|
18
|
+
* provider-neutral name in `./signature/`, which is where a second provider has
|
|
19
|
+
* to be served from.
|
|
20
|
+
*
|
|
21
|
+
* Every function here selects the JazzCash scheme unless the options name
|
|
22
|
+
* another one; see `SignatureOptions`.
|
|
23
|
+
*/
|
|
24
|
+
/** The exact string a payload is digested from, and why each field is in it. */
|
|
25
|
+
export type HashStringBreakdown = SignatureBreakdown;
|
|
26
|
+
/**
|
|
27
|
+
* The JazzCash forensic table.
|
|
28
|
+
*
|
|
29
|
+
* Reachable only as this scheme's property. Several entries describe how other
|
|
30
|
+
* gateways sign correctly, so a table shared between providers would report
|
|
31
|
+
* working code as a proven defect.
|
|
32
|
+
*/
|
|
33
|
+
export declare const HASH_VARIANTS: readonly SignatureVariant<JazzCashSignatureSettings>[];
|
|
34
|
+
/**
|
|
35
|
+
* Build the exact string that gets hashed, plus the reasoning behind it.
|
|
36
|
+
*
|
|
37
|
+
* Returning the breakdown rather than only the digest is the point: a merchant
|
|
38
|
+
* debugging `HASH_MISMATCH` needs to see which fields were used and in what
|
|
39
|
+
* order, which is precisely what no error message from the gateway tells them.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildHashString(parameters: RawParameters, integritySalt: string, options?: SignatureOptions): HashStringBreakdown;
|
|
42
|
+
/** HMAC-SHA256 a prepared string with the Integrity Salt as key. Lowercase hex. */
|
|
43
|
+
export declare function hmacSha256Hex(message: string, key: string): string;
|
|
44
|
+
/** Compute `pp_SecureHash` for a payload. Lowercase hex, as PHP's `hash_hmac` emits. */
|
|
45
|
+
export declare function computeSecureHash(parameters: RawParameters, integritySalt: string, options?: SignatureOptions): string;
|
|
46
|
+
/**
|
|
47
|
+
* Constant-time, case-insensitive hash comparison.
|
|
48
|
+
*
|
|
49
|
+
* Case insensitivity is required, not merely tolerant: request samples in the
|
|
50
|
+
* guides are lowercase (PHP `hash_hmac` output) while response samples are
|
|
51
|
+
* uppercase. Both are the same digest.
|
|
52
|
+
*/
|
|
53
|
+
export declare function hashesMatch(left: string, right: string): boolean;
|
|
54
|
+
/** Verify a supplied hash against a freshly computed one. */
|
|
55
|
+
export declare function verifySecureHash(parameters: RawParameters, integritySalt: string, providedHash: string, options?: SignatureOptions): SignatureVerification;
|
|
56
|
+
/**
|
|
57
|
+
* Explain why a hash does not match.
|
|
58
|
+
*
|
|
59
|
+
* Runs the selected scheme's known wrong constructions against the merchant's
|
|
60
|
+
* own parameters. A variant that reproduces their hash is reported as
|
|
61
|
+
* `confirmed`: that is not a guess, it is a demonstration of what their code
|
|
62
|
+
* did — which is why only the scheme the payload was signed under may be asked,
|
|
63
|
+
* and why `provenance` says whether the payload named that scheme.
|
|
64
|
+
*
|
|
65
|
+
* `provenance` is required rather than defaulted, for the same reason it is
|
|
66
|
+
* required on `diagnoseSignatureFor`: the safe value is the one that reports
|
|
67
|
+
* less, and a default of `declared` is the unsafe one, so a call site that
|
|
68
|
+
* forgot the argument would accuse a merchant of a construction error
|
|
69
|
+
* demonstrated under a construction nobody said they used. `declared` is the
|
|
70
|
+
* answer for every REQUEST — a flow's own hash specification selects the
|
|
71
|
+
* construction, and the flowless default selects `pp_`/`ppmpf_` fields only, so
|
|
72
|
+
* another provider's payload contributes nothing to it and no variant can
|
|
73
|
+
* reproduce that provider's signature. The response derivations are the ones
|
|
74
|
+
* that must pass `assumed`; see `requestHashOptions`, `responseHashOptions` and
|
|
75
|
+
* `forensicProvenance` in `src/catalogue/hash-options.ts`.
|
|
76
|
+
*/
|
|
77
|
+
export declare function diagnoseHashMismatch(parameters: RawParameters, integritySalt: string, providedHash: string, options: SignatureOptions | undefined, provenance: SchemeProvenance): SignatureDiagnosis;
|
|
78
|
+
//# sourceMappingURL=secure-hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure-hash.d.ts","sourceRoot":"","sources":["../../src/domain/secure-hash.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAmB,KAAK,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAE1F,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,gFAAgF;AAChF,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAErD;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,gBAAgB,CAAC,yBAAyB,CAAC,EAA6B,CAAC;AAE9G;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,aAAa,EACzB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,mBAAmB,CAErB;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAElE;AAED,wFAAwF;AACxF,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,aAAa,EACzB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,gBAAgB,GACzB,MAAM,CAER;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,aAAa,EACzB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,gBAAgB,GACzB,qBAAqB,CAEvB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,aAAa,EACzB,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,gBAAgB,GAAG,SAAS,EACrC,UAAU,EAAE,gBAAgB,GAC3B,kBAAkB,CAEpB"}
|