@agent-cards/sdk 0.20.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/PREFLIGHT.md +34 -0
  3. package/README.md +1217 -15
  4. package/dist/aci.d.ts +173 -0
  5. package/dist/aci.generated.d.ts +87 -0
  6. package/dist/aci.generated.js +306 -0
  7. package/dist/aci.js +371 -0
  8. package/dist/adyen-merchant-hosted.generated.d.ts +3 -3
  9. package/dist/adyen-merchant-hosted.generated.js +283 -49
  10. package/dist/agentcard.d.ts +9 -2
  11. package/dist/agentcard.js +4 -2
  12. package/dist/amadeus-checkout.generated.d.ts +57 -0
  13. package/dist/amadeus-checkout.generated.js +549 -0
  14. package/dist/amadeus.d.ts +41 -0
  15. package/dist/amadeus.js +81 -0
  16. package/dist/builtin-registry.generated.js +1 -1
  17. package/dist/card-endpoint.d.ts +177 -0
  18. package/dist/card-endpoint.js +286 -0
  19. package/dist/card-fields.generated.d.ts +5 -3
  20. package/dist/card-fields.generated.js +284 -7
  21. package/dist/cdp.d.ts +6 -1
  22. package/dist/cdp.js +983 -147
  23. package/dist/client.d.ts +493 -13
  24. package/dist/client.js +1100 -82
  25. package/dist/creditguard.generated.d.ts +79 -0
  26. package/dist/creditguard.generated.js +662 -0
  27. package/dist/cse-body.js +11 -1
  28. package/dist/cybersource-flex.d.ts +183 -0
  29. package/dist/cybersource-flex.generated.d.ts +92 -0
  30. package/dist/cybersource-flex.generated.js +689 -0
  31. package/dist/cybersource-flex.js +275 -0
  32. package/dist/datatrans.d.ts +96 -0
  33. package/dist/datatrans.generated.d.ts +64 -0
  34. package/dist/datatrans.generated.js +426 -0
  35. package/dist/datatrans.js +178 -0
  36. package/dist/elavon-converge.d.ts +37 -0
  37. package/dist/elavon-converge.generated.d.ts +49 -0
  38. package/dist/elavon-converge.generated.js +439 -0
  39. package/dist/elavon-converge.js +84 -0
  40. package/dist/eprotect.d.ts +152 -0
  41. package/dist/eprotect.generated.d.ts +77 -0
  42. package/dist/eprotect.generated.js +498 -0
  43. package/dist/eprotect.js +222 -0
  44. package/dist/gmo.d.ts +63 -0
  45. package/dist/gmo.generated.d.ts +60 -0
  46. package/dist/gmo.generated.js +586 -0
  47. package/dist/gmo.js +119 -0
  48. package/dist/hosted-form.d.ts +3 -2
  49. package/dist/hosted-form.js +3 -2
  50. package/dist/index.d.ts +19 -3
  51. package/dist/index.js +6 -1
  52. package/dist/juspay-gate.d.ts +82 -0
  53. package/dist/juspay-gate.js +126 -0
  54. package/dist/juspay.generated.d.ts +89 -0
  55. package/dist/juspay.generated.js +705 -0
  56. package/dist/lifecycle.d.ts +62 -6
  57. package/dist/lifecycle.js +123 -8
  58. package/dist/merchant-card-endpoints.generated.d.ts +63 -0
  59. package/dist/merchant-card-endpoints.generated.js +1103 -0
  60. package/dist/merchant-hosted.d.ts +4 -1
  61. package/dist/merchant-hosted.js +5 -2
  62. package/dist/merchant-session-probe.d.ts +48 -0
  63. package/dist/merchant-session-probe.js +53 -0
  64. package/dist/merchant-session.generated.d.ts +69 -0
  65. package/dist/merchant-session.generated.js +919 -0
  66. package/dist/payrails.d.ts +133 -0
  67. package/dist/payrails.generated.d.ts +73 -0
  68. package/dist/payrails.generated.js +596 -0
  69. package/dist/payrails.js +305 -0
  70. package/dist/pelecard.d.ts +32 -0
  71. package/dist/pelecard.generated.d.ts +32 -0
  72. package/dist/pelecard.generated.js +283 -0
  73. package/dist/pelecard.js +42 -0
  74. package/dist/pre-claim.d.ts +84 -3
  75. package/dist/pre-claim.js +987 -9
  76. package/dist/preflight-catalog.json +2310 -263
  77. package/dist/preflight-schemas.json +187 -6
  78. package/dist/preflight.generated.d.ts +1 -1
  79. package/dist/preflight.generated.js +247 -4
  80. package/dist/preparation.d.ts +5 -2
  81. package/dist/preparation.js +36 -10
  82. package/dist/prepared-processor.d.ts +86 -5
  83. package/dist/prepared-processor.js +157 -6
  84. package/dist/primer.d.ts +53 -0
  85. package/dist/primer.generated.d.ts +38 -0
  86. package/dist/primer.generated.js +624 -0
  87. package/dist/primer.js +82 -0
  88. package/dist/registry.d.ts +114 -12
  89. package/dist/registry.js +85 -11
  90. package/dist/shiji-sts.d.ts +144 -0
  91. package/dist/shiji-sts.generated.d.ts +72 -0
  92. package/dist/shiji-sts.generated.js +913 -0
  93. package/dist/shiji-sts.js +222 -0
  94. package/dist/stripe-checkout.generated.d.ts +1 -1
  95. package/dist/stripe-checkout.generated.js +735 -10
  96. package/dist/stripe-setup.d.ts +16 -0
  97. package/dist/stripe-setup.js +61 -0
  98. package/dist/substitutions.generated.js +187 -29
  99. package/dist/verifone.d.ts +68 -0
  100. package/dist/verifone.generated.d.ts +51 -0
  101. package/dist/verifone.generated.js +1401 -0
  102. package/dist/verifone.js +119 -0
  103. package/dist/voice-types.d.ts +27 -0
  104. package/dist/voice.d.ts +6 -1
  105. package/dist/voice.js +6 -1
  106. package/dist/wspay.d.ts +41 -0
  107. package/dist/wspay.generated.d.ts +41 -0
  108. package/dist/wspay.generated.js +370 -0
  109. package/dist/wspay.js +65 -0
  110. package/examples/preflight/kernel-native/inventory.json +1 -1
  111. package/package.json +3 -3
