@12-apps/payments-frontend 3.14.0 → 3.15.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 +6 -3
- package/src/flows/create-payments-settings.tsx +67 -0
- package/src/index.ts +2 -0
- package/src/manifest/index.ts +74 -0
- package/src/manifest/web.ts +79 -0
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@12-apps/payments-frontend",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.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": {
|
|
7
7
|
".": "./src/index.ts",
|
|
8
|
-
"./locales": "./src/locales.ts"
|
|
8
|
+
"./locales": "./src/locales.ts",
|
|
9
|
+
"./manifest": "./src/manifest/index.ts",
|
|
10
|
+
"./manifest/web": "./src/manifest/web.ts",
|
|
11
|
+
"./package.json": "./package.json"
|
|
9
12
|
},
|
|
10
13
|
"scripts": {
|
|
11
14
|
"clean": "rm -rf node_modules coverage storybook-static",
|
|
@@ -18,7 +21,7 @@
|
|
|
18
21
|
"storybook:build": "storybook build"
|
|
19
22
|
},
|
|
20
23
|
"dependencies": {
|
|
21
|
-
"@12-apps/payments-backend": "^4.19.
|
|
24
|
+
"@12-apps/payments-backend": "^4.19.1",
|
|
22
25
|
"react-qr-code": "^2.2.0"
|
|
23
26
|
},
|
|
24
27
|
"peerDependencies": {
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createWebPaymentsSettings` — the MERCHANT half of this package, mounted
|
|
3
|
+
* rather than composed.
|
|
4
|
+
*
|
|
5
|
+
* `createPaymentFlows` already does this for the buyer: one call, one bound
|
|
6
|
+
* transport, and the host mounts what comes back. The owner's settings page
|
|
7
|
+
* had no equivalent, so every host imported `PaymentProviderSettings` and
|
|
8
|
+
* threaded the same `PaymentsSettingsClient` into it at the call site — the
|
|
9
|
+
* one object that is genuinely per-tenant and genuinely built once. This
|
|
10
|
+
* binds it, and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* ## WHAT STAYS A PROP, and why
|
|
13
|
+
*
|
|
14
|
+
* **`copy`.** Every sentence this surface renders follows the READER's
|
|
15
|
+
* locale, which a host resolves per render. Binding the pack at factory time
|
|
16
|
+
* would pin the screen to whichever language was in effect when the host
|
|
17
|
+
* built it — a language switch that changes the chrome and leaves the
|
|
18
|
+
* settings page behind.
|
|
19
|
+
*
|
|
20
|
+
* **`prepareConnect`, `selectedProvider` / `onProviderChange`,
|
|
21
|
+
* `initialProvider`, `onChanged`.** The OAuth CSRF state is minted against
|
|
22
|
+
* the host's admin session; which provider is open may live in the host's
|
|
23
|
+
* URL. Both are the host's, per render, and a factory that froze them would
|
|
24
|
+
* make the page uncontrollable.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { ComponentType, JSX } from "react";
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
PaymentProviderSettings,
|
|
31
|
+
type PaymentProviderSettingsProps,
|
|
32
|
+
} from "../components/PaymentProviderSettings";
|
|
33
|
+
import type { PaymentsSettingsClient } from "../client";
|
|
34
|
+
|
|
35
|
+
/** What a host binds ONCE: the settings port. */
|
|
36
|
+
export interface PaymentsSettingsWebConfig {
|
|
37
|
+
/**
|
|
38
|
+
* The host's settings transport — its origin, its tenancy, its auth.
|
|
39
|
+
* `createPaymentsSettingsClient` builds one; a host with its own
|
|
40
|
+
* authenticated fetch may implement the interface directly.
|
|
41
|
+
*/
|
|
42
|
+
client: PaymentsSettingsClient;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The settings page's remaining props once the port is bound. */
|
|
46
|
+
export type BoundPaymentsSettingsProps = Omit<PaymentProviderSettingsProps, "client">;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The bound surface. `page` is a component TYPE, so a host must hold the
|
|
50
|
+
* object across renders — the wiring consumer's binder does that once per
|
|
51
|
+
* adoption.
|
|
52
|
+
*/
|
|
53
|
+
export interface PaymentsSettingsSurface {
|
|
54
|
+
/** The whole provider-settings page: list, connection, credentials, priority. */
|
|
55
|
+
page: ComponentType<BoundPaymentsSettingsProps>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Build the owner's payment-settings surface for a host. */
|
|
59
|
+
export function createWebPaymentsSettings(
|
|
60
|
+
config: PaymentsSettingsWebConfig,
|
|
61
|
+
): PaymentsSettingsSurface {
|
|
62
|
+
const { client } = config;
|
|
63
|
+
const Page = (props: BoundPaymentsSettingsProps): JSX.Element => (
|
|
64
|
+
<PaymentProviderSettings {...props} client={client} />
|
|
65
|
+
);
|
|
66
|
+
return { page: Page };
|
|
67
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -301,6 +301,8 @@ export {
|
|
|
301
301
|
PaymentProviderSettings,
|
|
302
302
|
type PaymentProviderSettingsProps,
|
|
303
303
|
} from './components/PaymentProviderSettings';
|
|
304
|
+
export { createWebPaymentsSettings } from './flows/create-payments-settings';
|
|
305
|
+
export type { BoundPaymentsSettingsProps, PaymentsSettingsSurface, PaymentsSettingsWebConfig } from './flows/create-payments-settings';
|
|
304
306
|
|
|
305
307
|
// ---------------------------------------------------------------------------
|
|
306
308
|
// The PLATFORM operations screens (FUT-479 / FUT-483, packaged by FUT-573) —
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@12-apps/payments-frontend/manifest` — the SHARED wiring manifests.
|
|
3
|
+
*
|
|
4
|
+
* UNTYPED pure data, unlike most sibling producer halves: the portability
|
|
5
|
+
* ruleset (`payments/no-host-imports`) allows no `@12-apps/wiring` import
|
|
6
|
+
* anywhere under `packages/payments/**`, type-only included — this package
|
|
7
|
+
* must vendor into a repo that has no wiring contract at all. The compliance
|
|
8
|
+
* run lives in the wiring suite's `payments-frontend-manifest.test.ts`
|
|
9
|
+
* instead, along a dependency edge that does exist, so a drift still fails a
|
|
10
|
+
* test run before any host sees it. That is exactly the arrangement
|
|
11
|
+
* `@12-apps/payments-backend`'s manifest already uses.
|
|
12
|
+
*
|
|
13
|
+
* TWO manifests, mirroring the backend's split for the same reason. The
|
|
14
|
+
* backend ships two route tables that must never merge — every library row is
|
|
15
|
+
* merchant-admin, every checkout row is the BUYER — and the browser half is
|
|
16
|
+
* the same product cut the same way:
|
|
17
|
+
*
|
|
18
|
+
* - **settings** is the OWNER's screen: which providers exist, which
|
|
19
|
+
* credentials are stored, which one is tried first. It mounts in an admin
|
|
20
|
+
* SPA, behind that host's admin session.
|
|
21
|
+
* - **checkout** is the SHOPPER's flow: methods, card entry, PIX, the hosted
|
|
22
|
+
* hand-off and the return leg. It mounts in a storefront SPA, for an
|
|
23
|
+
* anonymous visitor.
|
|
24
|
+
*
|
|
25
|
+
* One manifest would hand a host ONE surface config for two mounts that live
|
|
26
|
+
* in different applications, behind different gates, built from different
|
|
27
|
+
* ports — and would oblige the storefront to construct the owner's settings
|
|
28
|
+
* transport in order to render a checkout. Two make that impossible to
|
|
29
|
+
* express.
|
|
30
|
+
*
|
|
31
|
+
* ## THE NARROWINGS
|
|
32
|
+
*
|
|
33
|
+
* - **No `server` inventory on either.** There is no server half here; the
|
|
34
|
+
* HTTP surfaces are `@12-apps/payments-backend`'s, declared in its own
|
|
35
|
+
* manifest.
|
|
36
|
+
* - **No `db`, `permissions`, `mcp`, `env` or `e2e`.** This package stores
|
|
37
|
+
* nothing, advertises no tools and reads no environment; every
|
|
38
|
+
* authorization question is answered by the endpoints it talks to, and the
|
|
39
|
+
* packaged journeys ship in the SIBLING `@12-apps/payments-e2e` (a
|
|
40
|
+
* manifest must not declare an entry another package exports).
|
|
41
|
+
*
|
|
42
|
+
* `observability` names where a wiring host files each surface's browser
|
|
43
|
+
* reports. The package still binds no logger anywhere — it takes no
|
|
44
|
+
* observability dependency, by the same portability rule as above.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The OWNER's provider-settings screen. Same identity as the package,
|
|
49
|
+
* because it is the half a host adopting "payments-frontend" means by
|
|
50
|
+
* default.
|
|
51
|
+
*/
|
|
52
|
+
export const paymentsFrontendManifest = {
|
|
53
|
+
name: '@12-apps/payments-frontend',
|
|
54
|
+
contract: 1,
|
|
55
|
+
observability: { namespace: 'payments' },
|
|
56
|
+
web: ['surface', 'areas'],
|
|
57
|
+
} as const;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The SHOPPER's checkout flow. Its own identity so a host adopts it into the
|
|
61
|
+
* storefront SPA alone — and so a version bump can never widen the admin
|
|
62
|
+
* mount with a buyer screen nobody re-reviewed.
|
|
63
|
+
*
|
|
64
|
+
* The namespace matches the backend's buyer surface (`payments-checkout`)
|
|
65
|
+
* rather than `payments`: a failed checkout is one incident across the two
|
|
66
|
+
* halves, and filing the browser side under the merchant namespace is what
|
|
67
|
+
* makes a shopper's dead end and the charge behind it look unrelated.
|
|
68
|
+
*/
|
|
69
|
+
export const paymentsCheckoutFrontendManifest = {
|
|
70
|
+
name: '@12-apps/payments-checkout-ui',
|
|
71
|
+
contract: 1,
|
|
72
|
+
observability: { namespace: 'payments-checkout' },
|
|
73
|
+
web: ['surface', 'areas'],
|
|
74
|
+
} as const;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@12-apps/payments-frontend/manifest/web` — the web capabilities.
|
|
3
|
+
*
|
|
4
|
+
* UNTYPED pure data — see `./index` for why this package may not import the
|
|
5
|
+
* wiring contract, and where its compliance run lives instead.
|
|
6
|
+
*
|
|
7
|
+
* Each `surface.create` IS the package's existing factory, unchanged:
|
|
8
|
+
* `createWebPaymentsSettings` for the owner's screen and `createPaymentFlows`
|
|
9
|
+
* for the buyer's. Both return component TYPES, so the consumer's binder
|
|
10
|
+
* builds them ONCE per adoption — which is the memoisation rule every hand
|
|
11
|
+
* wiring carries as a comment today, and which matters more here than
|
|
12
|
+
* anywhere: rebuilding `createPaymentFlows` per render would rebuild the
|
|
13
|
+
* checkout transport under a shopper mid-payment.
|
|
14
|
+
*
|
|
15
|
+
* ## WHAT STAYS SURFACE CONFIG, deliberately
|
|
16
|
+
*
|
|
17
|
+
* The design-system slots (`CheckoutComponentsProvider`'s button, input,
|
|
18
|
+
* stepper, alert…) and `CheckoutHostPorts` are the config a host hands
|
|
19
|
+
* `createPaymentFlows`, and they stay exactly that. They are not capabilities
|
|
20
|
+
* to declare: a slot table is one host's design system, and a port is one
|
|
21
|
+
* host's cart, scope and settlement. The contract's `surface` capability is
|
|
22
|
+
* precisely the shape that carries them — `create(config)` — so declaring
|
|
23
|
+
* the factory declares the whole seam without naming a single host's answer.
|
|
24
|
+
*
|
|
25
|
+
* Likewise the COPY packs. Every sentence both surfaces render is a required
|
|
26
|
+
* prop with no package default (FUT-760), because a default would be one
|
|
27
|
+
* product's Portuguese compiled into every other product's checkout. They
|
|
28
|
+
* stay per-render props rather than factory config for the reason the estate
|
|
29
|
+
* separates the two: copy follows the READER's locale, and freezing it at
|
|
30
|
+
* bind time pins the surface to whichever language was in effect when the
|
|
31
|
+
* host built it.
|
|
32
|
+
*
|
|
33
|
+
* ## THE AREAS
|
|
34
|
+
*
|
|
35
|
+
* Suggestions, structurally — the host composes, reorders, relabels and
|
|
36
|
+
* vetoes at its single call site. Each carries one honest fact:
|
|
37
|
+
*
|
|
38
|
+
* - the settings screen belongs in the ADMIN area, as a routed page with a
|
|
39
|
+
* nav row (`testId: 'payments'` — the host maps its own icon and word);
|
|
40
|
+
* - the checkout belongs in the CLIENT area as a route with NO nav row. A
|
|
41
|
+
* checkout is reached from a cart, never from a menu, and a nav entry
|
|
42
|
+
* pointing at it is a link to an empty basket.
|
|
43
|
+
*
|
|
44
|
+
* No permission gates and no plan features on either: both are host
|
|
45
|
+
* vocabulary (this package depends on no RBAC and knows no plan catalog),
|
|
46
|
+
* and a package that guessed would be wrong for every host but the first.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import { createPaymentFlows } from '../flows/create-payment-flows';
|
|
50
|
+
import { createWebPaymentsSettings } from '../flows/create-payments-settings';
|
|
51
|
+
|
|
52
|
+
/** The OWNER's provider-settings surface — one routed page in the admin SPA. */
|
|
53
|
+
export const paymentsFrontendWebManifest = {
|
|
54
|
+
name: '@12-apps/payments-frontend',
|
|
55
|
+
surface: { create: createWebPaymentsSettings },
|
|
56
|
+
areas: [
|
|
57
|
+
{
|
|
58
|
+
area: 'admin',
|
|
59
|
+
routes: [{ path: 'config/payments', screen: 'page' }],
|
|
60
|
+
nav: [{ testId: 'payments', path: 'config/payments' }],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The SHOPPER's checkout surface. `screen: 'Checkout'` is the one-line mount
|
|
67
|
+
* `createPaymentFlows` returns; everything under `screens` is for a host
|
|
68
|
+
* composing its own pixels and is deliberately not routed here.
|
|
69
|
+
*/
|
|
70
|
+
export const paymentsCheckoutFrontendWebManifest = {
|
|
71
|
+
name: '@12-apps/payments-checkout-ui',
|
|
72
|
+
surface: { create: createPaymentFlows },
|
|
73
|
+
areas: [
|
|
74
|
+
{
|
|
75
|
+
area: 'client',
|
|
76
|
+
routes: [{ path: 'checkout', screen: 'Checkout' }],
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
} as const;
|