@agent-cards/sdk 0.21.0 → 0.23.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 (113) hide show
  1. package/CHANGELOG.md +87 -2
  2. package/PREFLIGHT.md +32 -0
  3. package/README.md +1177 -23
  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 +302 -56
  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-facts.d.ts +96 -0
  18. package/dist/card-endpoint-facts.js +275 -0
  19. package/dist/card-endpoint-page.d.ts +54 -0
  20. package/dist/card-endpoint-page.js +69 -0
  21. package/dist/card-endpoint.d.ts +298 -0
  22. package/dist/card-endpoint.js +438 -0
  23. package/dist/card-fields.generated.d.ts +5 -3
  24. package/dist/card-fields.generated.js +284 -7
  25. package/dist/cdp.d.ts +5 -1
  26. package/dist/cdp.js +1155 -141
  27. package/dist/client.d.ts +456 -20
  28. package/dist/client.js +1072 -104
  29. package/dist/creditguard.generated.d.ts +79 -0
  30. package/dist/creditguard.generated.js +662 -0
  31. package/dist/cse-body.js +11 -1
  32. package/dist/cybersource-flex.d.ts +30 -0
  33. package/dist/cybersource-flex.generated.d.ts +27 -1
  34. package/dist/cybersource-flex.generated.js +42 -2
  35. package/dist/cybersource-flex.js +46 -0
  36. package/dist/datatrans.d.ts +96 -0
  37. package/dist/datatrans.generated.d.ts +64 -0
  38. package/dist/datatrans.generated.js +426 -0
  39. package/dist/datatrans.js +178 -0
  40. package/dist/ekashu.d.ts +35 -0
  41. package/dist/ekashu.js +55 -0
  42. package/dist/elavon-converge.d.ts +37 -0
  43. package/dist/elavon-converge.generated.d.ts +49 -0
  44. package/dist/elavon-converge.generated.js +439 -0
  45. package/dist/elavon-converge.js +84 -0
  46. package/dist/eprotect.d.ts +152 -0
  47. package/dist/eprotect.generated.d.ts +77 -0
  48. package/dist/eprotect.generated.js +498 -0
  49. package/dist/eprotect.js +222 -0
  50. package/dist/hosted-form.d.ts +3 -2
  51. package/dist/hosted-form.js +3 -2
  52. package/dist/index.d.ts +17 -3
  53. package/dist/index.js +6 -1
  54. package/dist/juspay-gate.d.ts +82 -0
  55. package/dist/juspay-gate.js +126 -0
  56. package/dist/juspay.generated.d.ts +89 -0
  57. package/dist/juspay.generated.js +705 -0
  58. package/dist/lifecycle.d.ts +60 -6
  59. package/dist/lifecycle.js +122 -8
  60. package/dist/merchant-card-endpoints.generated.d.ts +122 -0
  61. package/dist/merchant-card-endpoints.generated.js +4261 -0
  62. package/dist/merchant-hosted.d.ts +4 -1
  63. package/dist/merchant-hosted.js +5 -2
  64. package/dist/merchant-session-probe.d.ts +48 -0
  65. package/dist/merchant-session-probe.js +53 -0
  66. package/dist/merchant-session.generated.d.ts +69 -0
  67. package/dist/merchant-session.generated.js +919 -0
  68. package/dist/payrails.d.ts +133 -0
  69. package/dist/payrails.generated.d.ts +73 -0
  70. package/dist/payrails.generated.js +596 -0
  71. package/dist/payrails.js +305 -0
  72. package/dist/pelecard.d.ts +32 -0
  73. package/dist/pelecard.generated.d.ts +32 -0
  74. package/dist/pelecard.generated.js +283 -0
  75. package/dist/pelecard.js +42 -0
  76. package/dist/pre-claim.d.ts +81 -2
  77. package/dist/pre-claim.js +1023 -5
  78. package/dist/preflight-catalog.json +2267 -288
  79. package/dist/preflight-schemas.json +183 -6
  80. package/dist/preflight.generated.d.ts +1 -1
  81. package/dist/preflight.generated.js +243 -4
  82. package/dist/preparation.d.ts +12 -3
  83. package/dist/preparation.js +63 -12
  84. package/dist/prepared-processor.d.ts +84 -5
  85. package/dist/prepared-processor.js +147 -6
  86. package/dist/primer.d.ts +53 -0
  87. package/dist/primer.generated.d.ts +38 -0
  88. package/dist/primer.generated.js +624 -0
  89. package/dist/primer.js +82 -0
  90. package/dist/registry.d.ts +100 -8
  91. package/dist/registry.js +85 -11
  92. package/dist/shiji-sts.d.ts +144 -0
  93. package/dist/shiji-sts.generated.d.ts +72 -0
  94. package/dist/shiji-sts.generated.js +913 -0
  95. package/dist/shiji-sts.js +222 -0
  96. package/dist/stripe-checkout.generated.d.ts +1 -1
  97. package/dist/stripe-checkout.generated.js +764 -9
  98. package/dist/stripe-setup.d.ts +16 -0
  99. package/dist/stripe-setup.js +61 -0
  100. package/dist/substitutions.generated.js +187 -29
  101. package/dist/verifone.d.ts +68 -0
  102. package/dist/verifone.generated.d.ts +51 -0
  103. package/dist/verifone.generated.js +1413 -0
  104. package/dist/verifone.js +119 -0
  105. package/dist/voice-types.d.ts +27 -0
  106. package/dist/voice.d.ts +6 -1
  107. package/dist/voice.js +6 -1
  108. package/dist/wspay.d.ts +41 -0
  109. package/dist/wspay.generated.d.ts +41 -0
  110. package/dist/wspay.generated.js +370 -0
  111. package/dist/wspay.js +65 -0
  112. package/examples/preflight/kernel-native/inventory.json +1 -1
  113. package/package.json +3 -3
