@agent-cards/sdk 0.23.22 → 0.23.24

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 (54) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/PREFLIGHT.md +2 -0
  3. package/README.md +34 -4
  4. package/dist/aci.generated.js +3 -3
  5. package/dist/agent-amount.generated.d.ts +7 -0
  6. package/dist/agent-amount.generated.js +3 -0
  7. package/dist/amadeus.d.ts +5 -2
  8. package/dist/amadeus.js +18 -3
  9. package/dist/amazon-payment-services.d.ts +25 -0
  10. package/dist/amazon-payment-services.generated.d.ts +76 -0
  11. package/dist/amazon-payment-services.generated.js +883 -0
  12. package/dist/amazon-payment-services.js +53 -0
  13. package/dist/capabilities.generated.d.ts +2 -0
  14. package/dist/capabilities.generated.js +3 -0
  15. package/dist/card-fields.generated.js +1127 -25
  16. package/dist/cdp.js +116 -15
  17. package/dist/client.d.ts +107 -8
  18. package/dist/client.js +277 -128
  19. package/dist/hosted-entry.js +2 -1
  20. package/dist/hosted-form.d.ts +5 -0
  21. package/dist/hosted-form.js +5 -0
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.js +1 -0
  24. package/dist/openpay.generated.d.ts +67 -0
  25. package/dist/openpay.generated.js +446 -0
  26. package/dist/paddle-checkout-watch.d.ts +70 -0
  27. package/dist/paddle-checkout-watch.js +239 -0
  28. package/dist/paddle-tokenex.generated.d.ts +29 -1
  29. package/dist/paddle-tokenex.generated.js +175 -26
  30. package/dist/paytrail.d.ts +58 -0
  31. package/dist/paytrail.js +98 -0
  32. package/dist/pre-claim.d.ts +4 -0
  33. package/dist/pre-claim.js +46 -2
  34. package/dist/prepared-processor.d.ts +12 -4
  35. package/dist/prepared-processor.js +31 -5
  36. package/dist/primer.generated.js +1155 -53
  37. package/dist/registry.d.ts +4 -3
  38. package/dist/registry.js +12 -4
  39. package/dist/sbps.d.ts +57 -0
  40. package/dist/sbps.generated.d.ts +96 -0
  41. package/dist/sbps.generated.js +427 -0
  42. package/dist/sbps.js +90 -0
  43. package/dist/stripe-checkout.generated.js +458 -8
  44. package/dist/tap-payments.d.ts +43 -0
  45. package/dist/tap-payments.generated.d.ts +59 -0
  46. package/dist/tap-payments.generated.js +990 -0
  47. package/dist/tap-payments.js +72 -0
  48. package/dist/transbank.d.ts +33 -0
  49. package/dist/transbank.js +62 -0
  50. package/dist/url-mask-parts.d.ts +24 -0
  51. package/dist/url-mask-parts.js +22 -0
  52. package/dist/url-masks.generated.d.ts +3 -0
  53. package/dist/url-masks.generated.js +2 -0
  54. package/package.json +4 -4
