@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,9 @@
|
|
|
1
|
+
import { type ValidationRule } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Constant parameters must not be modified.
|
|
4
|
+
*
|
|
5
|
+
* "Mandatory constant parameters (such as pp_Language, pp_TxnCurrency,
|
|
6
|
+
* pp_TxnType and pp_Version) must not be modified."
|
|
7
|
+
*/
|
|
8
|
+
export declare const constantsRule: ValidationRule;
|
|
9
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/E;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,cAyB3B,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { issue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Constant parameters must not be modified.
|
|
4
|
+
*
|
|
5
|
+
* "Mandatory constant parameters (such as pp_Language, pp_TxnCurrency,
|
|
6
|
+
* pp_TxnType and pp_Version) must not be modified."
|
|
7
|
+
*/
|
|
8
|
+
export const constantsRule = (context) => {
|
|
9
|
+
const issues = [];
|
|
10
|
+
for (const parameter of context.flow.parameters) {
|
|
11
|
+
if (parameter.valueType !== 'constant' || parameter.constantValue === undefined) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const value = context.parameters[parameter.name];
|
|
15
|
+
if (value === undefined || value === parameter.constantValue) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
issues.push(issue(context, {
|
|
19
|
+
code: 'constants.modified',
|
|
20
|
+
severity: 'error',
|
|
21
|
+
field: parameter.name,
|
|
22
|
+
message: `${parameter.name} is "${value}" but ${context.flow.title} fixes it at "${parameter.constantValue}".`,
|
|
23
|
+
fix: `Set "${parameter.name}" to "${parameter.constantValue}". ${parameter.notes}`,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
return issues;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/validation/rules/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAmB,CAAC,OAAO,EAA8B,EAAE;IACnF,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,SAAS,KAAK,UAAU,IAAI,SAAS,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YAChF,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,CAAC,aAAa,EAAE,CAAC;YAC7D,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,oBAAoB;YAC1B,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,QAAQ,KAAK,SAAS,OAAO,CAAC,IAAI,CAAC,KAAK,iBAAiB,SAAS,CAAC,aAAa,IAAI;YAC9G,GAAG,EAAE,QAAQ,SAAS,CAAC,IAAI,SAAS,SAAS,CAAC,aAAa,MAAM,SAAS,CAAC,KAAK,EAAE;SACnF,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraints.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/constraints.ts"],"names":[],"mappings":"AACA,OAAO,EAAiD,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAwFjG,eAAO,MAAM,eAAe,EAAE,cAsC7B,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { issue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The `maxLength` and `pattern` a flow declares are enforced generically.
|
|
4
|
+
*
|
|
5
|
+
* The catalogue is the contract between the corpus and the code, so a correction
|
|
6
|
+
* from JazzCash must be a data change rather than a code change. Without this
|
|
7
|
+
* rule the declared constraints are decorative: the 20-character reference limit
|
|
8
|
+
* would hold only because `domain/txn-ref.ts` hard-codes it, and a `pattern`
|
|
9
|
+
* added to a flow file would be silently ignored.
|
|
10
|
+
*
|
|
11
|
+
* Ordered last in the rule set, because it is the fallback: a value type with a
|
|
12
|
+
* dedicated rule gets that rule's specific diagnosis first, and this one only
|
|
13
|
+
* reports the constraints no dedicated rule expresses.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Value types whose own rule already enforces the declared length.
|
|
17
|
+
*
|
|
18
|
+
* `txn-ref` and `request-id` are length-checked against `parameter.maxLength` by
|
|
19
|
+
* the reference rule, which can also name the documented shape. Reporting the
|
|
20
|
+
* same violation here would give the merchant two errors for one mistake.
|
|
21
|
+
*/
|
|
22
|
+
const LENGTH_CHECKED_BY_REFERENCE_RULE = ['txn-ref', 'request-id'];
|
|
23
|
+
function maxLengthIssue(context, parameter, value) {
|
|
24
|
+
const limit = String(parameter.maxLength);
|
|
25
|
+
return issue(context, {
|
|
26
|
+
code: 'constraints.max-length',
|
|
27
|
+
severity: 'error',
|
|
28
|
+
field: parameter.name,
|
|
29
|
+
message: `${parameter.name} is ${String(value.length)} characters; ${context.flow.title} declares a maximum of ${limit}.`,
|
|
30
|
+
fix: `Shorten ${parameter.name} to ${limit} characters or fewer. ${parameter.notes}`,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Report a value that does not satisfy the declared pattern.
|
|
35
|
+
*
|
|
36
|
+
* The value is echoed so the merchant can see what was rejected, except for a
|
|
37
|
+
* parameter the flow marks `sensitive`: those are credentials and personal data,
|
|
38
|
+
* and this text reaches a transcript.
|
|
39
|
+
*/
|
|
40
|
+
function patternIssue(context, parameter, value, pattern) {
|
|
41
|
+
const subject = parameter.sensitive
|
|
42
|
+
? `${parameter.name} does not match the pattern`
|
|
43
|
+
: `${parameter.name} is "${value}", which does not match the pattern`;
|
|
44
|
+
return issue(context, {
|
|
45
|
+
code: 'constraints.pattern-mismatch',
|
|
46
|
+
severity: 'error',
|
|
47
|
+
field: parameter.name,
|
|
48
|
+
message: `${subject} ${context.flow.title} declares for it (${pattern}).`,
|
|
49
|
+
fix: `Send a ${parameter.name} matching ${pattern}. ${parameter.notes}`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Report a declared pattern that is not a usable regular expression.
|
|
54
|
+
*
|
|
55
|
+
* This is a defect in the flow data, not in the merchant's payload, so it is a
|
|
56
|
+
* warning addressed to whoever maintains the corpus. Letting `new RegExp` throw
|
|
57
|
+
* instead would take down every call that touches the flow.
|
|
58
|
+
*/
|
|
59
|
+
function unusablePatternIssue(context, parameter, pattern) {
|
|
60
|
+
return issue(context, {
|
|
61
|
+
code: 'constraints.pattern-unusable',
|
|
62
|
+
severity: 'warning',
|
|
63
|
+
field: parameter.name,
|
|
64
|
+
message: `${context.flow.title} declares the pattern ${pattern} for ${parameter.name}, but it is not a valid regular expression, so the constraint was not checked.`,
|
|
65
|
+
fix: `Correct the "pattern" declared for ${parameter.name} in the flow specification, or remove it.`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Compile a declared pattern, or return `undefined` when it cannot be compiled.
|
|
70
|
+
*
|
|
71
|
+
* The source string is used exactly as declared, so a flow that needs a
|
|
72
|
+
* whole-value match anchors it with `^` and `$` itself.
|
|
73
|
+
*/
|
|
74
|
+
function compilePattern(pattern) {
|
|
75
|
+
try {
|
|
76
|
+
return new RegExp(pattern);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export const constraintsRule = (context) => {
|
|
83
|
+
const issues = [];
|
|
84
|
+
for (const parameter of context.flow.parameters) {
|
|
85
|
+
const value = context.parameters[parameter.name];
|
|
86
|
+
// An absent or empty value is the presence rule's diagnosis. A constraint
|
|
87
|
+
// describes the shape of a value, not whether one is required.
|
|
88
|
+
if (value === undefined || value === '') {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (parameter.maxLength !== undefined &&
|
|
92
|
+
value.length > parameter.maxLength &&
|
|
93
|
+
!LENGTH_CHECKED_BY_REFERENCE_RULE.includes(parameter.valueType)) {
|
|
94
|
+
issues.push(maxLengthIssue(context, parameter, value));
|
|
95
|
+
}
|
|
96
|
+
if (parameter.pattern === undefined) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
// Compiled once per declared pattern, per validation, rather than cached
|
|
100
|
+
// across calls: a module-level cache would be shared mutable state in
|
|
101
|
+
// exchange for microseconds on a payload of at most two dozen fields.
|
|
102
|
+
const expression = compilePattern(parameter.pattern);
|
|
103
|
+
if (expression === undefined) {
|
|
104
|
+
issues.push(unusablePatternIssue(context, parameter, parameter.pattern));
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (!expression.test(value)) {
|
|
108
|
+
issues.push(patternIssue(context, parameter, value, parameter.pattern));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return issues;
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=constraints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraints.js","sourceRoot":"","sources":["../../../src/validation/rules/constraints.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datetime.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/datetime.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAa/E,eAAO,MAAM,YAAY,EAAE,cA8C1B,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { formatTxnDateTime, isValidTxnDateTime, daysBetweenTxnDateTimes } from '../../domain/datetime.js';
|
|
2
|
+
import { issue } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Timestamp format and plausibility.
|
|
5
|
+
*
|
|
6
|
+
* Format errors are hard failures. A stamp that is far from the current
|
|
7
|
+
* Pakistan time is only a warning: a merchant may legitimately be replaying a
|
|
8
|
+
* historical payload while debugging, and refusing that would be unhelpful.
|
|
9
|
+
*/
|
|
10
|
+
/** Days either side of now beyond which a transaction stamp looks like a clock error. */
|
|
11
|
+
const PLAUSIBLE_WINDOW_DAYS = 2;
|
|
12
|
+
export const dateTimeRule = (context) => {
|
|
13
|
+
const issues = [];
|
|
14
|
+
const nowStamp = formatTxnDateTime(context.now);
|
|
15
|
+
for (const parameter of context.flow.parameters) {
|
|
16
|
+
if (parameter.valueType !== 'pkt-datetime' && parameter.valueType !== 'pkt-expiry') {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const value = context.parameters[parameter.name];
|
|
20
|
+
if (value === undefined || value === '') {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (!isValidTxnDateTime(value)) {
|
|
24
|
+
issues.push(issue(context, {
|
|
25
|
+
code: 'datetime.invalid-format',
|
|
26
|
+
severity: 'error',
|
|
27
|
+
field: parameter.name,
|
|
28
|
+
message: `${parameter.name} is "${value}", which is not a valid YYYYMMDDHHMMSS timestamp.`,
|
|
29
|
+
fix: `Format the value as 14 digits in Pakistan Standard Time, for example "${nowStamp}". In PHP, call date_default_timezone_set("Asia/Karachi") first.`,
|
|
30
|
+
}));
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (parameter.valueType !== 'pkt-datetime') {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const drift = daysBetweenTxnDateTimes(nowStamp, value);
|
|
37
|
+
if (Math.abs(drift) > PLAUSIBLE_WINDOW_DAYS) {
|
|
38
|
+
issues.push(issue(context, {
|
|
39
|
+
code: 'datetime.implausible',
|
|
40
|
+
severity: 'warning',
|
|
41
|
+
field: parameter.name,
|
|
42
|
+
message: `${parameter.name} is "${value}", which is ${Math.abs(drift).toFixed(1)} days ${drift > 0 ? 'in the future' : 'in the past'} relative to the current Pakistan time (${nowStamp}).`,
|
|
43
|
+
fix: 'Confirm the server clock and that the timestamp is generated in Asia/Karachi rather than in the host time zone.',
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return issues;
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=datetime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datetime.js","sourceRoot":"","sources":["../../../src/validation/rules/datetime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC1G,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;GAMG;AAEH,yFAAyF;AACzF,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC,MAAM,CAAC,MAAM,YAAY,GAAmB,CAAC,OAAO,EAA8B,EAAE;IAClF,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAEhD,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,SAAS,KAAK,cAAc,IAAI,SAAS,CAAC,SAAS,KAAK,YAAY,EAAE,CAAC;YACnF,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,yBAAyB;gBAC/B,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,SAAS,CAAC,IAAI;gBACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,QAAQ,KAAK,mDAAmD;gBAC1F,GAAG,EAAE,yEAAyE,QAAQ,kEAAkE;aACzJ,CAAC,CACH,CAAC;YACF,SAAS;QACX,CAAC;QAED,IAAI,SAAS,CAAC,SAAS,KAAK,cAAc,EAAE,CAAC;YAC3C,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,uBAAuB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACvD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,qBAAqB,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,sBAAsB;gBAC5B,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,SAAS,CAAC,IAAI;gBACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,QAAQ,KAAK,eAAe,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,aAAa,2CAA2C,QAAQ,IAAI;gBAC3L,GAAG,EAAE,iHAAiH;aACvH,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ValidationRule } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unused parameters must be exactly `""`.
|
|
4
|
+
*
|
|
5
|
+
* "Parameters with no value must remain as empty strings. Do not replace them
|
|
6
|
+
* with null and do not remove them from the request."
|
|
7
|
+
*
|
|
8
|
+
* A JSON `null` is the common mistake here. It also changes the secure hash,
|
|
9
|
+
* because a null stringifies differently from an empty string, so the merchant
|
|
10
|
+
* sees a hash mismatch rather than a field error.
|
|
11
|
+
*/
|
|
12
|
+
export declare const emptyStringRule: ValidationRule;
|
|
13
|
+
//# sourceMappingURL=empty-string.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-string.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/empty-string.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/E;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,cAyB7B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { issue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Unused parameters must be exactly `""`.
|
|
4
|
+
*
|
|
5
|
+
* "Parameters with no value must remain as empty strings. Do not replace them
|
|
6
|
+
* with null and do not remove them from the request."
|
|
7
|
+
*
|
|
8
|
+
* A JSON `null` is the common mistake here. It also changes the secure hash,
|
|
9
|
+
* because a null stringifies differently from an empty string, so the merchant
|
|
10
|
+
* sees a hash mismatch rather than a field error.
|
|
11
|
+
*/
|
|
12
|
+
export const emptyStringRule = (context) => {
|
|
13
|
+
const issues = [];
|
|
14
|
+
for (const parameter of context.flow.parameters) {
|
|
15
|
+
if (parameter.requirement !== 'must-be-empty') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const value = context.parameters[parameter.name];
|
|
19
|
+
if (value === undefined || value === '') {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
issues.push(issue(context, {
|
|
23
|
+
code: 'empty-string.unexpected-value',
|
|
24
|
+
severity: 'error',
|
|
25
|
+
field: parameter.name,
|
|
26
|
+
message: `${parameter.name} carries the value "${value}", but ${context.flow.title} requires it to be sent as an empty string.`,
|
|
27
|
+
fix: `Set "${parameter.name}" to "". Because a non-empty value participates in the secure hash, leaving it populated also causes a hash mismatch.`,
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
return issues;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=empty-string.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-string.js","sourceRoot":"","sources":["../../../src/validation/rules/empty-string.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAmB,CAAC,OAAO,EAA8B,EAAE;IACrF,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,WAAW,KAAK,eAAe,EAAE,CAAC;YAC9C,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,+BAA+B;YACrC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,uBAAuB,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,KAAK,6CAA6C;YAC/H,GAAG,EAAE,QAAQ,SAAS,CAAC,IAAI,uHAAuH;SACnJ,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expiry.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/expiry.ts"],"names":[],"mappings":"AACA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAa/E,eAAO,MAAM,UAAU,EAAE,cA+CxB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { daysBetweenTxnDateTimes, isExpiryAfterTransaction, isValidTxnDateTime } from '../../domain/datetime.js';
|
|
2
|
+
import { issue } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* `pp_TxnExpiryDateTime` must follow `pp_TxnDateTime` by about one day.
|
|
5
|
+
*
|
|
6
|
+
* "Must be set to one day after the transaction date." An expiry that precedes
|
|
7
|
+
* the transaction is an error; a materially different window is a warning,
|
|
8
|
+
* since the guides state the rule without stating a tolerance.
|
|
9
|
+
*/
|
|
10
|
+
const EXPECTED_WINDOW_DAYS = 1;
|
|
11
|
+
const WINDOW_TOLERANCE_DAYS = 0.5;
|
|
12
|
+
export const expiryRule = (context) => {
|
|
13
|
+
const transactionField = context.flow.parameters.find((entry) => entry.valueType === 'pkt-datetime');
|
|
14
|
+
const expiryField = context.flow.parameters.find((entry) => entry.valueType === 'pkt-expiry');
|
|
15
|
+
if (transactionField === undefined || expiryField === undefined) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const transaction = context.parameters[transactionField.name];
|
|
19
|
+
const expiry = context.parameters[expiryField.name];
|
|
20
|
+
// Format problems are the datetime rule's responsibility.
|
|
21
|
+
if (transaction === undefined ||
|
|
22
|
+
expiry === undefined ||
|
|
23
|
+
!isValidTxnDateTime(transaction) ||
|
|
24
|
+
!isValidTxnDateTime(expiry)) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
if (!isExpiryAfterTransaction(transaction, expiry)) {
|
|
28
|
+
return [
|
|
29
|
+
issue(context, {
|
|
30
|
+
code: 'expiry.not-after-transaction',
|
|
31
|
+
severity: 'error',
|
|
32
|
+
field: expiryField.name,
|
|
33
|
+
message: `${expiryField.name} ("${expiry}") is not after ${transactionField.name} ("${transaction}"). The transaction would be expired before it began.`,
|
|
34
|
+
fix: `Set ${expiryField.name} to one day after ${transactionField.name}. In PHP: date('YmdHis', strtotime('+1 Days')).`,
|
|
35
|
+
}),
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
const window = daysBetweenTxnDateTimes(transaction, expiry);
|
|
39
|
+
if (Math.abs(window - EXPECTED_WINDOW_DAYS) > WINDOW_TOLERANCE_DAYS) {
|
|
40
|
+
return [
|
|
41
|
+
issue(context, {
|
|
42
|
+
code: 'expiry.unexpected-window',
|
|
43
|
+
severity: 'warning',
|
|
44
|
+
field: expiryField.name,
|
|
45
|
+
message: `${expiryField.name} is ${window.toFixed(2)} days after ${transactionField.name}. The guides specify one day.`,
|
|
46
|
+
fix: `Set ${expiryField.name} to exactly one day after ${transactionField.name} unless JazzCash has approved a different window for your account.`,
|
|
47
|
+
}),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=expiry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expiry.js","sourceRoot":"","sources":["../../../src/validation/rules/expiry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACjH,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;GAMG;AAEH,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,MAAM,CAAC,MAAM,UAAU,GAAmB,CAAC,OAAO,EAA8B,EAAE;IAChF,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,cAAc,CAAC,CAAC;IACrG,MAAM,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,YAAY,CAAC,CAAC;IAE9F,IAAI,gBAAgB,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAEpD,0DAA0D;IAC1D,IACE,WAAW,KAAK,SAAS;QACzB,MAAM,KAAK,SAAS;QACpB,CAAC,kBAAkB,CAAC,WAAW,CAAC;QAChC,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAC3B,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC,wBAAwB,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC;QACnD,OAAO;YACL,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,8BAA8B;gBACpC,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,WAAW,CAAC,IAAI;gBACvB,OAAO,EAAE,GAAG,WAAW,CAAC,IAAI,MAAM,MAAM,mBAAmB,gBAAgB,CAAC,IAAI,MAAM,WAAW,uDAAuD;gBACxJ,GAAG,EAAE,OAAO,WAAW,CAAC,IAAI,qBAAqB,gBAAgB,CAAC,IAAI,iDAAiD;aACxH,CAAC;SACH,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,uBAAuB,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAC5D,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,oBAAoB,CAAC,GAAG,qBAAqB,EAAE,CAAC;QACpE,OAAO;YACL,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,0BAA0B;gBAChC,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,WAAW,CAAC,IAAI;gBACvB,OAAO,EAAE,GAAG,WAAW,CAAC,IAAI,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,gBAAgB,CAAC,IAAI,+BAA+B;gBACvH,GAAG,EAAE,OAAO,WAAW,CAAC,IAAI,6BAA6B,gBAAgB,CAAC,IAAI,oEAAoE;aACnJ,CAAC;SACH,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"msisdn.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/msisdn.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAc/E,eAAO,MAAM,UAAU,EAAE,cA0CxB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { issue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Mobile wallet numbers.
|
|
4
|
+
*
|
|
5
|
+
* Every sample in the corpus uses the local 11-digit form beginning `03`, for
|
|
6
|
+
* example `03123456789` and `03002874299`. An international form is accepted
|
|
7
|
+
* with a warning rather than an error: no guide forbids it, but nothing in the
|
|
8
|
+
* corpus demonstrates it working either.
|
|
9
|
+
*/
|
|
10
|
+
const LOCAL_FORMAT = /^03\d{9}$/;
|
|
11
|
+
const INTERNATIONAL_FORMAT = /^(?:\+?92)3\d{9}$/;
|
|
12
|
+
export const msisdnRule = (context) => {
|
|
13
|
+
const issues = [];
|
|
14
|
+
for (const parameter of context.flow.parameters) {
|
|
15
|
+
if (parameter.valueType !== 'msisdn') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const value = context.parameters[parameter.name];
|
|
19
|
+
if (value === undefined || value === '') {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
if (LOCAL_FORMAT.test(value)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (INTERNATIONAL_FORMAT.test(value)) {
|
|
26
|
+
issues.push(issue(context, {
|
|
27
|
+
code: 'msisdn.international-format',
|
|
28
|
+
severity: 'warning',
|
|
29
|
+
field: parameter.name,
|
|
30
|
+
message: `${parameter.name} uses an international format. Every documented sample uses the local 11-digit form.`,
|
|
31
|
+
fix: `Send the number as 03XXXXXXXXX, for example "${value.replace(/^\+?92/, '0')}".`,
|
|
32
|
+
}));
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
issues.push(issue(context, {
|
|
36
|
+
code: 'msisdn.invalid',
|
|
37
|
+
severity: 'error',
|
|
38
|
+
field: parameter.name,
|
|
39
|
+
message: `${parameter.name} is "${value}", which is not a Pakistani mobile number in the documented format.`,
|
|
40
|
+
fix: 'Send 11 digits beginning 03, for example "03123456789". Remove spaces, dashes and country codes.',
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
return issues;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=msisdn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"msisdn.js","sourceRoot":"","sources":["../../../src/validation/rules/msisdn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;;GAOG;AAEH,MAAM,YAAY,GAAG,WAAW,CAAC;AACjC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAEjD,MAAM,CAAC,MAAM,UAAU,GAAmB,CAAC,OAAO,EAA8B,EAAE;IAChF,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChD,IAAI,SAAS,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YACrC,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;YACxC,SAAS;QACX,CAAC;QAED,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,SAAS;QACX,CAAC;QAED,IAAI,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,6BAA6B;gBACnC,QAAQ,EAAE,SAAS;gBACnB,KAAK,EAAE,SAAS,CAAC,IAAI;gBACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,sFAAsF;gBAChH,GAAG,EAAE,gDAAgD,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI;aACtF,CAAC,CACH,CAAC;YACF,SAAS;QACX,CAAC;QAED,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,QAAQ,KAAK,qEAAqE;YAC5G,GAAG,EAAE,kGAAkG;SACxG,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/presence.ts"],"names":[],"mappings":"AACA,OAAO,EAAiD,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAiDjG,eAAO,MAAM,YAAY,EAAE,cAoD1B,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { issue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Every declared parameter must be present, and a mandatory one must carry a value.
|
|
4
|
+
*
|
|
5
|
+
* "Keep all mandatory parameters in every request" and "No parameters may be
|
|
6
|
+
* added or removed from the request payload" — the guides are explicit that a
|
|
7
|
+
* field which is unused must still be transmitted, as an empty string.
|
|
8
|
+
*
|
|
9
|
+
* Presence alone is not enough to trust a payload. `normaliseParameters`
|
|
10
|
+
* collapses `null` and `undefined` to `''`, and every value rule defers an empty
|
|
11
|
+
* value back to this rule, so a payload whose mandatory fields are all blank
|
|
12
|
+
* would otherwise be reported as valid — losing the reject-before-send guard and
|
|
13
|
+
* telling the merchant an empty payload is correct.
|
|
14
|
+
*/
|
|
15
|
+
function missingIssue(context, parameter) {
|
|
16
|
+
return issue(context, {
|
|
17
|
+
code: 'presence.missing',
|
|
18
|
+
severity: 'error',
|
|
19
|
+
field: parameter.name,
|
|
20
|
+
message: `${parameter.name} is missing from the payload. ${context.flow.title} declares it as ${parameter.requirement}.`,
|
|
21
|
+
fix: parameter.requirement === 'must-be-empty'
|
|
22
|
+
? `Add "${parameter.name}": "" to the payload. Unused parameters must still be sent, as empty strings.`
|
|
23
|
+
: `Add "${parameter.name}" to the payload. ${parameter.notes}`,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function suppliedElsewhereIssue(context, parameter) {
|
|
27
|
+
return issue(context, {
|
|
28
|
+
code: 'presence.supplied-elsewhere',
|
|
29
|
+
severity: 'warning',
|
|
30
|
+
field: parameter.name,
|
|
31
|
+
message: `${parameter.name} is mandatory for ${context.flow.title} and is absent here, which is correct: the flow declares it as data that cannot cross the tool boundary. The payload is therefore incomplete as it stands, and the gateway will reject it until that field is added on the route that does carry it.`,
|
|
32
|
+
fix: `Add "${parameter.name}" in the integration code that runs on your own server — jazzcash_generate_integration_code emits it — or let the provider's hosted page or hosted fields send it straight from the customer's browser to the gateway. Never supply it through this server.`,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function emptyIssue(context, parameter) {
|
|
36
|
+
return issue(context, {
|
|
37
|
+
code: 'presence.empty',
|
|
38
|
+
severity: 'error',
|
|
39
|
+
field: parameter.name,
|
|
40
|
+
message: `${parameter.name} is present but empty, and ${context.flow.title} declares it as mandatory. An empty value is excluded from the secure hash, so the gateway receives neither the field nor its contribution to pp_SecureHash.`,
|
|
41
|
+
fix: `Supply a value for "${parameter.name}". ${parameter.notes}`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export const presenceRule = (context) => {
|
|
45
|
+
const issues = [];
|
|
46
|
+
for (const parameter of context.flow.parameters) {
|
|
47
|
+
// The secure hash is added after validation, so both its absence and its
|
|
48
|
+
// emptiness are expected when validating a payload that is not yet signed.
|
|
49
|
+
if (parameter.valueType === 'secure-hash') {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
// A parameter the flow forbids as a tool argument reaches the gateway by
|
|
53
|
+
// another route — a hosted field, or the merchant's own server — so its
|
|
54
|
+
// absence here is correct, and reporting it as an error would tell the
|
|
55
|
+
// merchant to paste a PAN into the conversation, which is what the flag
|
|
56
|
+
// exists to stop. Saying nothing at all is the other failure: a card payload
|
|
57
|
+
// with no PAN, no CVV and no expiry would be certified "valid, no issues
|
|
58
|
+
// found", which is a statement about a payload no gateway would accept. So
|
|
59
|
+
// the field is named — never its value, exactly as the tool-boundary
|
|
60
|
+
// refusal names one — as a warning, which leaves `valid` true and the
|
|
61
|
+
// builder working while recording that the payload is not yet complete.
|
|
62
|
+
if (parameter.neverAcceptAsToolArgument) {
|
|
63
|
+
// A value that did arrive is the `tool-argument.forbidden` rule's
|
|
64
|
+
// diagnosis, and repeating it here would report one mistake twice.
|
|
65
|
+
const supplied = context.parameters[parameter.name];
|
|
66
|
+
if (parameter.requirement === 'mandatory' && (supplied === undefined || supplied === '')) {
|
|
67
|
+
issues.push(suppliedElsewhereIssue(context, parameter));
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// Normalisation writes a string for every supplied key, so an undefined
|
|
72
|
+
// lookup means the key itself is absent rather than blank.
|
|
73
|
+
const value = context.parameters[parameter.name];
|
|
74
|
+
if (value === undefined) {
|
|
75
|
+
issues.push(missingIssue(context, parameter));
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (value !== '' || parameter.requirement !== 'mandatory') {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// An empty constant is the constants rule's diagnosis: it can name the value
|
|
82
|
+
// the flow fixes the field at, which is more use than "supply a value".
|
|
83
|
+
if (parameter.valueType === 'constant') {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
issues.push(emptyIssue(context, parameter));
|
|
87
|
+
}
|
|
88
|
+
return issues;
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=presence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presence.js","sourceRoot":"","sources":["../../../src/validation/rules/presence.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ValidationRule } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `pp_ReturnURL` is part of merchant authentication.
|
|
4
|
+
*
|
|
5
|
+
* "This field is mandatory and merchant must share this URL before using API as
|
|
6
|
+
* it will be a part of merchant profile. URL should always be the same in every
|
|
7
|
+
* request once shared. It is a part of merchant authentication; difference of
|
|
8
|
+
* URL will fail the validation."
|
|
9
|
+
*
|
|
10
|
+
* The failure this produces at the gateway is opaque, so a mismatch against the
|
|
11
|
+
* registered value is reported as an error whenever the registered value is known.
|
|
12
|
+
*/
|
|
13
|
+
export declare const returnUrlRule: ValidationRule;
|
|
14
|
+
//# sourceMappingURL=return-url.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"return-url.d.ts","sourceRoot":"","sources":["../../../src/validation/rules/return-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,EAAE,cAqD3B,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { issue } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `pp_ReturnURL` is part of merchant authentication.
|
|
4
|
+
*
|
|
5
|
+
* "This field is mandatory and merchant must share this URL before using API as
|
|
6
|
+
* it will be a part of merchant profile. URL should always be the same in every
|
|
7
|
+
* request once shared. It is a part of merchant authentication; difference of
|
|
8
|
+
* URL will fail the validation."
|
|
9
|
+
*
|
|
10
|
+
* The failure this produces at the gateway is opaque, so a mismatch against the
|
|
11
|
+
* registered value is reported as an error whenever the registered value is known.
|
|
12
|
+
*/
|
|
13
|
+
export const returnUrlRule = (context) => {
|
|
14
|
+
const parameter = context.flow.parameters.find((entry) => entry.valueType === 'url');
|
|
15
|
+
if (parameter === undefined) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
const value = context.parameters[parameter.name];
|
|
19
|
+
if (value === undefined || value === '') {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const issues = [];
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = new URL(value);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return [
|
|
29
|
+
issue(context, {
|
|
30
|
+
code: 'return-url.not-absolute',
|
|
31
|
+
severity: 'error',
|
|
32
|
+
field: parameter.name,
|
|
33
|
+
message: `${parameter.name} is "${value}", which is not an absolute URL.`,
|
|
34
|
+
fix: 'Supply the full absolute URL you registered with JazzCash, including the scheme, for example https://shop.example.pk/jazzcash/return.',
|
|
35
|
+
}),
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
if (parsed.protocol !== 'https:') {
|
|
39
|
+
issues.push(issue(context, {
|
|
40
|
+
code: 'return-url.not-https',
|
|
41
|
+
severity: 'warning',
|
|
42
|
+
field: parameter.name,
|
|
43
|
+
message: `${parameter.name} uses ${parsed.protocol.replace(':', '')}. The payment result is posted to this URL.`,
|
|
44
|
+
fix: 'Serve the return URL over HTTPS.',
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
if (context.registeredReturnUrl !== undefined && value !== context.registeredReturnUrl) {
|
|
48
|
+
issues.push(issue(context, {
|
|
49
|
+
code: 'return-url.does-not-match-registered',
|
|
50
|
+
severity: 'error',
|
|
51
|
+
field: parameter.name,
|
|
52
|
+
message: `${parameter.name} is "${value}" but the URL registered against this merchant profile is "${context.registeredReturnUrl}". The gateway treats any difference — including a trailing slash — as an authentication failure.`,
|
|
53
|
+
fix: `Send exactly "${context.registeredReturnUrl}", or update the registered URL under Integration > Credentials in the portal.`,
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
return issues;
|
|
57
|
+
};
|
|
58
|
+
//# sourceMappingURL=return-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"return-url.js","sourceRoot":"","sources":["../../../src/validation/rules/return-url.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA6C,MAAM,aAAa,CAAC;AAE/E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,aAAa,GAAmB,CAAC,OAAO,EAA8B,EAAE;IACnF,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC;IACrF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,IAAI,MAAuB,CAAC;IAE5B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;YACL,KAAK,CAAC,OAAO,EAAE;gBACb,IAAI,EAAE,yBAAyB;gBAC/B,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,SAAS,CAAC,IAAI;gBACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,QAAQ,KAAK,kCAAkC;gBACzE,GAAG,EAAE,uIAAuI;aAC7I,CAAC;SACH,CAAC;IACJ,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,sBAAsB;YAC5B,QAAQ,EAAE,SAAS;YACnB,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,SAAS,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,6CAA6C;YAChH,GAAG,EAAE,kCAAkC;SACxC,CAAC,CACH,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,mBAAmB,KAAK,SAAS,IAAI,KAAK,KAAK,OAAO,CAAC,mBAAmB,EAAE,CAAC;QACvF,MAAM,CAAC,IAAI,CACT,KAAK,CAAC,OAAO,EAAE;YACb,IAAI,EAAE,sCAAsC;YAC5C,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,SAAS,CAAC,IAAI;YACrB,OAAO,EAAE,GAAG,SAAS,CAAC,IAAI,QAAQ,KAAK,8DAA8D,OAAO,CAAC,mBAAmB,mGAAmG;YACnO,GAAG,EAAE,iBAAiB,OAAO,CAAC,mBAAmB,gFAAgF;SAClI,CAAC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ValidationRule } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A parameter the flow marks `neverAcceptAsToolArgument` must not appear at all.
|
|
4
|
+
*
|
|
5
|
+
* Card flows carry the PAN, the expiry and the CVV. `safeHandler` scrubs tool
|
|
6
|
+
* OUTPUTS, not inputs, so a value supplied here was written to the conversation
|
|
7
|
+
* transcript — and to whatever the harness persists of it — before any server
|
|
8
|
+
* code ran. By the time this rule fires the disclosure has already happened, so
|
|
9
|
+
* the issue says so plainly instead of offering a correction that would repeat
|
|
10
|
+
* it: the only safe next step is to route the value around this server and to
|
|
11
|
+
* treat the one already sent as compromised.
|
|
12
|
+
*
|
|
13
|
+
* The value is never echoed back, for the same reason.
|
|
14
|
+
*/
|
|
15
|
+
export declare const toolArgumentRule: ValidationRule;
|
|
16
|
+
//# sourceMappingURL=tool-argument.d.ts.map
|