@@ -0,0 +1,549 @@
1
+ // @ts-nocheck
2
+ // Generated from @agent-cards/payment-core. Do not edit.
3
+ // artifact-sha256: bc8b9a0ad66eb321bec67650079b2d157a84f9f8de4ad79cc9006b937a9a5a58
4
+ // src/amadeus-body.js
5
+ var AMADEUS_CARD_MOPID = /^creditcard[0-9]*$/;
6
+ var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
7
+ var owns = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
8
+ var holdsPan = (mopdata) => record(mopdata) && owns(mopdata, "pan") && mopdata.pan !== null && mopdata.pan !== "";
9
+ function amadeusBodyKind(body) {
10
+ let value;
11
+ try {
12
+ value = typeof body === "string" ? JSON.parse(body) : void 0;
13
+ }
14
+ catch {
15
+ return "card";
16
+ }
17
+ if (!record(value))
18
+ return "card";
19
+ if (value.action === "add") {
20
+ const entries = Array.isArray(value.data) ? value.data : [value.data];
21
+ return entries.some((entry) => record(entry) && typeof entry.mopid === "string" && AMADEUS_CARD_MOPID.test(entry.mopid) && holdsPan(entry.mopdata)) ? "card" : "other";
22
+ }
23
+ if (value.action === "store")
24
+ return record(value.data) && holdsPan(value.data.mopdata) ? "card" : "other";
25
+ return "other";
26
+ }
27
+ // src/amadeus-checkout.js
28
+ var AMADEUS_CHECKOUT_PSP = "amadeus_checkout";
29
+ var AMADEUS_CHECKOUT_CAPABILITY = "amadeus_checkout_actions.v1";
30
+ var AMADEUS_CARD_URLS = Object.freeze({
31
+ production: Object.freeze({
32
+ sdk: Object.freeze(["https://paypages.payment.amadeus.com/1ASIATP/ARIAPP/pay"]),
33
+ dcp: Object.freeze(["https://paypages.payment.amadeus.com/1ASIATP/ATPDCP/collect"])
34
+ }),
35
+ // pdt, uat, mig and skl. DCP was seen on the production path only, so the test host takes no store.
36
+ sandbox: Object.freeze({
37
+ sdk: Object.freeze([
38
+ "https://paypages.test.payment.amadeus.com/1ASIATP/ARIAPP/pay",
39
+ "https://paypages.test.payment.amadeus.com/1ASIATPU/ARIAPP/pay",
40
+ "https://paypages.test.payment.amadeus.com/1ASIATPM/ARIAPP/pay",
41
+ "https://paypages.test.payment.amadeus.com/1ASIATPK/ARIAPP/pay"
42
+ ]),
43
+ dcp: Object.freeze([])
44
+ })
45
+ });
46
+ var AMADEUS_MERCHANT_EXPIRY_POLICIES = Object.freeze(["refuse", "fill"]);
47
+ var AMADEUS_MERCHANT_EXPIRY_POLICY = "refuse";
48
+ var AMADEUS_REFUSAL_REASONS = Object.freeze([
49
+ "unsupported",
50
+ "card_on_file",
51
+ "split_tender",
52
+ "installments",
53
+ "currency_conversion",
54
+ "amadeus_3ds",
55
+ "saved_card",
56
+ "vendor_mismatch",
57
+ "header_binding",
58
+ "merchant_held_expiry",
59
+ "dcp_field_config_unreviewed"
60
+ ]);
61
+ var MESSAGES = Object.freeze({
62
+ unsupported: "Refusing to pay: unsupported Amadeus card request.",
63
+ card_on_file: "Refusing to pay: this Amadeus payment would let the merchant keep your card on file, which needs your consent first. Nothing was sent.",
64
+ split_tender: "Refusing to pay: this Amadeus payment splits the total across more than one payment method. Nothing was sent.",
65
+ installments: "Refusing to pay: this Amadeus payment asks to pay in installments. Nothing was sent.",
66
+ currency_conversion: "Refusing to pay: this Amadeus payment converts the total into another currency. Nothing was sent.",
67
+ amadeus_3ds: "Refusing to pay: this Amadeus payment set up its card check for a different card. Nothing was sent.",
68
+ saved_card: "Refusing to pay: this Amadeus payment uses a card saved with the merchant, not your Vault card. Nothing was sent.",
69
+ vendor_mismatch: "Refusing to pay: this Amadeus payment names a card network that is not your card's. Nothing was sent.",
70
+ header_binding: "Refusing to pay: this Amadeus card form does not belong to the merchant you approved. Nothing was sent.",
71
+ merchant_held_expiry: "Refusing to pay: this merchant sends your card's expiry date separately, which Agentcard cannot fill yet. Nothing was sent.",
72
+ dcp_field_config_unreviewed: "Refusing to pay: Agentcard has not reviewed this merchant's Amadeus card form yet. Nothing was sent."
73
+ });
74
+ var FILL_REFUSAL = "Could not fill the card fields for Amadeus. Nothing was sent.";
75
+ var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
76
+ var owns2 = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
77
+ var exact = (pattern, value) => typeof value === "string" && pattern.exec(value)?.[0] === value;
78
+ var digits = (value, min, max) => typeof value === "string" && value.length >= min && value.length <= max && !/[^0-9]/.test(value);
79
+ var panLike = (value) => /(?:[0-9][ _.:-]*){12,}/.test(value);
80
+ var plain = (value, max) => typeof value === "string" && value.length <= max && !/[\u0000-\u001f\u007f]/.test(value) && !panLike(value);
81
+ var keysWithin = (value, allowed) => Object.keys(value).every((key) => allowed.includes(key));
82
+ var IDENTIFIER_ID = /^[A-Za-z0-9._~-]{8,64}$/;
83
+ function readAmadeusBody(body) {
84
+ if (typeof body !== "string" || body === "" || body.length > 65536)
85
+ return null;
86
+ let value;
87
+ try {
88
+ value = JSON.parse(body);
89
+ }
90
+ catch {
91
+ return null;
92
+ }
93
+ return record2(value) && JSON.stringify(value) === body ? value : null;
94
+ }
95
+ function amadeusCardUrl(url) {
96
+ if (typeof url !== "string")
97
+ return null;
98
+ for (const environment of ["production", "sandbox"]) {
99
+ for (const path of ["sdk", "dcp"]) {
100
+ if (AMADEUS_CARD_URLS[environment][path].includes(url))
101
+ return { path, environment };
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+ function isAmadeusCardUrl(url, method = "POST") {
107
+ return method === "POST" && amadeusCardUrl(url) !== null;
108
+ }
109
+ function amadeusEnvironment(url) {
110
+ return amadeusCardUrl(url)?.environment;
111
+ }
112
+ function amadeusPreparationUrls(environment) {
113
+ if (environment !== "production" && environment !== "sandbox")
114
+ throw new Error("unsupported_preparation_environment");
115
+ return [...AMADEUS_CARD_URLS[environment].sdk, ...AMADEUS_CARD_URLS[environment].dcp];
116
+ }
117
+ var SDK_CONTENT_TYPE = /^text\/plain(?:;\s*charset=utf-8)?$/i;
118
+ var DCP_CONTENT_TYPE = /^application\/json(?:;\s*charset=utf-8)?$/i;
119
+ var SDK_VERSION = /^WEB\/[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9a-f]{6,40}$/;
120
+ var SDK_FLAVORS = Object.freeze(["Core-Sdk", "Angular-Web-Sdk"]);
121
+ var LABEL = "[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?";
122
+ var SDK_HOST = new RegExp(`^${LABEL}(?:\\.${LABEL})+(?::[0-9]{1,5})?$`, "i");
123
+ var SDK_HEADERS = Object.freeze(["amadeus-checkout-sdk-version", "amadeus-checkout-sdk-host", "amadeus-checkout-sdk-flavor"]);
124
+ function foldHeaders(headers) {
125
+ if (!record2(headers))
126
+ return null;
127
+ const folded = /* @__PURE__ */ new Map();
128
+ for (const [name, value] of Object.entries(headers)) {
129
+ const lower = name.toLowerCase();
130
+ if (folded.has(lower) || typeof value !== "string")
131
+ return null;
132
+ folded.set(lower, value);
133
+ }
134
+ return folded;
135
+ }
136
+ function amadeusOwnHost(host) {
137
+ const name = host.split(":")[0].toLowerCase();
138
+ return ["amadeus.com", "amadeus.net", "outpayce.com"].some((domain) => name === domain || name.endsWith(`.${domain}`));
139
+ }
140
+ var HOSTLESS_SDK_VERSION = /^WEB\/3\.0\.0\/[0-9a-f]{6,40}$/;
141
+ function hostBindingRefusal(folded, approvedHost) {
142
+ const host = folded.get("amadeus-checkout-sdk-host");
143
+ if (host === void 0) {
144
+ return approvedHost === void 0 && exact(HOSTLESS_SDK_VERSION, folded.get("amadeus-checkout-sdk-version")) ? null : "header_binding";
145
+ }
146
+ if (!exact(SDK_HOST, host) || amadeusOwnHost(host))
147
+ return "header_binding";
148
+ if (approvedHost === void 0)
149
+ return null;
150
+ return typeof approvedHost === "string" && host.toLowerCase() === approvedHost.toLowerCase() ? null : "header_binding";
151
+ }
152
+ function amadeusSdkHostRefusal(headers, approvedHost) {
153
+ const folded = foldHeaders(headers);
154
+ if (!folded || typeof approvedHost !== "string" || approvedHost === "")
155
+ return "header_binding";
156
+ return hostBindingRefusal(folded, approvedHost);
157
+ }
158
+ function headersRefusal(path, headers, merchantHost) {
159
+ const folded = foldHeaders(headers ?? {});
160
+ if (!folded)
161
+ return "unsupported";
162
+ if (path === "dcp") {
163
+ if (!exact(DCP_CONTENT_TYPE, folded.get("content-type")))
164
+ return "unsupported";
165
+ return SDK_HEADERS.some((name) => folded.has(name)) ? "unsupported" : null;
166
+ }
167
+ if (!exact(SDK_CONTENT_TYPE, folded.get("content-type")))
168
+ return "unsupported";
169
+ if (!exact(SDK_VERSION, folded.get("amadeus-checkout-sdk-version")))
170
+ return "header_binding";
171
+ const flavor = folded.get("amadeus-checkout-sdk-flavor");
172
+ if (flavor !== void 0 && !SDK_FLAVORS.includes(flavor))
173
+ return "unsupported";
174
+ return hostBindingRefusal(folded, merchantHost);
175
+ }
176
+ var SDK_DATA_KEYS = Object.freeze(["mopid", "mopdata", "fingerprint"]);
177
+ var SDK_MOPDATA_KEYS = Object.freeze(["pan", "CVV", "holdername", "expmonth", "expyear", "vendor", "address", "contact"]);
178
+ var SDK_MOPDATA_REFUSALS = Object.freeze({
179
+ prefill_index: "saved_card",
180
+ installmentPlansID: "installments",
181
+ selectedInstallmentPlan: "installments",
182
+ options: "currency_conversion",
183
+ tdsSessionId: "amadeus_3ds",
184
+ tdsDeviceInformation: "amadeus_3ds"
185
+ });
186
+ var VENDOR = /^[a-z0-9_]{2,32}$/;
187
+ var TWO_DIGITS = /^[0-9]{2}$/;
188
+ var MONTH = /^(?:0[1-9]|1[0-2])$/;
189
+ var PHONE = /^\+?[0-9][0-9 ().-]{2,31}$/;
190
+ var ADDRESS_KEY = /^[A-Za-z][A-Za-z0-9_]{0,31}$/;
191
+ function addressSound(value) {
192
+ if (!record2(value))
193
+ return false;
194
+ const entries = Object.entries(value);
195
+ return entries.length <= 16 && entries.every(([key, text]) => exact(ADDRESS_KEY, key) && plain(text, 128));
196
+ }
197
+ function contactSound(value) {
198
+ return record2(value) && keysWithin(value, ["phone", "email"]) && (!owns2(value, "phone") || exact(PHONE, value.phone)) && (!owns2(value, "email") || plain(value.email, 254));
199
+ }
200
+ function sdkShapeRefusal(value) {
201
+ if (!keysWithin(value, ["PPID", "data", "action"]) || !owns2(value, "data") || value.action !== "add" || !exact(IDENTIFIER_ID, value.PPID))
202
+ return "unsupported";
203
+ if (Array.isArray(value.data))
204
+ return "split_tender";
205
+ const data = value.data;
206
+ if (!record2(data))
207
+ return "unsupported";
208
+ if (owns2(data, "saveMopInformation"))
209
+ return "card_on_file";
210
+ if (owns2(data, "partial_amount"))
211
+ return "split_tender";
212
+ if (!keysWithin(data, SDK_DATA_KEYS) || !exact(AMADEUS_CARD_MOPID, data.mopid) || !record2(data.mopdata) || owns2(data, "fingerprint") && !(plain(data.fingerprint, 256) && /^[\x20-\x7e]+$/.test(data.fingerprint)))
213
+ return "unsupported";
214
+ const mopdata = data.mopdata;
215
+ for (const key of Object.keys(mopdata)) {
216
+ if (owns2(SDK_MOPDATA_REFUSALS, key))
217
+ return SDK_MOPDATA_REFUSALS[key];
218
+ }
219
+ if (!keysWithin(mopdata, SDK_MOPDATA_KEYS) || !digits(mopdata.pan, 12, 19) || !digits(mopdata.CVV, 3, 4) || !exact(VENDOR, mopdata.vendor))
220
+ return "unsupported";
221
+ const bothEmpty = mopdata.expmonth === "" && mopdata.expyear === "";
222
+ if (!bothEmpty && !(exact(MONTH, mopdata.expmonth) && exact(TWO_DIGITS, mopdata.expyear)))
223
+ return "unsupported";
224
+ if (owns2(mopdata, "holdername") && !plain(mopdata.holdername, 128) || owns2(mopdata, "address") && !addressSound(mopdata.address) || owns2(mopdata, "contact") && !contactSound(mopdata.contact))
225
+ return "unsupported";
226
+ return null;
227
+ }
228
+ var AMADEUS_DCP_REVIEWED_KEYS = Object.freeze(["vendor", "pan", "expdate", "owner", "cvv", "address", "city", "zipCode", "country", "state"]);
229
+ var DCP_TEXT_KEYS = Object.freeze(["address", "city", "zipCode", "country", "state"]);
230
+ var DCP_VENDOR = /^[A-Za-z0-9_-]{1,32}$/;
231
+ var EXPDATE = /^(?:0[1-9]|1[0-2])[0-9]{2}$/;
232
+ var NETWORKS = Object.freeze(["visa", "mastercard", "amex"]);
233
+ function isAmadeusDcpConfig(config) {
234
+ if (!record2(config) || !keysWithin(config, ["keys", "vendors"]) || !Array.isArray(config.keys) || !record2(config.vendors))
235
+ return false;
236
+ const keys = config.keys;
237
+ if (new Set(keys).size !== keys.length || !keys.every((key) => AMADEUS_DCP_REVIEWED_KEYS.includes(key)) || !["pan", "expdate", "vendor"].every((key) => keys.includes(key)))
238
+ return false;
239
+ const vendors = Object.entries(config.vendors);
240
+ return vendors.length > 0 && vendors.every(([network, code]) => NETWORKS.includes(network) && exact(DCP_VENDOR, code));
241
+ }
242
+ function dcpShapeRefusal(value, config) {
243
+ if (!keysWithin(value, ["DCPID", "action", "data"]) || value.action !== "store" || !exact(IDENTIFIER_ID, value.DCPID) || !record2(value.data) || !keysWithin(value.data, ["mopdata"]) || !record2(value.data.mopdata))
244
+ return "unsupported";
245
+ if (!isAmadeusDcpConfig(config))
246
+ return "dcp_field_config_unreviewed";
247
+ const mopdata = value.data.mopdata;
248
+ if (typeof mopdata.pan === "string" && (mopdata.pan.includes("X") || mopdata.pan.startsWith("prefilled-")))
249
+ return "saved_card";
250
+ if (!keysWithin(mopdata, config.keys) || !digits(mopdata.pan, 12, 19) || !exact(EXPDATE, mopdata.expdate) || !exact(DCP_VENDOR, mopdata.vendor) || owns2(mopdata, "cvv") && !digits(mopdata.cvv, 3, 4) || owns2(mopdata, "owner") && !plain(mopdata.owner, 128) || DCP_TEXT_KEYS.some((key) => owns2(mopdata, key) && !plain(mopdata[key], 128)))
251
+ return "unsupported";
252
+ return null;
253
+ }
254
+ function amadeusVendorFor(number) {
255
+ if (!digits(number, 12, 19))
256
+ return null;
257
+ const two = Number(number.slice(0, 2));
258
+ const four = Number(number.slice(0, 4));
259
+ if (number[0] === "4")
260
+ return "visa";
261
+ if (two >= 51 && two <= 55 || four >= 2221 && four <= 2720)
262
+ return "mastercard";
263
+ if (two === 34 || two === 37)
264
+ return "amex";
265
+ return null;
266
+ }
267
+ function soundCard(card) {
268
+ if (!record2(card))
269
+ return null;
270
+ const month = Number.isInteger(card.month) || digits(card.month, 1, 2) ? Number(card.month) : NaN;
271
+ const year = Number.isInteger(card.year) || digits(card.year, 2, 4) ? Number(card.year) : NaN;
272
+ const vendor = amadeusVendorFor(card.number);
273
+ if (!vendor || !(month >= 1 && month <= 12) || !(year >= 0 && year <= 99 || year >= 2e3 && year <= 2099) || !digits(card.cvc, vendor === "amex" ? 4 : 3, vendor === "amex" ? 4 : 3))
274
+ return null;
275
+ const name = typeof card.name === "string" && card.name.trim() !== "" && plain(card.name, 128) ? card.name : null;
276
+ return { number: card.number, cvc: card.cvc, vendor, mm: String(month).padStart(2, "0"), yy: String(year % 100).padStart(2, "0"), name };
277
+ }
278
+ function bodyRefusal(path, value, card, options) {
279
+ if (path === "sdk") {
280
+ if (!owns2(value, "PPID"))
281
+ return "unsupported";
282
+ const shape2 = sdkShapeRefusal(value);
283
+ if (shape2)
284
+ return shape2;
285
+ const mopdata = value.data.mopdata;
286
+ const policy = options.expiryPolicy ?? AMADEUS_MERCHANT_EXPIRY_POLICY;
287
+ if (mopdata.expmonth === "" && policy !== "fill")
288
+ return "merchant_held_expiry";
289
+ if (card === null)
290
+ return null;
291
+ return amadeusVendorFor(card && card.number) === mopdata.vendor ? null : "vendor_mismatch";
292
+ }
293
+ if (!owns2(value, "DCPID"))
294
+ return "unsupported";
295
+ const shape = dcpShapeRefusal(value, options.dcpConfig);
296
+ if (shape)
297
+ return shape;
298
+ if (card === null)
299
+ return null;
300
+ const network = amadeusVendorFor(card && card.number);
301
+ return network !== null && options.dcpConfig.vendors[network] === value.data.mopdata.vendor ? null : "vendor_mismatch";
302
+ }
303
+ function amadeusRequestRefusal(request, card, options = {}) {
304
+ if (!record2(request) || request.method !== "POST")
305
+ return "unsupported";
306
+ const at = amadeusCardUrl(request.url);
307
+ const value = readAmadeusBody(request.body);
308
+ if (!at || !value)
309
+ return "unsupported";
310
+ return headersRefusal(at.path, request.headers, options.merchantHost) ?? bodyRefusal(at.path, value, card, options);
311
+ }
312
+ function amadeusRefusalMessage(reason) {
313
+ return owns2(MESSAGES, reason) ? MESSAGES[reason] : MESSAGES.unsupported;
314
+ }
315
+ function isPreparedAmadeusRequest(url, method, body, environment, headers, options = {}) {
316
+ return (environment === "production" || environment === "sandbox") && amadeusEnvironment(url) === environment && amadeusRequestRefusal({ url, method, body, headers }, null, options) === null;
317
+ }
318
+ var NAME_REFUSAL = "Add a cardholder name to the selected card in your Vault, then try again. Nothing was sent.";
319
+ function injectAmadeusCard(body, card, options = {}) {
320
+ const value = readAmadeusBody(body);
321
+ const path = value && owns2(value, "PPID") ? "sdk" : value && owns2(value, "DCPID") ? "dcp" : null;
322
+ if (path === null)
323
+ throw new Error(MESSAGES.unsupported);
324
+ const shape = bodyRefusal(path, value, null, options);
325
+ if (shape)
326
+ throw new Error(amadeusRefusalMessage(shape));
327
+ const sound = soundCard(card);
328
+ if (!sound)
329
+ throw new Error(FILL_REFUSAL);
330
+ const vendor = bodyRefusal(path, value, card, options);
331
+ if (vendor)
332
+ throw new Error(amadeusRefusalMessage(vendor));
333
+ const mopdata = value.data.mopdata;
334
+ const holder = path === "sdk" ? "holdername" : "owner";
335
+ if (owns2(mopdata, holder) && !sound.name) {
336
+ throw new Error(typeof card.name === "string" && card.name.trim() !== "" ? FILL_REFUSAL : NAME_REFUSAL);
337
+ }
338
+ const where = [];
339
+ const write = (key, text) => {
340
+ mopdata[key] = text;
341
+ where.push(`data.mopdata.${key}`);
342
+ };
343
+ if (path === "sdk") {
344
+ write("pan", sound.number);
345
+ write("CVV", sound.cvc);
346
+ write("expmonth", sound.mm);
347
+ write("expyear", sound.yy);
348
+ }
349
+ else {
350
+ write("pan", sound.number);
351
+ if (owns2(mopdata, "cvv"))
352
+ write("cvv", sound.cvc);
353
+ write("expdate", `${sound.mm}${sound.yy}`);
354
+ }
355
+ if (owns2(mopdata, holder))
356
+ write(holder, sound.name);
357
+ return { body: JSON.stringify(value), where };
358
+ }
359
+ var RESPONSE_LIMIT = 32768;
360
+ var DECLINE_LABELS = Object.freeze(["label_error_payment", "label_error_bin", "label_error_bin_vendor", "label_error_bin_type"]);
361
+ var EXPIRED_LABELS = Object.freeze(["session_timeout", "ppid_expired"]);
362
+ var REF_KEYS = Object.freeze(["recloc", "orderId", "mopId", "pri", "approvalcode", "externalId", "paymentMerchantReference", "prr"]);
363
+ var PAYMENT_INFORMATION_KEYS = Object.freeze(["approvalcode", "pri", "externalId", "mopId"]);
364
+ var REF_VALUE = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,63}$/;
365
+ var FEE = /^[0-9]{1,9}(?:\.[0-9]{1,4})?$/;
366
+ function readAnswer(body) {
367
+ if (typeof body !== "string" || body === "" || body.length > RESPONSE_LIMIT)
368
+ return null;
369
+ try {
370
+ const value = JSON.parse(body);
371
+ return record2(value) ? value : null;
372
+ }
373
+ catch {
374
+ return null;
375
+ }
376
+ }
377
+ function refValues(value, keys) {
378
+ const out = {};
379
+ for (const key of keys) {
380
+ if (!owns2(value, key))
381
+ continue;
382
+ if (!exact(REF_VALUE, value[key]))
383
+ return null;
384
+ out[key] = value[key];
385
+ }
386
+ return out;
387
+ }
388
+ function rebuildRefs(refs) {
389
+ if (!record2(refs))
390
+ return null;
391
+ const out = refValues(refs, REF_KEYS);
392
+ if (!out)
393
+ return null;
394
+ if (owns2(refs, "paymentInformation")) {
395
+ const list = refs.paymentInformation;
396
+ if (!Array.isArray(list) || list.length > 8 || !list.every(record2))
397
+ return null;
398
+ const rebuilt = list.map((entry) => refValues(entry, PAYMENT_INFORMATION_KEYS));
399
+ if (rebuilt.some((entry) => entry === null))
400
+ return null;
401
+ out.paymentInformation = rebuilt;
402
+ }
403
+ return out;
404
+ }
405
+ function successUrl(value) {
406
+ if (typeof value !== "string" || value.length > 2048 || !/^https:\/\/[\x21-\x7e]+$/.test(value) || /["'<>\\]/.test(value))
407
+ return false;
408
+ try {
409
+ return new URL(value).protocol === "https:";
410
+ }
411
+ catch {
412
+ return false;
413
+ }
414
+ }
415
+ function unescaped(text) {
416
+ let out = text;
417
+ for (let pass = 0; pass < 16; pass += 1) {
418
+ const next = out.replace(/%([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
419
+ if (next === out)
420
+ return out;
421
+ out = next;
422
+ }
423
+ return null;
424
+ }
425
+ function cardShaped(text) {
426
+ const open = unescaped(text);
427
+ return open === null || /(?:[0-9][^A-Za-z0-9]*){12,}/.test(open);
428
+ }
429
+ function rebuildSdkSuccess(value) {
430
+ const data = value.data;
431
+ const unexpected = { out: null, reason: "amadeus_unexpected_response" };
432
+ if (!keysWithin(value, ["status", "action", "data", "messages"]) || value.status !== "OK" || value.action !== "redirect" || !record2(data) || !keysWithin(data, ["type", "refs", "url", "obfees_amount"]) || data.type !== "success_backtomerchant")
433
+ return unexpected;
434
+ const out = { status: "OK", action: "redirect", data: { type: "success_backtomerchant" } };
435
+ const kept = [];
436
+ if (owns2(data, "refs")) {
437
+ const refs = rebuildRefs(data.refs);
438
+ if (!refs)
439
+ return unexpected;
440
+ out.data.refs = refs;
441
+ kept.push(...REF_KEYS.filter((key) => owns2(refs, key)).map((key) => refs[key]));
442
+ for (const entry of refs.paymentInformation ?? [])
443
+ kept.push(...Object.values(entry));
444
+ }
445
+ if (owns2(data, "url")) {
446
+ if (!successUrl(data.url))
447
+ return unexpected;
448
+ out.data.url = data.url;
449
+ kept.push(data.url);
450
+ }
451
+ if (owns2(data, "obfees_amount")) {
452
+ const fee = data.obfees_amount;
453
+ if (!(exact(FEE, fee) || typeof fee === "number" && Number.isFinite(fee) && fee >= 0 && fee < 1e9))
454
+ return unexpected;
455
+ out.data.obfees_amount = fee;
456
+ }
457
+ return kept.some(cardShaped) ? { out: null, reason: "amadeus_card_shaped_value" } : { out, reason: null };
458
+ }
459
+ function sdkFailureLabel(value) {
460
+ if (value.status !== "KO" || !Array.isArray(value.messages) || !record2(value.messages[0]))
461
+ return null;
462
+ const label = value.messages[0].text;
463
+ return DECLINE_LABELS.includes(label) || EXPIRED_LABELS.includes(label) ? label : null;
464
+ }
465
+ var cardText = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? String(value) : value;
466
+ function echoesCard(body, value, card) {
467
+ if (!record2(card))
468
+ return false;
469
+ const number = cardText(card.number);
470
+ if (!digits(number, 12, 19))
471
+ return false;
472
+ if (new RegExp(number.split("").join("[ _.:-]?")).test(body))
473
+ return true;
474
+ const cvc = cardText(card.cvc);
475
+ const pending = [value];
476
+ while (pending.length > 0) {
477
+ const node = pending.pop();
478
+ for (const [key, item] of Object.entries(node)) {
479
+ for (const text of [key, typeof item === "string" || typeof item === "number" ? String(item) : ""]) {
480
+ const open = unescaped(text);
481
+ if (open === null || open.replace(/[^0-9]/g, "").includes(number))
482
+ return true;
483
+ }
484
+ if (typeof item === "string" && key !== "obfees_amount" && digits(cvc, 3, 4) && unescaped(item)?.replace(/[\s_:-]/g, "") === cvc)
485
+ return true;
486
+ if (item !== null && typeof item === "object")
487
+ pending.push(item);
488
+ }
489
+ }
490
+ return false;
491
+ }
492
+ function amadeusResponseOutcome(status, body, { url, card } = {}) {
493
+ const at = amadeusCardUrl(url);
494
+ if (!at)
495
+ return { outcome: "unknown", reason: "amadeus_request_unknown" };
496
+ if (status >= 400 && status < 500)
497
+ return { outcome: "refused", code: `http_${status}` };
498
+ if (status !== 200)
499
+ return { outcome: "unknown", reason: "amadeus_status_unconfirmed" };
500
+ const value = readAnswer(body);
501
+ if (!value)
502
+ return { outcome: "unknown", reason: "amadeus_unreadable" };
503
+ if (card && echoesCard(body, value, card))
504
+ return { outcome: "unknown", reason: "amadeus_card_echo" };
505
+ if (at.path === "dcp")
506
+ return value.status === "OK" ? { outcome: "approved", feeApplied: false } : { outcome: "unknown", reason: "amadeus_dcp_unconfirmed" };
507
+ if (value.status === "KO") {
508
+ const label = sdkFailureLabel(value);
509
+ if (DECLINE_LABELS.includes(label))
510
+ return { outcome: "refused", code: label };
511
+ return { outcome: "unknown", reason: label ? "amadeus_session_expired" : "amadeus_unexpected_response" };
512
+ }
513
+ if (owns2(value, "actionToken") || owns2(value, "replies") || value.action !== "redirect" || !record2(value.data) || value.data.type !== "success_backtomerchant")
514
+ return { outcome: "unknown", reason: "amadeus_action_required" };
515
+ const rebuilt = rebuildSdkSuccess(value);
516
+ if (!rebuilt.out)
517
+ return { outcome: "unknown", reason: rebuilt.reason };
518
+ return { outcome: "approved", feeApplied: owns2(rebuilt.out.data, "obfees_amount") && Number(rebuilt.out.data.obfees_amount) !== 0 };
519
+ }
520
+ function sanitizeAmadeusResponse(body, url, card) {
521
+ const at = amadeusCardUrl(url);
522
+ const value = readAnswer(body);
523
+ const fail = () => {
524
+ throw new Error("Invalid Amadeus card response.");
525
+ };
526
+ if (!at || !value)
527
+ return fail();
528
+ let out;
529
+ if (at.path === "dcp") {
530
+ out = value.status === "OK" ? '{"status":"OK"}' : fail();
531
+ }
532
+ else if (value.status === "KO") {
533
+ const label = sdkFailureLabel(value);
534
+ out = label ? JSON.stringify({ status: "KO", messages: [{ type: "error", text: label }] }) : fail();
535
+ }
536
+ else {
537
+ const rebuilt = rebuildSdkSuccess(value);
538
+ out = rebuilt.out ? JSON.stringify(rebuilt.out) : fail();
539
+ }
540
+ if (card && echoesCard(out, JSON.parse(out), card))
541
+ return fail();
542
+ return out;
543
+ }
544
+ function amadeusFacts(body) {
545
+ const value = readAnswer(body);
546
+ const label = value ? sdkFailureLabel(value) : null;
547
+ return { refusalCode: DECLINE_LABELS.includes(label) ? label : null };
548
+ }
549
+ export { AMADEUS_CARD_MOPID, AMADEUS_CARD_URLS, AMADEUS_CHECKOUT_CAPABILITY, AMADEUS_CHECKOUT_PSP, AMADEUS_DCP_REVIEWED_KEYS, AMADEUS_MERCHANT_EXPIRY_POLICIES, AMADEUS_MERCHANT_EXPIRY_POLICY, AMADEUS_REFUSAL_REASONS, amadeusBodyKind, amadeusCardUrl, amadeusEnvironment, amadeusFacts, amadeusPreparationUrls, amadeusRefusalMessage, amadeusRequestRefusal, amadeusResponseOutcome, amadeusSdkHostRefusal, amadeusVendorFor, injectAmadeusCard, isAmadeusCardUrl, isAmadeusDcpConfig, isPreparedAmadeusRequest, readAmadeusBody, sanitizeAmadeusResponse };
@@ -0,0 +1,41 @@
1
+ /** How long after the pause a paused Amadeus SDK add may still be sent. */
2
+ export declare const AMADEUS_SEND_WINDOW_MS = 20000;
3
+ /**
4
+ * True when a request the adapters refuse must fail as a network error (ERR_FAILED) rather than as
5
+ * the cancellation (ERR_ABORTED) they use elsewhere. An XMLHttpRequest reports a cancellation only
6
+ * through its abort event, and Amadeus's tunnel listens for load, error and timeout alone, so a
7
+ * cancelled add would leave the SDK, and Air France's page, waiting for the page's own 40 second
8
+ * limit. As a network error, the tunnel reports it at once as its own "Error".
9
+ */
10
+ export declare function failsAsNetworkError(url: string): boolean;
11
+ /** The send window for a request paused under a preparation for `psp`, or null when it has none. */
12
+ export declare function amadeusSendWindowMs(psp: string | undefined, url: string): number | null;
13
+ /** What the window reads from the adapter, re-read when it closes. */
14
+ export interface SendWindowHooks {
15
+ /** The authorization the paused request raised, once the API created it. */
16
+ authorizationId(): string | null;
17
+ /** True once the answer is being handed to the page: the window no longer applies. */
18
+ delivering(): boolean;
19
+ /** A plain runtime cancel. Resolves only when the API confirms the card never moved. */
20
+ cancel?: (authorizationId: string) => Promise<unknown>;
21
+ /**
22
+ * Retire the preparation of a create that has not answered (VaultClient.retirePreparation).
23
+ * Resolves null once the API confirms no request can bind it, or the ID of the authorization
24
+ * already bound to it; rejects when the API confirms neither.
25
+ */
26
+ retirePreparation?: () => Promise<string | null>;
27
+ onEvent?: (event: {
28
+ type: string;
29
+ detail?: unknown;
30
+ }) => void;
31
+ }
32
+ /** The part of a merchant attempt the window acts on. */
33
+ export interface SendWindowAttempt {
34
+ readonly signal: AbortSignal;
35
+ stop(cause: 'amadeus_send_window_closed'): void;
36
+ }
37
+ /**
38
+ * Arm the window on one paused request. Returns the function that disarms it, which the adapter
39
+ * calls once the attempt settles, whatever the outcome.
40
+ */
41
+ export declare function armSendWindow(ms: number, attempt: SendWindowAttempt, hooks: SendWindowHooks): () => void;
@@ -0,0 +1,81 @@
1
+ // Two Amadeus Checkout rules both browser adapters share: how a refused card request fails
2
+ // (failsAsNetworkError), and the send window of a prepared SDK add, below.
3
+ //
4
+ // The Checkout Web SDK's tunnel iframe gives its add XHR 30 seconds (xhr.timeout = 30000 in
5
+ // tunnel.50fc56c91f295b5bfef0.js), then reports a timeout and Air France's page gives the payment
6
+ // up. A card the device sends after that point would register with Amadeus on a payment the page no
7
+ // longer waits for, so a paused add must be sent within 20 seconds of the pause or fail unsent. The
8
+ // SDK cannot see the device start sending, and the API can: a plain runtime cancel is confirmed only
9
+ // while the card has not moved, and once it is, the device's send is refused.
10
+ //
11
+ // So when the window closes and no answer is being handed to the page yet, the adapter asks for that
12
+ // cancel. Confirmed: nothing was sent and nothing can be, so the attempt stops, the page's request
13
+ // fails, and the checkout reads failed. Not confirmed: the device may already be sending, so the
14
+ // attempt keeps waiting for its answer, which can still reach the page, and the page's own 30 second
15
+ // deadline still ends it. A create that has not answered yet may already have committed its row and
16
+ // bound the preparation the cardholder approved, and that device may be sending too. So the window
17
+ // first retires the preparation: once the API confirms no request can bind it, nothing can be sent;
18
+ // when a request already holds it, that authorization gets the same cancel and the same rule, and
19
+ // when the API confirms neither, the attempt keeps waiting. The Data Collection Page's store has no
20
+ // client timeout and gets no window.
21
+ import { amadeusCardUrl } from './amadeus-checkout.generated.js';
22
+ /** How long after the pause a paused Amadeus SDK add may still be sent. */
23
+ export const AMADEUS_SEND_WINDOW_MS = 20_000;
24
+ /**
25
+ * True when a request the adapters refuse must fail as a network error (ERR_FAILED) rather than as
26
+ * the cancellation (ERR_ABORTED) they use elsewhere. An XMLHttpRequest reports a cancellation only
27
+ * through its abort event, and Amadeus's tunnel listens for load, error and timeout alone, so a
28
+ * cancelled add would leave the SDK, and Air France's page, waiting for the page's own 40 second
29
+ * limit. As a network error, the tunnel reports it at once as its own "Error".
30
+ */
31
+ export function failsAsNetworkError(url) {
32
+ return amadeusCardUrl(url) !== null;
33
+ }
34
+ /** The send window for a request paused under a preparation for `psp`, or null when it has none. */
35
+ export function amadeusSendWindowMs(psp, url) {
36
+ return psp === 'amadeus_checkout' && amadeusCardUrl(url)?.path === 'sdk' ? AMADEUS_SEND_WINDOW_MS : null;
37
+ }
38
+ /**
39
+ * Arm the window on one paused request. Returns the function that disarms it, which the adapter
40
+ * calls once the attempt settles, whatever the outcome.
41
+ */
42
+ export function armSendWindow(ms, attempt, hooks) {
43
+ let disarmed = false;
44
+ const settled = () => disarmed || attempt.signal.aborted || hooks.delivering();
45
+ // Resolves only once the API confirms the card never left the device and never can; see the top
46
+ // of this file for the create that has not answered.
47
+ const retire = async () => {
48
+ let id = hooks.authorizationId();
49
+ if (id === null) {
50
+ if (typeof hooks.retirePreparation !== 'function')
51
+ throw new Error('preparation_retirement_unavailable');
52
+ id = await hooks.retirePreparation();
53
+ }
54
+ if (id === null)
55
+ return;
56
+ if (typeof hooks.cancel !== 'function')
57
+ throw new Error('authorization_cancel_unavailable');
58
+ await hooks.cancel(id);
59
+ };
60
+ const close = async () => {
61
+ if (settled())
62
+ return;
63
+ let confirmed = false;
64
+ try {
65
+ await retire();
66
+ confirmed = true;
67
+ }
68
+ catch { /* not confirmed: the card may already be on its way */ }
69
+ if (settled())
70
+ return;
71
+ if (!confirmed) {
72
+ hooks.onEvent?.({ type: 'blocked', detail: 'amadeus_send_window_unconfirmed' });
73
+ return;
74
+ }
75
+ hooks.onEvent?.({ type: 'blocked', detail: 'amadeus_send_window_closed' });
76
+ attempt.stop('amadeus_send_window_closed');
77
+ };
78
+ const timer = setTimeout(() => { void close(); }, ms);
79
+ timer.unref?.();
80
+ return () => { disarmed = true; clearTimeout(timer); };
81
+ }