@12-apps/payments-frontend 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/payments-frontend",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "type": "module",
5
5
  "description": "Browser half of the vendor-agnostic payments platform: plug-and-play MUI components for the per-provider settings page (credential form from each provider's schema, masked hints, verify/enable) and the checkout page (PIX QR + polling, card tokenization, hosted-checkout redirect), plus the headless hooks and fetch clients they build on. Talks only to the host's payments HTTP surface — never to a provider directly. Microfrontend-ready: no app coupling, host injects theme and auth.",
6
6
  "exports": {
@@ -17,7 +17,7 @@
17
17
  "storybook:build": "storybook build"
18
18
  },
19
19
  "dependencies": {
20
- "@12-apps/payments-backend": "^1.8.0",
20
+ "@12-apps/payments-backend": "^1.9.0",
21
21
  "react-qr-code": "^2.2.0"
22
22
  },
23
23
  "peerDependencies": {
@@ -28,8 +28,8 @@
28
28
  "react-dom": ">=19.0.0"
29
29
  },
30
30
  "devDependencies": {
31
- "@12-apps/eslint-config": "^1.9.0",
32
- "@12-apps/typescript-config": "^1.9.0",
31
+ "@12-apps/eslint-config": "^1.10.0",
32
+ "@12-apps/typescript-config": "^1.10.0",
33
33
  "@emotion/react": "^11.14.0",
34
34
  "@emotion/styled": "^11.14.0",
35
35
  "@mui/material": "^6.5.0",
@@ -9,7 +9,7 @@ import { useEffect } from "react";
9
9
 
10
10
  import { tokenizerFor, type CardTokenizationConfig } from "../../card";
11
11
 
12
- import type { CheckoutProviderConfig, PaymentMethod } from "./types";
12
+ import type { CheckoutChainLink, CheckoutProviderConfig, PaymentMethod } from "./types";
13
13
 
14
14
  /**
15
15
  * Whether the store's CHAIN gives this browser a card path (FUT-697/563).
@@ -26,16 +26,39 @@ import type { CheckoutProviderConfig, PaymentMethod } from "./types";
26
26
  * Answering "yes, it is REDIRECT" off the head alone is what let the picker
27
27
  * offer a card the submit could never tokenize.
28
28
  *
29
+ * Asked only of the entries that DECLARE `CARD` (FUT-747), for the same reason
30
+ * the server's predicate is: tokenization is a card fact, so a PIX-only entry
31
+ * has nothing to say about the card path and must not be read as "this store
32
+ * hands the buyer over". A store with no card-capable entry at all has no card
33
+ * path — `offeredMethods` is already not offering one, and saying so here is
34
+ * what lets {@link usePreselectSoleMethod} pick the store's only method.
35
+ *
29
36
  * `null` config (still loading / fetch blip) fails OPEN for the UI — the
30
37
  * tokenizer itself still fails CLOSED.
31
38
  */
32
39
  export function cardPathAvailable(config: CheckoutProviderConfig | null): boolean {
33
40
  if (!config) return true;
34
- const chain = cardChain(config);
41
+ const chain = cardCapableChain(config);
42
+ if (chain.length === 0) return false;
35
43
  if (!chain.some((link) => link.mintable)) return true;
36
44
  return chain.some(canMintFor);
37
45
  }
38
46
 
47
+ /**
48
+ * The published chain narrowed to the entries that declare `CARD` — the same
49
+ * subset the server's walk will attempt, since it skips a provider whose
50
+ * capabilities exclude the method.
51
+ *
52
+ * A store that served NO chain (an older host, or a mocked config) has no
53
+ * per-entry `methods` to narrow on, so it degrades to {@link cardChain}'s head
54
+ * triple and behaves exactly as it did before.
55
+ */
56
+ function cardCapableChain(config: CheckoutProviderConfig): CardChainLink[] {
57
+ const chain = config.chain;
58
+ if (!chain || chain.length === 0) return cardChain(config);
59
+ return chain.filter((link) => link.methods.includes("CARD")).map(toCardLink);
60
+ }
61
+
39
62
  /** Whether this browser can really produce an instrument for ONE chain entry. */
40
63
  function canMintFor(link: CardChainLink): boolean {
41
64
  if (!link.mintable) return false;
@@ -104,12 +127,17 @@ export function cardChain(config: CheckoutProviderConfig | null): CardChainLink[
104
127
  const mintable = config.tokenization === null || MINTABLE.has(config.tokenization);
105
128
  return [{ ...cardTokenization(config), mintable }];
106
129
  }
107
- return chain.map((link) => ({
130
+ return chain.map(toCardLink);
131
+ }
132
+
133
+ /** ONE published chain entry, as the card path sees it. */
134
+ function toCardLink(link: CheckoutChainLink): CardChainLink {
135
+ return {
108
136
  provider: link.provider,
109
137
  publicKey: link.publicKey,
110
138
  mockTokenization: link.mockTokenization,
111
139
  mintable: MINTABLE.has(link.tokenization),
112
- }));
140
+ };
113
141
  }
114
142
 
115
143
  /**