@12-apps/payments-frontend 1.7.0 → 1.8.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.
@@ -0,0 +1,179 @@
1
+ /**
2
+ * The `createPaymentFlows` vocabulary (FUT-741).
3
+ *
4
+ * `@12-apps/payments-frontend` exported a FLAT list — components, headless
5
+ * hooks and fetch clients — and every host composed them by hand: six named
6
+ * imports, a local slot table, a local fetch client, and its own answer to
7
+ * "can this store charge?". Three hosts wrote that glue; the FUT-740 review
8
+ * found its criticals in exactly the seam that glue spans.
9
+ *
10
+ * So there is now an easy path: call this ONCE at module scope, mount what
11
+ * comes back. The flat exports stay — they are the escape hatch, and the
12
+ * headless story proves they still work.
13
+ *
14
+ * ## Zero provider names
15
+ *
16
+ * Nothing in this file, or in anything it returns, names a vendor. Every branch
17
+ * is decided by the server-published `tokenization` / `methods` /
18
+ * `customerSchema`. The only place a name exists at all is as an OPAQUE KEY:
19
+ * `chain[].provider`, looked up in the tokenizer registry and used verbatim as
20
+ * a `tokensByProvider` key. A host never types one.
21
+ */
22
+ import type { ComponentType, ReactNode } from "react";
23
+
24
+ import type { SavedCard } from "../card";
25
+ import type { CheckoutComponents } from "../components/checkout/ui";
26
+ import type { CheckoutCartView } from "../components/checkout/checkout-flow";
27
+ import type {
28
+ BuyerContact,
29
+ BuyerInfo,
30
+ ChargeCardInput,
31
+ ChargeOutcome,
32
+ CheckoutOrder,
33
+ CheckoutProviderConfig,
34
+ ComandaCheckout,
35
+ CreateOrderRequest,
36
+ CreateOrderResult,
37
+ OrderStatus,
38
+ PaymentMethod,
39
+ } from "../components/checkout/types";
40
+ import type { CheckoutTransport } from "../components/checkout/transport";
41
+ import type { useCheckoutController } from "../components/checkout/use-checkout-controller";
42
+ import type { Result } from "../result";
43
+
44
+ import type { CheckoutCopyFE } from "./copy";
45
+
46
+ /** The host's remedy on the unavailable screen, and its veto over a live chain. */
47
+ export interface CheckoutAvailability {
48
+ /**
49
+ * The host's own answer to "may this store take money right now?".
50
+ *
51
+ * OR'd with the chain, never swapped for it. A store with a working provider
52
+ * chain that has switched online payments OFF is invisible to `/config` —
53
+ * the chain is non-empty and the checkout would happily offer a picker it
54
+ * will not honour. That fact lives in the host, so the host votes.
55
+ */
56
+ payable: boolean;
57
+ /** What the buyer can do instead, when there is something. */
58
+ remedy?: { label: string; onSelect(): void };
59
+ }
60
+
61
+ /** Everything the flow needs FROM its host that is not a money rule. */
62
+ export interface CheckoutPorts {
63
+ /** Raise the payable + first charge. Same contract as today's `createOrder`. */
64
+ createPayable(input: CreateOrderRequest): Promise<CreateOrderResult>;
65
+ /** Persist the buyer's contact under the "salvar meus dados" consent. */
66
+ saveBuyerContact?(contact: BuyerContact): void;
67
+ /** Leave checkout for the host's menu/catalog. */
68
+ exitToCatalog(): void;
69
+ /** The payable settled PAID — the host re-reads whatever the server emptied. */
70
+ onPaid?(): void;
71
+ /**
72
+ * Hosted handover / 3-DS. Defaults to `window.location.assign`. A port
73
+ * because the destination is ANOTHER ORIGIN — never the host's router — and
74
+ * some hosts must log or confirm the departure.
75
+ */
76
+ navigate?(url: string): void;
77
+ /** The remedy shown on the no-provider screen, AND the host's veto. */
78
+ useAvailability?(): CheckoutAvailability;
79
+ }
80
+
81
+ /** What `createPaymentFlows` is configured with. */
82
+ export interface PaymentFlowsConfig {
83
+ /** Where the `createPaymentFlowsBE` mount lives. Default `/api/checkout`. */
84
+ transport?: CheckoutTransport;
85
+
86
+ /**
87
+ * The store being paid. A HOOK because the host's router owns it: taking a
88
+ * value here would freeze the slug of whichever store loaded first onto every
89
+ * checkout the page ever renders.
90
+ */
91
+ useScope?(): { tenantSlug?: string };
92
+ /** The cart, reduced to display facts. Never money math. */
93
+ useCart(): CheckoutCartView;
94
+ /** The buyer's saved details, and whether a CPF is already on file. */
95
+ useBuyerDefaults?(): { buyer?: BuyerInfo; taxIdOnFile?: boolean; pending?: boolean };
96
+ /** Present ⇒ this checkout settles a comanda rather than the cart. */
97
+ useComanda?(): ComandaCheckout | null;
98
+
99
+ /** Design-system slots, filled ONCE instead of per screen. */
100
+ components?: Partial<CheckoutComponents>;
101
+
102
+ /** The host's domain, as ports. Nothing here is a money rule. */
103
+ ports: CheckoutPorts;
104
+
105
+ polling?: { intervalMs?: number; cardMaxPolls?: number };
106
+ // NO `tokenization: { mintTimeoutMs }` here yet, deliberately. It was
107
+ // declared and never threaded to the mint path, so a host could set a
108
+ // deadline, believe the chain honoured it, and get none — config that lies is
109
+ // worse than config that is absent. Landing it for real needs the answer to
110
+ // "what happens WHEN it fires": a timed-out mint must decide whether the walk
111
+ // advances to the next entry or the whole charge refuses, and that is a money
112
+ // rule (FUT-563), not a wire-up.
113
+ copy?: Partial<CheckoutCopyFE>;
114
+ /** Host content under the paid receipt (the storefront's PWA install invite). */
115
+ confirmation?: { extra?: ReactNode };
116
+ /**
117
+ * Warnings the host reports (Sentry). Default SILENT — never `console`: a
118
+ * library that writes to a buyer's console tells them nothing and tells the
119
+ * host nothing either.
120
+ */
121
+ onWarning?(line: string, context?: Record<string, unknown>): void;
122
+ }
123
+
124
+ /** The flow controller a hand-composing host drives itself. */
125
+ export type CheckoutController = ReturnType<typeof useCheckoutController>;
126
+
127
+ /** The pre-bound fetch clients — same shapes as the free functions. */
128
+ export interface BoundCheckoutClient {
129
+ getConfig(tenantSlug: string): Promise<Result<CheckoutProviderConfig>>;
130
+ getStatus(ref: string): Promise<Result<OrderStatus>>;
131
+ charge(input: ChargeCardInput): Promise<Result<ChargeOutcome>>;
132
+ listInstruments(tenantSlug?: string): Promise<SavedCard[]>;
133
+ refreshBrowserKey(input: { orderId: string }): Promise<Result<{ publicKey: string | null }>>;
134
+ }
135
+
136
+ /** What the schema-derived buyer form renders. */
137
+ export interface BuyerDetailsProps {
138
+ value: BuyerInfo;
139
+ onChange(b: BuyerInfo): void;
140
+ /** Narrows the chain's declaration to this method (FUT-595); `null` ⇒ union. */
141
+ method: PaymentMethod | null;
142
+ onContinue(): void;
143
+ /** A server refusal to echo onto the offending input (MISSING_BUYER_FIELD). */
144
+ error?: { field: "cpf" | "email" | "name" | "phone"; message: string } | null;
145
+ }
146
+
147
+ /** The screens a host may nest itself. Every one works standalone. */
148
+ export interface CheckoutScreens {
149
+ MethodChoice: ComponentType<{ value: PaymentMethod | null; onChange(m: PaymentMethod): void }>;
150
+ BuyerDetails: ComponentType<BuyerDetailsProps>;
151
+ CardEntry: ComponentType<{ payable: CheckoutOrder; onResolved(s: OrderStatus): void }>;
152
+ PixPayment: ComponentType<{ payable: CheckoutOrder; onResolved(s: OrderStatus): void }>;
153
+ HostedHandoff: ComponentType<{ url: string; payable: CheckoutOrder; onCancel?(): void }>;
154
+ HostedReturn: ComponentType<{ onResolved(s: OrderStatus): void }>;
155
+ PaymentStatus: ComponentType<{ status: OrderStatus | null; payable?: CheckoutOrder | null }>;
156
+ PaymentsUnavailable: ComponentType<Record<string, never>>;
157
+ PayerSummary: ComponentType<{ buyer: BuyerInfo; onEdit?(): void }>;
158
+ SavedCards: ComponentType<{ selection: string; onSelect(id: string): void }>;
159
+ EmptyCart: ComponentType<Record<string, never>>;
160
+ }
161
+
162
+ /** The fetched store protocol, plus whether it is still in flight. */
163
+ export interface CheckoutConfigState {
164
+ config: CheckoutProviderConfig | null;
165
+ pending: boolean;
166
+ }
167
+
168
+ /** What `createPaymentFlows` returns. */
169
+ export interface PaymentFlows {
170
+ /** THE mount: a complete buyer checkout in one line. */
171
+ Checkout: ComponentType<{ comanda?: ComandaCheckout | null }>;
172
+ /** Slots + transport + scope + the fetched config, for a nesting host. */
173
+ Provider: ComponentType<{ children: ReactNode; config?: CheckoutProviderConfig | null }>;
174
+ screens: CheckoutScreens;
175
+ /** The flow controller, pre-bound to the ports — the easy path is not the only path. */
176
+ useCheckout(): CheckoutController;
177
+ useCheckoutConfig(): CheckoutConfigState;
178
+ client: BoundCheckoutClient;
179
+ }
package/src/index.ts CHANGED
@@ -48,6 +48,39 @@ export {
48
48
  type CheckoutCartView,
49
49
  type CheckoutFlowProps,
50
50
  } from './components/checkout/checkout-flow';
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // The MOUNTED buyer checkout (FUT-741) — `createPaymentFlows` returns every
54
+ // screen pre-bound to one transport, one scope, one slot table and one set of
55
+ // host ports. Additive: everything above and below stays exported, and the
56
+ // hand-composing path is unchanged.
57
+ // ---------------------------------------------------------------------------
58
+ export { createPaymentFlows } from './flows/create-payment-flows';
59
+ export {
60
+ DEFAULT_CHECKOUT_COPY_FE,
61
+ type CheckoutCopyFE,
62
+ } from './flows/copy';
63
+ export {
64
+ type BoundCheckoutClient,
65
+ type BuyerDetailsProps,
66
+ type CheckoutAvailability,
67
+ type CheckoutConfigState,
68
+ type CheckoutController,
69
+ type CheckoutPorts,
70
+ type CheckoutScreens,
71
+ type PaymentFlows,
72
+ type PaymentFlowsConfig,
73
+ } from './flows/types';
74
+ export {
75
+ buyerFieldsFor,
76
+ fieldSatisfied,
77
+ } from './components/checkout/buyer-fields';
78
+ export {
79
+ createCheckoutClient,
80
+ DEFAULT_CHECKOUT_BASE_URL,
81
+ type CheckoutClient,
82
+ type CheckoutTransport,
83
+ } from './components/checkout/transport';
51
84
  export { type CheckoutHostPorts } from './components/checkout/use-checkout-controller';
52
85
  export { PaymentsUnavailable } from './components/checkout/payments-unavailable';
53
86
  export { fetchCheckoutConfig } from './components/checkout/client';
@@ -70,6 +103,8 @@ export {
70
103
  type BuyerContact,
71
104
  type BuyerField,
72
105
  type BuyerInfo,
106
+ type CheckoutChainLink,
107
+ type CheckoutCustomerField,
73
108
  type CheckoutError,
74
109
  type CheckoutOrder,
75
110
  type CheckoutProviderConfig,