@@ -0,0 +1,49 @@
1
+ declare var CONVERGE_HOSTS: readonly string[];
2
+ declare var CONVERGE_DEMO_HOST: string;
3
+ declare var CONVERGE_PROCESS_PATH: string;
4
+ declare var CONVERGE_PROCESS_URLS: readonly string[];
5
+ declare var CONVERGE_REFUSAL_CODES: readonly string[];
6
+ declare function parseConvergeBody(body: any): any;
7
+ declare function convergeAmountCents(value: any): number | null;
8
+ declare function convergeBodyVerdict(body: any): Readonly<{
9
+ verdict: "refuse";
10
+ code: any;
11
+ }> | Readonly<{
12
+ verdict: "continue";
13
+ }> | Readonly<{
14
+ verdict: "card";
15
+ }>;
16
+ declare function convergeBodyRefusal(body: any): any;
17
+ declare function isConvergeProcessUrl(url: any): boolean;
18
+ declare function convergeRequestRefusal(request: any): any;
19
+ declare function convergeRefusalMessage(code: any): any;
20
+ declare function injectConvergeHppCard(templateBody: any, card: any): {
21
+ body: string;
22
+ where: string[];
23
+ };
24
+ declare function convergeAnswerKind(text: any): "unknown" | "approved" | "declined" | "step" | "session_timeout";
25
+ declare function convergeFacts(text: any, template: any): {
26
+ kind: string;
27
+ final: boolean;
28
+ refusalCode: any;
29
+ txnId: string | null;
30
+ approvalCode: string | null;
31
+ amountCents: number | null;
32
+ tokenIssued: boolean;
33
+ chargedAboveRequest: boolean;
34
+ };
35
+ declare function convergeResponseOutcome(status: any, text: any): {
36
+ outcome: string;
37
+ reason: string;
38
+ code?: undefined;
39
+ } | {
40
+ outcome: string;
41
+ reason?: undefined;
42
+ code?: undefined;
43
+ } | {
44
+ outcome: string;
45
+ code: any;
46
+ reason?: undefined;
47
+ };
48
+ declare function sanitizeConvergeResponse(text: any): string;
49
+ export { CONVERGE_DEMO_HOST, CONVERGE_HOSTS, CONVERGE_PROCESS_PATH, CONVERGE_PROCESS_URLS, CONVERGE_REFUSAL_CODES, convergeAmountCents, convergeAnswerKind, convergeBodyRefusal, convergeBodyVerdict, convergeFacts, convergeRefusalMessage, convergeRequestRefusal, convergeResponseOutcome, injectConvergeHppCard, isConvergeProcessUrl, parseConvergeBody, sanitizeConvergeResponse };
@@ -0,0 +1,439 @@
1
+ // @ts-nocheck
2
+ // Generated from @agent-cards/payment-core. Do not edit.
3
+ // artifact-sha256: dc4269c2533c43ddcc4f7be0f3a4645beea09bce6854c98e38701f29cf037e2b
4
+ // src/elavon-converge.js
5
+ var CONVERGE_HOSTS = /* @__PURE__ */ Object.freeze(["api.convergepay.com", "api.demo.convergepay.com"]);
6
+ var CONVERGE_DEMO_HOST = "api.demo.convergepay.com";
7
+ var CONVERGE_PROCESS_PATH = "/hosted-payments/service/payment/hpp/process";
8
+ var CONVERGE_PROCESS_URLS = /* @__PURE__ */ Object.freeze([
9
+ "https://api.convergepay.com/hosted-payments/service/payment/hpp/process",
10
+ "https://api.demo.convergepay.com/hosted-payments/service/payment/hpp/process"
11
+ ]);
12
+ var CONVERGE_REFUSAL_CODES = /* @__PURE__ */ Object.freeze([
13
+ "converge_body_malformed",
14
+ "converge_payment_type_refused",
15
+ "converge_debit_card_refused",
16
+ "converge_push_to_card_refused",
17
+ "converge_gift_card_refused",
18
+ "converge_credential_refused",
19
+ "converge_wallet_refused",
20
+ "converge_captcha_refused",
21
+ "converge_service_fee_refused",
22
+ "converge_3ds_follow_up_refused",
23
+ "converge_surcharge_refused",
24
+ "converge_amount_add_on_refused",
25
+ "converge_card_saving_refused",
26
+ "converge_recurring_refused",
27
+ "converge_currency_refused",
28
+ "converge_amount_missing",
29
+ "converge_context_missing",
30
+ "converge_card_missing",
31
+ "converge_card_malformed",
32
+ "converge_url_refused",
33
+ "converge_method_refused",
34
+ "converge_content_type_refused"
35
+ ]);
36
+ var TOP_LEVEL_KEYS = /* @__PURE__ */ Object.freeze(["paymentType", "paymentData", "context", "captchaToken", "shippingSameAsBilling"]);
37
+ var WALLET_FIELDS = /* @__PURE__ */ Object.freeze([
38
+ "ssl_ewallet",
39
+ "googlepay_authmethod",
40
+ "ssl_google_pay",
41
+ "ssl_applepay_web",
42
+ "ssl_dsrp_cryptogram",
43
+ "ssl_visapayload",
44
+ "ssl_ewallet_shipping"
45
+ ]);
46
+ var SERVICE_FEE_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_service_fee_agree", "ssl_service_fee_amount", "ssl_service_fee_percent"]);
47
+ var THREE_DS_FIELDS = /* @__PURE__ */ Object.freeze([
48
+ "ssl_transaction_type",
49
+ "ssl_eci_ind",
50
+ "ssl_3dsecure_value",
51
+ "ssl_dir_server_tran_id",
52
+ "ssl_xid",
53
+ "ssl_program_protocol"
54
+ ]);
55
+ var THREE_DS_PREFIXES = /* @__PURE__ */ Object.freeze(["ssl_3ds_", "ssl_fsg_"]);
56
+ var SURCHARGE_FIELDS = /* @__PURE__ */ Object.freeze([
57
+ "ssl_credit_surcharge_agree",
58
+ "ssl_credit_surcharge_amount",
59
+ "bypass_credit_surcharge",
60
+ "ssl_amount_subtotal",
61
+ "ssl_total_amount",
62
+ "ssl_surcharge_fee_total"
63
+ ]);
64
+ var RECURRING_FIELDS = /* @__PURE__ */ Object.freeze([
65
+ "recurring",
66
+ "installment",
67
+ "ssl_billing_cycle",
68
+ "ssl_next_payment_date",
69
+ "ssl_total_installments",
70
+ "ssl_skip_payment",
71
+ "ssl_recurring_id",
72
+ "ssl_recurring_batch_count",
73
+ "ssl_installment_id"
74
+ ]);
75
+ var CARD_SAVING_FLAGS = /* @__PURE__ */ Object.freeze(["ssl_get_token", "ssl_add_token"]);
76
+ var CREDENTIAL_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_account_id", "ssl_merchant_id", "ssl_user_id", "ssl_pin", "ssl_vendor_id"]);
77
+ var AMOUNT_ADD_ON_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_tip_amount", "ssl_cashback_amount"]);
78
+ var CARD_NUMBER = /^\d{12,19}$/;
79
+ var EXPIRY_MMYY = /^(0[1-9]|1[0-2])\d{2}$/;
80
+ var CVC = /^\d{3,4}$/;
81
+ var AMOUNT = /^(\d{1,13})(?:\.(\d{1,2}))?$/;
82
+ var isRecord = (value) => !!value && typeof value === "object" && !Array.isArray(value);
83
+ var owns = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
84
+ var refuse = (code) => Object.freeze({ verdict: "refuse", code });
85
+ var CARD = /* @__PURE__ */ Object.freeze({ verdict: "card" });
86
+ var CONTINUE = /* @__PURE__ */ Object.freeze({ verdict: "continue" });
87
+ function parseConvergeBody(body) {
88
+ if (typeof body !== "string" || body === "" || body.length > 131072)
89
+ return null;
90
+ let parsed;
91
+ try {
92
+ parsed = JSON.parse(body);
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ if (!isRecord(parsed) || JSON.stringify(parsed) !== body)
98
+ return null;
99
+ return parsed;
100
+ }
101
+ function convergeAmountCents(value) {
102
+ const text = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
103
+ const m = typeof text === "string" ? AMOUNT.exec(text) : null;
104
+ if (!m)
105
+ return null;
106
+ const cents = Number(m[1]) * 100 + Number(((m[2] ?? "") + "00").slice(0, 2));
107
+ return Number.isSafeInteger(cents) && cents > 0 ? cents : null;
108
+ }
109
+ function convergeBodyVerdict(body) {
110
+ const parsed = parseConvergeBody(body);
111
+ if (parsed === null || !Object.keys(parsed).every((key) => TOP_LEVEL_KEYS.includes(key)))
112
+ return refuse("converge_body_malformed");
113
+ const data = parsed.paymentData;
114
+ if (!isRecord(data))
115
+ return refuse("converge_body_malformed");
116
+ const type = parsed.paymentType;
117
+ if (type === "ELECTRONICCHECK" || type === "FINANCING") {
118
+ return owns(data, "ssl_card_number") ? refuse("converge_payment_type_refused") : CONTINUE;
119
+ }
120
+ if (type === "DEBITCARD") {
121
+ return refuse(typeof data.ssl_transaction_type === "string" && /DISBURSEMENT/i.test(data.ssl_transaction_type) ? "converge_push_to_card_refused" : "converge_debit_card_refused");
122
+ }
123
+ if (type === "GIFTCARD")
124
+ return refuse("converge_gift_card_refused");
125
+ if (type !== "CREDITCARD")
126
+ return refuse("converge_payment_type_refused");
127
+ const keys = Object.keys(data);
128
+ if (CREDENTIAL_FIELDS.some((key) => owns(data, key)))
129
+ return refuse("converge_credential_refused");
130
+ if (WALLET_FIELDS.some((key) => owns(data, key)))
131
+ return refuse("converge_wallet_refused");
132
+ if (owns(parsed, "captchaToken"))
133
+ return refuse("converge_captcha_refused");
134
+ if (SERVICE_FEE_FIELDS.some((key) => owns(data, key)))
135
+ return refuse("converge_service_fee_refused");
136
+ if (THREE_DS_FIELDS.some((key) => owns(data, key)) || keys.some((key) => THREE_DS_PREFIXES.some((prefix) => key.startsWith(prefix))))
137
+ return refuse("converge_3ds_follow_up_refused");
138
+ if (SURCHARGE_FIELDS.some((key) => owns(data, key)))
139
+ return refuse("converge_surcharge_refused");
140
+ if (AMOUNT_ADD_ON_FIELDS.some((key) => owns(data, key)))
141
+ return refuse("converge_amount_add_on_refused");
142
+ if (owns(data, "ssl_token") || CARD_SAVING_FLAGS.some((key) => owns(data, key) && !(typeof data[key] === "string" && /^n$/i.test(data[key])))) {
143
+ return refuse("converge_card_saving_refused");
144
+ }
145
+ if (RECURRING_FIELDS.some((key) => owns(data, key)))
146
+ return refuse("converge_recurring_refused");
147
+ if (owns(data, "ssl_transaction_currency") && !(typeof data.ssl_transaction_currency === "string" && /^usd$/i.test(data.ssl_transaction_currency))) {
148
+ return refuse("converge_currency_refused");
149
+ }
150
+ if (convergeAmountCents(data.ssl_amount) === null)
151
+ return refuse("converge_amount_missing");
152
+ if (typeof parsed.context !== "string" || parsed.context === "")
153
+ return refuse("converge_context_missing");
154
+ if (owns(parsed, "shippingSameAsBilling") && typeof parsed.shippingSameAsBilling !== "boolean")
155
+ return refuse("converge_body_malformed");
156
+ if (!owns(data, "ssl_card_number") || data.ssl_card_number === "" || data.ssl_card_number === null)
157
+ return refuse("converge_card_missing");
158
+ if (typeof data.ssl_card_number !== "string" || !CARD_NUMBER.test(data.ssl_card_number) || typeof data.ssl_exp_date !== "string" || !EXPIRY_MMYY.test(data.ssl_exp_date) || typeof data.ssl_cvv2cvc2 !== "string" || !CVC.test(data.ssl_cvv2cvc2))
159
+ return refuse("converge_card_malformed");
160
+ return CARD;
161
+ }
162
+ function convergeBodyRefusal(body) {
163
+ const verdict = convergeBodyVerdict(body);
164
+ return verdict.verdict === "refuse" ? verdict.code : null;
165
+ }
166
+ function isConvergeProcessUrl(url) {
167
+ if (typeof url !== "string")
168
+ return false;
169
+ let parsed;
170
+ try {
171
+ parsed = new URL(url);
172
+ }
173
+ catch {
174
+ return false;
175
+ }
176
+ return parsed.href === url && CONVERGE_PROCESS_URLS.includes(parsed.href);
177
+ }
178
+ function convergeRequestRefusal(request) {
179
+ if (!isRecord(request))
180
+ return "converge_body_malformed";
181
+ if (request.method !== "POST")
182
+ return "converge_method_refused";
183
+ if (!isConvergeProcessUrl(request.url))
184
+ return "converge_url_refused";
185
+ const headers = request.headers === void 0 ? {} : request.headers;
186
+ if (!isRecord(headers))
187
+ return "converge_content_type_refused";
188
+ for (const [name, value] of Object.entries(headers)) {
189
+ if (/^content-type$/i.test(name) && !(typeof value === "string" && /^application\/json\s*(?:;\s*charset=utf-8\s*)?$/i.test(value)))
190
+ return "converge_content_type_refused";
191
+ }
192
+ const verdict = convergeBodyVerdict(request.body);
193
+ if (verdict.verdict === "refuse")
194
+ return verdict.code;
195
+ return verdict.verdict === "card" ? null : "converge_payment_type_refused";
196
+ }
197
+ var EXTRA_STEP = "Refusing to pay: this payment needs an extra step the Vault can't complete here. Nothing was sent.";
198
+ var NOT_THE_PAGE = "Refusing to pay: this is not the card request of Elavon Converge's payment page. Nothing was sent.";
199
+ var REFUSAL_MESSAGES = /* @__PURE__ */ Object.freeze({
200
+ converge_body_malformed: NOT_THE_PAGE,
201
+ converge_payment_type_refused: "Refusing to pay: only a credit card sale on Elavon Converge's payment page is supported. Nothing was sent.",
202
+ converge_debit_card_refused: "Refusing to pay: a debit card payment on Elavon Converge's payment page is not supported. Nothing was sent.",
203
+ converge_push_to_card_refused: "Refusing to pay: this payment would send money to the card, which the Vault never does. Nothing was sent.",
204
+ converge_gift_card_refused: "Refusing to pay: a gift card payment on Elavon Converge's payment page is not supported. Nothing was sent.",
205
+ converge_credential_refused: NOT_THE_PAGE,
206
+ converge_wallet_refused: "Refusing to pay: this payment uses a wallet, not the card you approve here. Nothing was sent.",
207
+ converge_captcha_refused: "Refusing to pay: this payment page asks for a CAPTCHA, which the Vault can't complete. Nothing was sent.",
208
+ converge_service_fee_refused: "Refusing to pay: this merchant adds a separate service fee, which a one-time card can't pay. Nothing was sent.",
209
+ converge_3ds_follow_up_refused: EXTRA_STEP,
210
+ converge_surcharge_refused: EXTRA_STEP,
211
+ converge_amount_add_on_refused: "Refusing to pay: this payment adds a tip or cash back to its amount. Nothing was sent.",
212
+ converge_card_saving_refused: "Refusing to pay: this payment would save the card with the merchant. Nothing was sent.",
213
+ converge_recurring_refused: "Refusing to pay: this payment would set up recurring or installment charges. Nothing was sent.",
214
+ converge_currency_refused: "Refusing to pay: this payment is not in US dollars. Nothing was sent.",
215
+ converge_amount_missing: "Refusing to pay: this payment names no amount. Nothing was sent.",
216
+ converge_context_missing: "Refusing to pay: this payment carries no payment page session. Nothing was sent.",
217
+ converge_card_missing: NOT_THE_PAGE,
218
+ converge_card_malformed: NOT_THE_PAGE,
219
+ converge_url_refused: NOT_THE_PAGE,
220
+ converge_method_refused: NOT_THE_PAGE,
221
+ converge_content_type_refused: NOT_THE_PAGE
222
+ });
223
+ function convergeRefusalMessage(code) {
224
+ return typeof code === "string" && owns(REFUSAL_MESSAGES, code) ? REFUSAL_MESSAGES[code] : NOT_THE_PAGE;
225
+ }
226
+ var CONVERGE_CARD_PATHS = /* @__PURE__ */ Object.freeze(["paymentData.ssl_card_number", "paymentData.ssl_exp_date", "paymentData.ssl_cvv2cvc2"]);
227
+ function injectConvergeHppCard(templateBody, card) {
228
+ const verdict = convergeBodyVerdict(templateBody);
229
+ if (verdict.verdict !== "card") {
230
+ throw new Error(convergeRefusalMessage(verdict.verdict === "refuse" ? verdict.code : "converge_payment_type_refused"));
231
+ }
232
+ const number = card ? String(card.number) : "";
233
+ const month = card ? String(card.month).padStart(2, "0") : "";
234
+ const year = card ? String(card.year) : "";
235
+ const cvc = card ? String(card.cvc) : "";
236
+ if (!CARD_NUMBER.test(number) || !/^(0[1-9]|1[0-2])$/.test(month) || !/^(?:\d{2}|\d{4})$/.test(year) || !CVC.test(cvc)) {
237
+ throw new Error("Could not fill the card fields for Elavon Converge. Nothing was sent.");
238
+ }
239
+ const parsed = JSON.parse(templateBody);
240
+ parsed.paymentData.ssl_card_number = number;
241
+ parsed.paymentData.ssl_exp_date = month + year.slice(-2);
242
+ parsed.paymentData.ssl_cvv2cvc2 = cvc;
243
+ return { body: JSON.stringify(parsed), where: [...CONVERGE_CARD_PATHS] };
244
+ }
245
+ var IDENTIFIER = /^[a-z0-9_.:-]{1,64}$/i;
246
+ var identifier = (value) => typeof value === "string" && IDENTIFIER.exec(value)?.[0] === value ? value : null;
247
+ function parseAnswer(text) {
248
+ if (typeof text !== "string" || text === "")
249
+ return null;
250
+ try {
251
+ const parsed = JSON.parse(text);
252
+ return isRecord(parsed) ? parsed : null;
253
+ }
254
+ catch {
255
+ return null;
256
+ }
257
+ }
258
+ var SURCHARGE_QUOTE_FIELDS = /* @__PURE__ */ Object.freeze(["ssl_credit_surcharge_amount", "ssl_total_amount"]);
259
+ function convergeAnswerKind(text) {
260
+ const answer = parseAnswer(text);
261
+ if (answer === null)
262
+ return "unknown";
263
+ const fields = isRecord(answer.responseFields) ? answer.responseFields : null;
264
+ const step = !!(answer.efsToken || answer.threeDSecure || answer.dcc || fields && (fields.surchargeAllowed === "Y" || fields.ssl_result_message === "INVLD SURCHARGE") || fields && answer.approved === false && SURCHARGE_QUOTE_FIELDS.some((key) => owns(fields, key) && fields[key] !== null && fields[key] !== ""));
265
+ const sessionTimeout = isRecord(answer.errorModel) && answer.errorModel.errorType === "SESSION_TIMEOUT";
266
+ if ((step || sessionTimeout) && answer.approved === true)
267
+ return "unknown";
268
+ if (step)
269
+ return "step";
270
+ if (sessionTimeout)
271
+ return "session_timeout";
272
+ if (answer.approved === true) {
273
+ if (!fields || identifier(fields.ssl_txn_id) === null)
274
+ return "unknown";
275
+ if (owns(fields, "ssl_result") && String(fields.ssl_result) !== "0")
276
+ return "unknown";
277
+ return "approved";
278
+ }
279
+ if (answer.approved === false && fields && !(owns(fields, "ssl_result") && String(fields.ssl_result) === "0"))
280
+ return "declined";
281
+ return "unknown";
282
+ }
283
+ var KIND_REFUSAL = /* @__PURE__ */ Object.freeze({
284
+ declined: "converge_declined",
285
+ session_timeout: "converge_session_timeout",
286
+ step: "converge_step_unsupported"
287
+ });
288
+ function convergeFacts(text, template) {
289
+ const kind = convergeAnswerKind(text);
290
+ const answer = parseAnswer(text);
291
+ const fields = answer && isRecord(answer.responseFields) ? answer.responseFields : {};
292
+ const amountCents = kind === "approved" ? convergeAmountCents(fields.ssl_amount) : null;
293
+ const requested = template && typeof template.body === "string" ? parseConvergeBody(template.body) : null;
294
+ const requestAmountCents = requested && isRecord(requested.paymentData) ? convergeAmountCents(requested.paymentData.ssl_amount) : null;
295
+ return {
296
+ kind,
297
+ final: kind === "approved" || kind === "declined" || kind === "session_timeout",
298
+ refusalCode: KIND_REFUSAL[kind] ?? null,
299
+ txnId: kind === "approved" ? identifier(fields.ssl_txn_id) : null,
300
+ approvalCode: kind === "approved" ? identifier(fields.ssl_approval_code) : null,
301
+ amountCents,
302
+ tokenIssued: kind === "approved" && typeof fields.ssl_token === "string" && fields.ssl_token !== "",
303
+ chargedAboveRequest: amountCents !== null && requestAmountCents !== null && amountCents > requestAmountCents
304
+ };
305
+ }
306
+ function convergeResponseOutcome(status, text) {
307
+ if (!(status >= 200 && status < 300))
308
+ return { outcome: "unknown", reason: "converge_unconfirmed" };
309
+ const kind = convergeAnswerKind(text);
310
+ if (kind === "approved")
311
+ return { outcome: "approved" };
312
+ if (KIND_REFUSAL[kind])
313
+ return { outcome: "refused", code: KIND_REFUSAL[kind] };
314
+ return { outcome: "unknown", reason: "converge_unconfirmed" };
315
+ }
316
+ var RESPONSE_FIELDS = /* @__PURE__ */ Object.freeze([
317
+ "ssl_result",
318
+ "ssl_result_message",
319
+ "ssl_txn_id",
320
+ "ssl_approval_code",
321
+ "ssl_amount",
322
+ "ssl_txn_time",
323
+ "ssl_invoice_number",
324
+ "ssl_description",
325
+ "ssl_card_short_description",
326
+ "ssl_card_type",
327
+ "ssl_card_number",
328
+ "ssl_cvv2_response",
329
+ "ssl_avs_response",
330
+ "ssl_transaction_type",
331
+ "ssl_merchant_txn_id",
332
+ "ssl_reference_number",
333
+ "ssl_transaction_reference_number",
334
+ "ssl_salestax",
335
+ "ssl_customer_code"
336
+ ]);
337
+ var MASKED_CARD = /^(?=.{12,19}$)\d{0,6}[*Xx#]+\d{0,4}$/;
338
+ var FIELD_NAME = /^[A-Za-z0-9_.-]{1,64}$/;
339
+ function luhn(digits) {
340
+ let sum = 0;
341
+ for (let i = 0; i < digits.length; i += 1) {
342
+ let d = Number(digits[digits.length - 1 - i]);
343
+ if (i % 2 === 1) {
344
+ d *= 2;
345
+ if (d > 9)
346
+ d -= 9;
347
+ }
348
+ sum += d;
349
+ }
350
+ return sum % 10 === 0;
351
+ }
352
+ var SEPARATORS = /[\s.\u00b7\u2010-\u2015\u2212-]+/g;
353
+ var DIGIT_GROUPS = /\d+(?:[\s.\u00b7\u2010-\u2015\u2212-]+\d+)*/g;
354
+ function holdsCardNumber(text) {
355
+ const whole = text.replace(SEPARATORS, "");
356
+ if (/^\d{12,19}$/.test(whole) && luhn(whole))
357
+ return true;
358
+ for (const run of text.match(DIGIT_GROUPS) ?? []) {
359
+ const groups = run.split(SEPARATORS);
360
+ for (let start = 0; start < groups.length; start += 1) {
361
+ if (groups[start][0] === "0")
362
+ continue;
363
+ let digits = "";
364
+ for (let end = start; end < groups.length && digits.length + groups[end].length <= 19; end += 1) {
365
+ digits += groups[end];
366
+ if (digits.length >= 12 && luhn(digits))
367
+ return true;
368
+ }
369
+ }
370
+ }
371
+ return false;
372
+ }
373
+ function safeScalar(value) {
374
+ if (typeof value === "boolean")
375
+ return true;
376
+ if (typeof value === "number" && !Number.isFinite(value))
377
+ return false;
378
+ if (typeof value !== "number" && (typeof value !== "string" || value.length > 1024 || /[\u0000-\u001f\u007f]/.test(value)))
379
+ return false;
380
+ return !holdsCardNumber(String(value));
381
+ }
382
+ function keepReturnField(name, value) {
383
+ if (typeof name !== "string" || !FIELD_NAME.test(name))
384
+ return false;
385
+ const lower = name.toLowerCase();
386
+ if (lower.startsWith("ssl_") && !RESPONSE_FIELDS.includes(lower))
387
+ return false;
388
+ if (lower === "ssl_card_number")
389
+ return typeof value === "string" && MASKED_CARD.test(value);
390
+ return safeScalar(value);
391
+ }
392
+ function sanitizeReturnList(list) {
393
+ if (Array.isArray(list)) {
394
+ return list.filter((entry) => isRecord(entry) && keepReturnField(entry.name, entry.value)).slice(0, 128).map((entry) => ({ name: entry.name, value: entry.value }));
395
+ }
396
+ if (isRecord(list)) {
397
+ const out = {};
398
+ for (const [name, value] of Object.entries(list).slice(0, 128))
399
+ if (keepReturnField(name, value))
400
+ out[name] = value;
401
+ return out;
402
+ }
403
+ return void 0;
404
+ }
405
+ function sanitizeConvergeResponse(text) {
406
+ if (convergeAnswerKind(text) !== "approved")
407
+ throw new Error("Refusing to store an Elavon Converge answer that is not an approval.");
408
+ const answer = parseAnswer(text);
409
+ const out = { approved: true };
410
+ for (const key of ["amount", "currency", "paymentType", "transactionType"]) {
411
+ if (owns(answer, key) && (typeof answer[key] === "string" || typeof answer[key] === "number") && safeScalar(answer[key]) && String(answer[key]).length <= 64)
412
+ out[key] = answer[key];
413
+ }
414
+ for (const key of ["debitAsCredit", "dcc", "threeDSecure"])
415
+ if (answer[key] === false)
416
+ out[key] = false;
417
+ const fields = {};
418
+ for (const name of RESPONSE_FIELDS) {
419
+ if (!owns(answer.responseFields, name))
420
+ continue;
421
+ const value = answer.responseFields[name];
422
+ if (name === "ssl_card_number" ? typeof value === "string" && MASKED_CARD.test(value) : safeScalar(value))
423
+ fields[name] = value;
424
+ }
425
+ out.responseFields = fields;
426
+ if (isRecord(answer.paymentReturnFields)) {
427
+ const returns = {};
428
+ for (const key of ["approveFields", "declineFields"]) {
429
+ const kept = sanitizeReturnList(answer.paymentReturnFields[key]);
430
+ if (kept !== void 0)
431
+ returns[key] = kept;
432
+ }
433
+ out.paymentReturnFields = returns;
434
+ }
435
+ if (typeof answer.context === "string" && answer.context.length <= 65536)
436
+ out.context = answer.context;
437
+ return JSON.stringify(out);
438
+ }
439
+ export { CONVERGE_DEMO_HOST, CONVERGE_HOSTS, CONVERGE_PROCESS_PATH, CONVERGE_PROCESS_URLS, CONVERGE_REFUSAL_CODES, convergeAmountCents, convergeAnswerKind, convergeBodyRefusal, convergeBodyVerdict, convergeFacts, convergeRefusalMessage, convergeRequestRefusal, convergeResponseOutcome, injectConvergeHppCard, isConvergeProcessUrl, parseConvergeBody, sanitizeConvergeResponse };
@@ -0,0 +1,84 @@
1
+ // Elavon Converge Hosted Payment Page (psp `elavon_converge`): the page NY DMV's payment apps
2
+ // redirect to, api.convergepay.com/hosted-payments/?ssl_txn_auth_token=<one-time token> (the
3
+ // demo environment serves the same page on api.demo.convergepay.com). Converge's own AngularJS
4
+ // app posts the card in one same-origin JSON XHR, POST /hosted-payments/service/payment/hpp/process,
5
+ // with the card at paymentData.ssl_card_number, ssl_exp_date (MMYY) and ssl_cvv2cvc2, the amount
6
+ // at paymentData.ssl_amount, and the page's rolling session in `context`. The same URL also takes
7
+ // electronic check and financing payments with no card, wallet payments with a card number the
8
+ // server supplied, the debit, gift card and push-to-card tabs, and the follow-ups after a 3-D
9
+ // Secure, Pay Defense or surcharge step. This module holds what the SDK decides about that request.
10
+ // The rules themselves are payment-core's (elavon-converge.generated.ts): the API applies the same
11
+ // ones at create, and the cardholder's device applies them again before it writes a card.
12
+ //
13
+ // The processor ships dark. The API serves the elavon_converge recognizer only to a build that
14
+ // declares the `converge_hpp_process` capability (client.ts SUPPORTED_CAPABILITIES), and only for
15
+ // an org Agentcard enabled for Converge, so an SDK that has not synced, or that runs for any other
16
+ // org, never recognizes a Converge host and leaves its requests alone.
17
+ import { CONVERGE_HOSTS, convergeRequestRefusal } from './elavon-converge.generated.js';
18
+ export const CONVERGE_PSP = 'elavon_converge';
19
+ /** The dark-launch capability the API serves the elavon_converge recognizer behind. */
20
+ export const CONVERGE_CAPABILITY = 'converge_hpp_process';
21
+ /**
22
+ * Why the SDK refuses an Elavon Converge payment before anything is claimed, created or prompted:
23
+ * payment-core's own codes (CONVERGE_REFUSAL_CODES), the ones the API answers a create with and
24
+ * the device refuses with, so an integrator reads one code whichever of them refused.
25
+ * - A shape the Vault never pays: `converge_wallet_refused`, `converge_debit_card_refused`,
26
+ * `converge_push_to_card_refused`, `converge_gift_card_refused`, `converge_payment_type_refused`,
27
+ * `converge_captcha_refused`, `converge_service_fee_refused`, `converge_recurring_refused`,
28
+ * `converge_card_saving_refused` (ssl_get_token or ssl_add_token), `converge_amount_add_on_refused`
29
+ * (a tip or cash back) and `converge_currency_refused` (anything but US dollars).
30
+ * - A follow-up after a step the Vault cannot complete: `converge_3ds_follow_up_refused` (3-D
31
+ * Secure or Pay Defense) and `converge_surcharge_refused`.
32
+ * - A body the cardholder has nothing to approve on: `converge_amount_missing` and
33
+ * `converge_context_missing`.
34
+ * - Not the page's own card request, which the device could never fill: `converge_body_malformed`,
35
+ * `converge_credential_refused`, `converge_card_missing`, `converge_card_malformed`,
36
+ * `converge_url_refused`, `converge_method_refused` and `converge_content_type_refused`.
37
+ */
38
+ export const CONVERGE_REFUSAL_REASONS = [
39
+ 'converge_body_malformed',
40
+ 'converge_payment_type_refused',
41
+ 'converge_debit_card_refused',
42
+ 'converge_push_to_card_refused',
43
+ 'converge_gift_card_refused',
44
+ 'converge_credential_refused',
45
+ 'converge_wallet_refused',
46
+ 'converge_captcha_refused',
47
+ 'converge_service_fee_refused',
48
+ 'converge_3ds_follow_up_refused',
49
+ 'converge_surcharge_refused',
50
+ 'converge_amount_add_on_refused',
51
+ 'converge_card_saving_refused',
52
+ 'converge_recurring_refused',
53
+ 'converge_currency_refused',
54
+ 'converge_amount_missing',
55
+ 'converge_context_missing',
56
+ 'converge_card_missing',
57
+ 'converge_card_malformed',
58
+ 'converge_url_refused',
59
+ 'converge_method_refused',
60
+ 'converge_content_type_refused',
61
+ ];
62
+ /** True when the URL's host is one of Converge's two payment page hosts. */
63
+ export function isConvergeHost(url) {
64
+ try {
65
+ return CONVERGE_HOSTS.includes(new URL(url).hostname);
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ /**
72
+ * The pause decision for a card-carrying POST the registry recognized on a Converge host. Null
73
+ * when it is the page's own first credit card sale, which pauses for approval; otherwise the reason
74
+ * it is refused. It judges the whole request (the exact process URL, the page's JSON content type,
75
+ * and a body exactly as the page serializes it) with payment-core's convergeRequestRefusal, the
76
+ * check the API runs at create and the device runs before it writes a card. A code this build does
77
+ * not list reads as not the page's request, so a newer core can only refuse more.
78
+ */
79
+ export function convergeRefusal(request) {
80
+ const code = convergeRequestRefusal({ url: request.url, method: 'POST', headers: request.headers ?? {}, body: request.body ?? '' });
81
+ if (code === null)
82
+ return null;
83
+ return CONVERGE_REFUSAL_REASONS.includes(code) ? code : 'converge_body_malformed';
84
+ }