@@ -0,0 +1,72 @@
1
+ // Tap Payments' card frame, the token request as the SDK sees it (payment-core tap-payments.js has the request's shape,
2
+ // the merchant pins, the device's encryption and the substitution). Tap's frame encrypts the card itself, under the
3
+ // merchant's own RSA key, and sends it in one request:
4
+ // POST https://sdk.tap.company/v2/card/token
5
+ // Content-Type: application/json, Authorization: <the merchant's publishable key>
6
+ // {"encryptedData":"<base64>","purpose":"CHARGE",...,"order":{...},"device":{...},"browser":{...},"app":{...}}
7
+ // The agent's page encrypts a placeholder card, so encryptedData carries the placeholder. This build holds that request
8
+ // and writes over it the approved card's own ciphertext: the one the cardholder's device made under the key payment-core
9
+ // pins for the request's publishable key (never a key from a row, a request or a page). Every other byte goes as the
10
+ // frame wrote it (mode cse), so the full card number never reaches the agent's runtime. Tap answers a token; 3-D
11
+ // Secure and the merchant's charge then run in the agent's browser, card free.
12
+ //
13
+ // The generic Adyen swap takes only JWEs at a named holder, and Tap's ciphertext is RSA base64 at the body root, so
14
+ // this lane is dispatched by the token URL to substituteTapPayments, as 2C2P is to its own swap. The ciphertext names no
15
+ // session and no time: it would ask Tap for a token at the same merchant again, so the continuation writes it only into
16
+ // the one request the approval was created from, byte for byte.
17
+ //
18
+ // The registry entry ships dark (capability tap_card_sdk_token). Until this build declares the capability, the API
19
+ // serves the recognizer to no client of it, so nothing here fires. Autopilot never pays this processor: the API, the
20
+ // authority and the enclave refuse it.
21
+ import { TAP_PAYMENTS_FIELD, isTapPaymentsTokenUrl, substituteTapPayments, tapPaymentsRequestKey } from './tap-payments.generated.js';
22
+ /** The PSP id the API and the recognizer name this lane, re-exported so the client dispatches by it. */
23
+ export { TAP_PAYMENTS_PSP } from './tap-payments.generated.js';
24
+ /** The dark-launch capability a build declares when it fills a Tap token request with the device's ciphertext. */
25
+ export const TAP_PAYMENTS_CAPABILITY = 'tap_card_sdk_token';
26
+ /**
27
+ * Whether an approved Tap authorization's served substitution is one this SDK can continue: JSON at the body root (`at`
28
+ * is ''), no sibling to remove, and exactly the one ciphertext, a non-empty string. substituteTapPayments checks its
29
+ * size and range against the pin for the request's publishable key; this is the shape gate the client runs first.
30
+ */
31
+ export function isTapPaymentsServedSubstitution(sub) {
32
+ if (!sub || typeof sub !== 'object' || Array.isArray(sub))
33
+ return false;
34
+ const { encoding, at, fields, remove } = sub;
35
+ if (encoding !== 'json' || at !== '' || !fields || typeof fields !== 'object' || Array.isArray(fields))
36
+ return false;
37
+ if (remove !== undefined && !(Array.isArray(remove) && remove.length === 0))
38
+ return false;
39
+ const named = fields;
40
+ return Object.keys(named).length === 1 && typeof named[TAP_PAYMENTS_FIELD] === 'string' && named[TAP_PAYMENTS_FIELD].length > 0;
41
+ }
42
+ /**
43
+ * The continuation of an approved Tap token request: the paused body with the device's ciphertext written over the
44
+ * placeholder's at encryptedData (payment-core substituteTapPayments, which runs the frame's request rule again on the
45
+ * headers of the request that continues, and refuses a ciphertext that does not have the size and range of one under
46
+ * the pin for its publishable key, or one already in the paused body).
47
+ *
48
+ * Only into `approved`, the paused request the approval was created from: `url` and `body` must equal it byte for byte.
49
+ * A ciphertext under the merchant's key would ask Tap for a token in any later request of the same shape; binding it
50
+ * to the one request keeps this lane from ever writing one checkout's card into another. `headers` are those of the
51
+ * request that continues, the paused one or the page's retry of it, and the browser sends them as they are: they
52
+ * must name the publishable key the approved request named, so a retry under another merchant's key never carries the
53
+ * card.
54
+ *
55
+ * Null when neither URL is Tap's token URL, so every other processor keeps its own swap. Throws for any other body,
56
+ * URL or key, and for a substitution the shape gate or the swap refuses, in each case before anything continues. The
57
+ * approval is not retired on a refusal: the runtime already read the ciphertext, so the API keeps the row and its hold.
58
+ */
59
+ export function tapPaymentsContinuation(url, body, headers, sub, approved) {
60
+ if (!isTapPaymentsTokenUrl(url) && !isTapPaymentsTokenUrl(approved.url))
61
+ return null;
62
+ if (url !== approved.url || body !== approved.body)
63
+ throw new Error('Refusing to substitute: the paused request is not the Tap card request the cardholder approved.');
64
+ const key = tapPaymentsRequestKey({ headers: headers ?? {} });
65
+ if (key === null || key !== tapPaymentsRequestKey({ headers: approved.headers ?? {} })) {
66
+ throw new Error('Refusing to substitute: the Tap card request does not name the merchant key the cardholder approved.');
67
+ }
68
+ if (!isTapPaymentsServedSubstitution(sub))
69
+ throw new Error('Refusing to substitute: the Tap approval is not one encrypted card.');
70
+ const request = { url, method: 'POST', headers: headers ?? {}, body };
71
+ return { body: substituteTapPayments(request, { [TAP_PAYMENTS_FIELD]: sub.fields[TAP_PAYMENTS_FIELD] }) };
72
+ }
@@ -43,3 +43,36 @@ export declare function servesTransbank(vault: {
43
43
  export declare function isArmedTransbankUrl(vault: {
44
44
  isCardRequest(url: string, method?: string): boolean;
45
45
  } | undefined, url: string): boolean;
46
+ /**
47
+ * A reviewed Webpay shop, as this build reads it to send the browser back: the hosts of its checkout pages, the host of
48
+ * its return page, and the return page itself, exactly as its transactions name it (null while nobody has read it).
49
+ */
50
+ export interface TransbankReturnPage {
51
+ readonly hosts: readonly string[];
52
+ readonly returnHost: string;
53
+ readonly returnUrl: string | null;
54
+ }
55
+ /**
56
+ * payment-core's TRANSBANK_MERCHANTS, every row that names its commerce code, with these three fields. A row without a
57
+ * code names no shop there, so it is not listed here. transbank.test.mjs pins this list to payment-core's, so a reviewed
58
+ * change that codes a shop there fails this package's tests until the shop is listed here too. Teleférico Santiago's
59
+ * row names no code yet, so no paused entry is sent back anywhere.
60
+ */
61
+ export declare const TRANSBANK_RETURN_PAGES: readonly TransbankReturnPage[];
62
+ /**
63
+ * Where the paused Webpay entry `entryUrl` goes once the cardholder's phone has paid it: the return page of the one
64
+ * reviewed shop whose checkout pages include `pageOrigin` (the origin the create named, written exactly as an origin),
65
+ * with the entry's token as `token_ws`. The same navigation payment-core's transbankMerchantReturn builds, and the one
66
+ * Webpay itself sends the phone's session to. Null for a link that is not Webpay's entry, a page no reviewed shop
67
+ * lists, a page two list, or a shop whose return page no token can follow. `pages` is for tests.
68
+ */
69
+ export declare function transbankMerchantReturn(entryUrl: unknown, pageOrigin: unknown, pages?: readonly TransbankReturnPage[]): string | null;
70
+ /**
71
+ * The answer the paused entry gets: a 303 to the shop's return page, which the browser follows with a GET, and which no
72
+ * cache keeps (the URL carries Webpay's token).
73
+ */
74
+ export declare function transbankMerchantReturnAnswer(returnUrl: string): {
75
+ status: 303;
76
+ headers: Record<string, string>;
77
+ body: string;
78
+ };
package/dist/transbank.js CHANGED
@@ -71,3 +71,65 @@ export function servesTransbank(vault) {
71
71
  export function isArmedTransbankUrl(vault, url) {
72
72
  return isTransbankHost(url) && servesTransbank(vault);
73
73
  }
74
+ /**
75
+ * payment-core's TRANSBANK_MERCHANTS, every row that names its commerce code, with these three fields. A row without a
76
+ * code names no shop there, so it is not listed here. transbank.test.mjs pins this list to payment-core's, so a reviewed
77
+ * change that codes a shop there fails this package's tests until the shop is listed here too. Teleférico Santiago's
78
+ * row names no code yet, so no paused entry is sent back anywhere.
79
+ */
80
+ export const TRANSBANK_RETURN_PAGES = Object.freeze([]);
81
+ // Webpay's own return fields (payment-core processors/transbank.js RETURN_FIELDS): a return page never carries one.
82
+ const RETURN_FIELDS = new Set(['token_ws', 'TBK_TOKEN', 'TBK_ORDEN_COMPRA', 'TBK_ID_SESION']);
83
+ /** `page.returnUrl` when a token can follow it, as payment-core's pinnedReturnUrl reads a row's; null otherwise. */
84
+ function returnPageUrl(page) {
85
+ const raw = page?.returnUrl;
86
+ if (typeof raw !== 'string' || raw.length > 1024)
87
+ return null;
88
+ let url;
89
+ try {
90
+ url = new URL(raw);
91
+ }
92
+ catch {
93
+ return null;
94
+ }
95
+ if (url.protocol !== 'https:' || url.hostname !== page.returnHost || url.port || url.username || url.password || url.href !== raw
96
+ || /#|\?$|\?&|&&|&$/.test(raw))
97
+ return null;
98
+ for (const [name] of url.searchParams)
99
+ if (RETURN_FIELDS.has(name))
100
+ return null;
101
+ return raw;
102
+ }
103
+ /**
104
+ * Where the paused Webpay entry `entryUrl` goes once the cardholder's phone has paid it: the return page of the one
105
+ * reviewed shop whose checkout pages include `pageOrigin` (the origin the create named, written exactly as an origin),
106
+ * with the entry's token as `token_ws`. The same navigation payment-core's transbankMerchantReturn builds, and the one
107
+ * Webpay itself sends the phone's session to. Null for a link that is not Webpay's entry, a page no reviewed shop
108
+ * lists, a page two list, or a shop whose return page no token can follow. `pages` is for tests.
109
+ */
110
+ export function transbankMerchantReturn(entryUrl, pageOrigin, pages = TRANSBANK_RETURN_PAGES) {
111
+ if (!isTransbankEntryUrl(entryUrl) || typeof pageOrigin !== 'string' || pageOrigin.length > 256)
112
+ return null;
113
+ const token = new URL(entryUrl).searchParams.get('token_ws');
114
+ let origin;
115
+ try {
116
+ origin = new URL(pageOrigin);
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ if (origin.protocol !== 'https:' || origin.origin !== pageOrigin || origin.port)
122
+ return null;
123
+ const listing = pages.filter((page) => Array.isArray(page?.hosts) && page.hosts.includes(origin.hostname));
124
+ const returnUrl = listing.length === 1 ? returnPageUrl(listing[0]) : null;
125
+ if (!returnUrl || !token)
126
+ return null;
127
+ return `${returnUrl}${new URL(returnUrl).search ? '&' : '?'}token_ws=${token}`;
128
+ }
129
+ /**
130
+ * The answer the paused entry gets: a 303 to the shop's return page, which the browser follows with a GET, and which no
131
+ * cache keeps (the URL carries Webpay's token).
132
+ */
133
+ export function transbankMerchantReturnAnswer(returnUrl) {
134
+ return { status: 303, headers: { location: returnUrl, 'cache-control': 'no-store' }, body: '' };
135
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The parts every URL mask is built from (client.ts redactUrl). A processor whose card request carries its own
3
+ * credential in the URL path writes its mask in src/url-masks/<psp id>.ts, exported as `mask`, and the build
4
+ * collects every such file into src/url-masks.generated.ts (scripts/generate-url-masks.mjs).
5
+ */
6
+ /**
7
+ * `mask` reads a text that names the processor's host; `pathMask`, where a processor has one, reads the path of a
8
+ * URL already parsed on that host, which `mask` reads otherwise.
9
+ */
10
+ export interface UrlMask {
11
+ host: RegExp;
12
+ named: RegExp;
13
+ mask: (path: string) => string;
14
+ pathMask?: (path: string) => string;
15
+ }
16
+ /**
17
+ * A slash as the masks read one: plain, or escaped once or more in either case (%2F, %2f, %252F). A path keeps
18
+ * an escape as it was written, and the id behind it is the same id, so every slash a mask names reads in any of these
19
+ * spellings. The slashes right before an id read as a run, and a doubled slash hides nothing either.
20
+ */
21
+ export declare const SLASH = "(?:/|%(?:25)*2f)";
22
+ /** A hyphen inside an id: plain, or escaped once or more in either case (%2D, %252d). */
23
+ export declare const HYPHEN = "(?:-|%(?:25)*2d)";
24
+ export declare function maskUuids(path: string, label: string): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The parts every URL mask is built from (client.ts redactUrl). A processor whose card request carries its own
3
+ * credential in the URL path writes its mask in src/url-masks/<psp id>.ts, exported as `mask`, and the build
4
+ * collects every such file into src/url-masks.generated.ts (scripts/generate-url-masks.mjs).
5
+ */
6
+ /**
7
+ * A slash as the masks read one: plain, or escaped once or more in either case (%2F, %2f, %252F). A path keeps
8
+ * an escape as it was written, and the id behind it is the same id, so every slash a mask names reads in any of these
9
+ * spellings. The slashes right before an id read as a run, and a doubled slash hides nothing either.
10
+ */
11
+ export const SLASH = '(?:/|%(?:25)*2f)';
12
+ /** A hyphen inside an id: plain, or escaped once or more in either case (%2D, %252d). */
13
+ export const HYPHEN = '(?:-|%(?:25)*2d)';
14
+ /**
15
+ * The masks that find a uuid by its shape take it in any case, with or without its hyphens, each hyphen in any
16
+ * spelling HYPHEN reads. The pattern reads a percent escape as one unit and keeps it, so the hex digits of an escaped
17
+ * separator before the id (%2F, %252F, %3D) never start a match and leave the id's last digits showing.
18
+ */
19
+ const UUID_OR_ESCAPE = new RegExp(`%(?:25)*[0-9a-f]{2}|[0-9a-f]{8}${HYPHEN}?[0-9a-f]{4}${HYPHEN}?[0-9a-f]{4}${HYPHEN}?[0-9a-f]{4}${HYPHEN}?[0-9a-f]{12}`, 'gi');
20
+ export function maskUuids(path, label) {
21
+ return path.replace(UUID_OR_ESCAPE, (token) => (token.startsWith('%') ? token : label));
22
+ }
@@ -0,0 +1,3 @@
1
+ import type { UrlMask } from './url-mask-parts.js';
2
+ /** The masks of the processors registered in src/url-masks/: none yet. */
3
+ export declare const URL_MASKS: readonly UrlMask[];
@@ -0,0 +1,2 @@
1
+ /** The masks of the processors registered in src/url-masks/: none yet. */
2
+ export const URL_MASKS = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-cards/sdk",
3
- "version": "0.23.22",
3
+ "version": "0.23.24",
4
4
  "description": "Agentcard's SDK: one client, Agentcard, with two modules. checkout pauses a browser purchase and pays it with the person's own card; voice connects a person to your product once and approves a purchase by voice inside it. Card data never enters your process.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,12 +25,12 @@
25
25
  },
26
26
  "scripts": {
27
27
  "_comment_build": "The public SDK keeps zero runtime dependencies. Its build vendors deterministic metadata and substitution artifacts from the internal payment core (src/*.generated.ts), the voice streaming door from packages/voice/src/core (the phone package, @agent-cards/voice, ships it to phones), and the Kernel kit's inventory from the built catalog; git ignores every file it writes. TypeScript remains pinned.",
28
- "build": "node ../payment-core/scripts/build.mjs && node scripts/generate-payment-core.mjs && node scripts/generate-voice-stream.mjs && npx -y -p typescript@5.9.3 tsc && node scripts/generate-preflight-contract.mjs && node scripts/generate-kernel-native-inventory.mjs",
28
+ "build": "node ../payment-core/scripts/build.mjs && node scripts/generate-payment-core.mjs && node scripts/generate-voice-stream.mjs && node scripts/generate-url-masks.mjs && node scripts/generate-capabilities.mjs && node scripts/generate-agent-amount.mjs && npx -y -p typescript@5.9.3 tsc && node scripts/generate-preflight-contract.mjs && node scripts/generate-kernel-native-inventory.mjs",
29
29
  "prepublishOnly": "pnpm build",
30
30
  "_comment_test": "check:built runs first and names the command when a file the build generates (the copies in src/, the preflight contracts in dist/, the Kernel inventory) is missing or stale; verify:pack runs last, on the same dist.",
31
- "check:built": "node scripts/generate-payment-core.mjs --check && node scripts/generate-voice-stream.mjs --check && node scripts/generate-preflight-contract.mjs --check && node scripts/generate-kernel-native-inventory.mjs --check",
31
+ "check:built": "node scripts/generate-payment-core.mjs --check && node scripts/generate-voice-stream.mjs --check && node scripts/generate-url-masks.mjs --check && node scripts/generate-capabilities.mjs --check && node scripts/generate-agent-amount.mjs --check && node scripts/generate-preflight-contract.mjs --check && node scripts/generate-kernel-native-inventory.mjs --check",
32
32
  "verify:pack": "node scripts/verify-pack.mjs",
33
- "test": "npm run check:built && node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs redsys.test.mjs quickpay.test.mjs paypal-hosted-fields.test.mjs paypal-card-forms.test.mjs cybersource-secure-acceptance.test.mjs ebanx.test.mjs payrexx.test.mjs payrexx-follow-ups.test.mjs payrexx-adapters.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs wix-payments.test.mjs hipay.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs voice.test.mjs agentcard.test.mjs buy.test.mjs readme.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs paddle-vgs.test.mjs hold.test.mjs paddle-tokenex.test.mjs lyra.test.mjs gopay.test.mjs paygent.test.mjs twoc2p.test.mjs pay-nl.test.mjs toast.test.mjs redact-url.test.mjs hosted-entry.test.mjs comgate.test.mjs przelewy24.test.mjs tokenex-iframe.test.mjs transbank.test.mjs sumup.test.mjs clover.test.mjs eximbay.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs browser-tests.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs && node scripts/verify-pack.mjs",
33
+ "test": "npm run check:built && node test.mjs && node --test lifecycle.test.mjs merchant-abort.test.mjs preparation.test.mjs braintree.test.mjs pre-claim.test.mjs ekashu.test.mjs redsys.test.mjs quickpay.test.mjs paytrail.test.mjs paypal-hosted-fields.test.mjs paypal-card-forms.test.mjs cybersource-secure-acceptance.test.mjs ebanx.test.mjs payrexx.test.mjs payrexx-follow-ups.test.mjs payrexx-adapters.test.mjs autopilot.test.mjs stripe-checkout.test.mjs stripe-setup.test.mjs stripe-legacy-checkout.test.mjs payment-core.test.mjs prepared-processor.test.mjs merchant-hosted.test.mjs merchant-total.test.mjs sandbox-declaration.test.mjs minimum-delay.test.mjs paysafe.test.mjs wix-payments.test.mjs hipay.test.mjs openpay.test.mjs payu.test.mjs attachment.test.mjs worker-targets.test.mjs mercado-checkout.test.mjs mercado-polling.test.mjs amadeus.test.mjs pelecard.test.mjs aci.test.mjs primer.test.mjs payrails.test.mjs elavon-converge.test.mjs voice.test.mjs agentcard.test.mjs buy.test.mjs readme.test.mjs gmo.test.mjs cybersource-flex.test.mjs juspay-gate.test.mjs card-endpoint.test.mjs card-endpoint-fastspring.test.mjs card-endpoint-navigation.test.mjs merchant-session-probe.test.mjs datatrans.test.mjs authorize-net-dpm.test.mjs creditguard.test.mjs eprotect.test.mjs wspay.test.mjs shiji-sts.test.mjs worldline-mycheckout.test.mjs verifone.test.mjs gravy.test.mjs paddle-vgs.test.mjs sbps.test.mjs hold.test.mjs paddle-tokenex.test.mjs lyra.test.mjs gopay.test.mjs paygent.test.mjs twoc2p.test.mjs tap-payments.test.mjs pay-nl.test.mjs toast.test.mjs redact-url.test.mjs hosted-entry.test.mjs comgate.test.mjs przelewy24.test.mjs tokenex-iframe.test.mjs transbank.test.mjs sumup.test.mjs clover.test.mjs eximbay.test.mjs xendit.test.mjs omise.test.mjs fastspring.test.mjs amazon-payment-services.test.mjs && node --test preflight-package.test.mjs preflight-collector.test.mjs browser-tests.test.mjs && node --test kernel-native-qualification.test.mjs && node --test ../vault/scripts/recurly-validation/watch-duty-sdk-result.test.mjs && node scripts/verify-pack.mjs",
34
34
  "test:browser": "node browser-tests.mjs",
35
35
  "check:payment-core": "node scripts/generate-payment-core.mjs --check",
36
36
  "check:voice-stream": "node scripts/generate-voice-stream.mjs --check",