import * as React from 'react'; import { ComponentType, AnchorHTMLAttributes, ReactNode, ErrorInfo } from 'react'; import { FallbackProps } from 'react-error-boundary'; type LinkComponentProps = AnchorHTMLAttributes & { children?: ReactNode; }; type LinkComponent = ComponentType; /** * The UI frameworks a widget's UI layer can render with. * * - `shadcn` — the shadcn/Tailwind implementation. This is the default and the * implicit fallback, so existing consumers that select nothing keep rendering * shadcn. * - `tecton` — the Tecton implementation. * * Declared as an `as const` object (not a TypeScript `enum`) per repo * convention. */ declare const UIFramework: { readonly Shadcn: "shadcn"; readonly Tecton: "tecton"; }; type UIFramework = (typeof UIFramework)[keyof typeof UIFramework]; interface PaginationFooterLabels { rowsPerPageLabel: string; previousPageButton: string; nextPageButton: string; } /** * Every key of `T` optional, recursively, so a consumer can override one nested * label without restating its siblings. Defined locally because the repo has no * shared deep-partial type and does not depend on `type-fest`. */ type PartialDeep$3 = { [K in keyof T]?: T[K] extends object ? PartialDeep$3 : T[K]; }; interface CardsListColumnHeaderLabels { cardName: string; fundingAccount: string; cardholder: string; status: string; limit: string; } /** * Screen-reader-only copy naming the details sheet a row click opens. * * Both strings are invisible by design: the sheet's visible header belongs to * whatever the owner slots into it (`CardDetailsPanel`, via `CardsWidget`), and a * second visible title would duplicate it. They exist because the sheet is a * dialog, and a dialog without an accessible name is announced as nothing. */ interface CardsListDetailsSheetLabels { /** Accessible name for the sheet. */ title: string; /** Accessible description, announced after the name. */ description: string; } /** * Every user-facing string the cards list renders, including screen-reader-only * copy and the decorative separators. * * There is intentionally **no** card-type or card-status map here: the row * arrives with `typeLabel` and `statusLabel` already resolved, so the * `DIGITAL`/`PHYSICAL` and `PENDING_ACTIVATION`/`ACTIVE`/`LOCKED`/`CLOSED` maps * live in `shared/feature` keyed on the generated types (EMBD-4404 amendment; * see `statusBadge.ts`). That is also where the "label keys carry the code term, * values carry the copy" rule applies — `digital`, never `virtual`, so a later * wording change is not a breaking rename. */ interface CardsListLabels { title: string; /** Accessible name for the list region. */ regionLabel: string; columnHeaders: CardsListColumnHeaderLabels; /** Screen-reader name for the unheaded trailing row-actions column. */ rowActionsColumn: string; showMyCardsToggle: string; createCardButton: string; activateButton: string; /** Accessible name for a row's Activate button; the card name is appended. */ activateButtonForCard: string; /** Accessible name for a row's open-details control; card name appended. */ selectCardButton: string; /** Separator between a card's nickname and its last four digits. */ cardNameSeparator: string; /** Stands in for the limit when a card has none set. */ noLimit: string; /** Announced while a page of cards is loading. */ loadingLabel: string; emptyTitle: string; emptyDescription: string; errorTitle: string; errorDescription: string; retryButton: string; pagination: PaginationFooterLabels; /** * Copy for the details sheet a row click opens. Rendered by * `CardsListDetailsSheet` rather than by the table, but part of this surface * because it is one screen and one `labels` prop — the same reason `pagination` * sits here for a footer that lives in `shared/ui`. */ detailsSheet: CardsListDetailsSheetLabels; /** * Screen-reader copy for the same sheet when Create card is slotted in, rather * than a selected card's details. Same chrome, different accessible name. */ createSheet: CardsListDetailsSheetLabels; } type AuthToken = string | undefined; interface Auth { /** * Which part of the request do we use to send the auth? * * @default 'header' */ in?: 'header' | 'query' | 'cookie'; /** * A unique identifier for the security scheme. * * Defined only when there are multiple security schemes whose `Auth` * shape would otherwise be identical. */ key?: string; /** * Header or query parameter name. * * @default 'Authorization' */ name?: string; scheme?: 'basic' | 'bearer'; type: 'apiKey' | 'http'; } interface SerializerOptions { /** * @default true */ explode: boolean; style: T; } type ArrayStyle = 'form' | 'spaceDelimited' | 'pipeDelimited'; type ObjectStyle = 'form' | 'deepObject'; type QuerySerializer = (query: Record) => string; type BodySerializer = (body: unknown) => unknown; type QuerySerializerOptionsObject = { allowReserved?: boolean; array?: Partial>; object?: Partial>; }; type QuerySerializerOptions = QuerySerializerOptionsObject & { /** * Per-parameter serialization overrides. When provided, these settings * override the global array/object settings for specific parameter names. */ parameters?: Record; }; type HttpMethod = 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace'; type Client$1 = { /** * Returns the final request URL. */ buildUrl: BuildUrlFn; getConfig: () => Config; request: RequestFn; setConfig: (config: Config) => Config; } & { [K in HttpMethod]: MethodFn; } & ([SseFn] extends [never] ? { sse?: never; } : { sse: { [K in HttpMethod]: SseFn; }; }); interface Config$1 { /** * Auth token or a function returning auth token. The resolved value will be * added to the request payload as defined by its `security` array. */ auth?: ((auth: Auth) => Promise | AuthToken) | AuthToken; /** * A function for serializing request body parameter. By default, * {@link JSON.stringify()} will be used. */ bodySerializer?: BodySerializer | null; /** * An object containing any HTTP headers that you want to pre-populate your * `Headers` object with. * * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more} */ headers?: RequestInit['headers'] | Record; /** * The request method. * * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more} */ method?: Uppercase; /** * A function for serializing request query parameters. By default, arrays * will be exploded in form style, objects will be exploded in deepObject * style, and reserved characters are percent-encoded. * * This method will have no effect if the native `paramsSerializer()` Axios * API function is used. * * {@link https://swagger.io/docs/specification/serialization/#query View examples} */ querySerializer?: QuerySerializer | QuerySerializerOptions; /** * A function validating request data. This is useful if you want to ensure * the request conforms to the desired shape, so it can be safely sent to * the server. */ requestValidator?: (data: unknown) => Promise; /** * A function transforming response data before it's returned. This is useful * for post-processing data, e.g., converting ISO strings into Date objects. */ responseTransformer?: (data: unknown) => Promise; /** * A function validating response data. This is useful if you want to ensure * the response conforms to the desired shape, so it can be safely passed to * the transformers and returned to the user. */ responseValidator?: (data: unknown) => Promise; } type ServerSentEventsOptions = Omit & Pick & { /** * Fetch API implementation. You can use this option to provide a custom * fetch instance. * * @default globalThis.fetch */ fetch?: typeof fetch; /** * Implementing clients can call request interceptors inside this hook. */ onRequest?: (url: string, init: RequestInit) => Promise; /** * Callback invoked when a network or parsing error occurs during streaming. * * This option applies only if the endpoint returns a stream of events. * * @param error The error that occurred. */ onSseError?: (error: unknown) => void; /** * Callback invoked when an event is streamed from the server. * * This option applies only if the endpoint returns a stream of events. * * @param event Event streamed from the server. * @returns Nothing (void). */ onSseEvent?: (event: StreamEvent) => void; serializedBody?: RequestInit['body']; /** * Default retry delay in milliseconds. * * This option applies only if the endpoint returns a stream of events. * * @default 3000 */ sseDefaultRetryDelay?: number; /** * Maximum number of retry attempts before giving up. */ sseMaxRetryAttempts?: number; /** * Maximum retry delay in milliseconds. * * Applies only when exponential backoff is used. * * This option applies only if the endpoint returns a stream of events. * * @default 30000 */ sseMaxRetryDelay?: number; /** * Optional sleep function for retry backoff. * * Defaults to using `setTimeout`. */ sseSleepFn?: (ms: number) => Promise; url: string; }; interface StreamEvent { data: TData; event?: string; id?: string; retry?: number; } type ServerSentEventsResult = { stream: AsyncGenerator ? TData[keyof TData] : TData, TReturn, TNext>; }; type ErrInterceptor = (error: Err, /** response may be undefined due to a network error where no response object is produced */ response: Res | undefined, /** request may be undefined, because error may be from building the request object itself */ request: Req | undefined, options: Options) => Err | Promise; type ReqInterceptor = (request: Req, options: Options) => Req | Promise; type ResInterceptor = (response: Res, request: Req, options: Options) => Res | Promise; declare class Interceptors { fns: Array; clear(): void; eject(id: number | Interceptor): void; exists(id: number | Interceptor): boolean; getInterceptorIndex(id: number | Interceptor): number; update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false; use(fn: Interceptor): number; } interface Middleware { error: Interceptors>; request: Interceptors>; response: Interceptors>; } type ResponseStyle = 'data' | 'fields'; interface Config extends Omit, Config$1 { /** * Base URL for all requests made by this client. */ baseUrl?: T['baseUrl']; /** * Fetch API implementation. You can use this option to provide a custom * fetch instance. * * @default globalThis.fetch */ fetch?: typeof fetch; /** * Please don't use the Fetch client for Next.js applications. The `next` * options won't have any effect. * * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead. */ next?: never; /** * Return the response data parsed in a specified format. By default, `auto` * will infer the appropriate method from the `Content-Type` response header. * You can override this behavior with any of the {@link Body} methods. * Select `stream` if you don't want to parse response data at all. * * @default 'auto' */ parseAs?: 'arrayBuffer' | 'auto' | 'blob' | 'formData' | 'json' | 'stream' | 'text'; /** * Should we return only data or multiple fields (data, error, response, etc.)? * * @default 'fields' */ responseStyle?: ResponseStyle; /** * Throw an error instead of returning it in the response? * * @default false */ throwOnError?: T['throwOnError']; } interface RequestOptions extends Config<{ responseStyle: TResponseStyle; throwOnError: ThrowOnError; }>, Pick, 'onRequest' | 'onSseError' | 'onSseEvent' | 'sseDefaultRetryDelay' | 'sseMaxRetryAttempts' | 'sseMaxRetryDelay'> { /** * Any body that you want to add to your request. * * {@link https://developer.mozilla.org/docs/Web/API/fetch#body} */ body?: unknown; path?: Record; query?: Record; /** * Security mechanism(s) to use for the request. */ security?: ReadonlyArray; url: Url; } interface ResolvedRequestOptions extends RequestOptions { headers: Headers; serializedBody?: string; } type RequestResult = ThrowOnError extends true ? Promise ? TData[keyof TData] : TData : { data: TData extends Record ? TData[keyof TData] : TData; request: Request; response: Response; }> : Promise ? TData[keyof TData] : TData) | undefined : ({ data: TData extends Record ? TData[keyof TData] : TData; error: undefined; } | { data: undefined; error: TError extends Record ? TError[keyof TError] : TError; }) & { /** request may be undefined, because error may be from building the request object itself */ request?: Request; /** response may be undefined, because error may be from building the request object itself or from a network error */ response?: Response; }>; interface ClientOptions$1 { baseUrl?: string; responseStyle?: ResponseStyle; throwOnError?: boolean; } type MethodFn = (options: Omit, 'method'>) => RequestResult; type SseFn = (options: Omit, 'method'>) => Promise>; type RequestFn = (options: Omit, 'method'> & Pick>, 'method'>) => RequestResult; type BuildUrlFn = ; query?: Record; url: string; }>(options: TData & Options) => string; type Client = Client$1 & { interceptors: Middleware; }; interface TDataShape { body?: unknown; headers?: unknown; path?: unknown; query?: unknown; url: string; } type OmitKeys = Pick>; type Options = OmitKeys, 'body' | 'path' | 'query' | 'url'> & ([TData] extends [never] ? unknown : Omit); type ClientOptions = { baseUrl: 'https://api.stage.tesouro.com' | 'https://api.sandbox.stage.tesouro.com' | 'https://api.stage.business-banking.app' | 'https://api.tesouro.com' | 'https://api.sandbox.tesouro.com' | 'https://api.business-banking.app' | (string & {}); }; type CreditCardStatus = 'PENDING_ACTIVATION' | 'ACTIVE' | 'LOCKED' | 'CLOSED'; type CreditCardType = 'DIGITAL' | 'PHYSICAL'; type EmbeddedClient = Client; type ExtractLiterals = T extends string ? string extends T ? never : T : never; type BaseUrl = ExtractLiterals; /** * The implementation a widget renders with. * * - `native` — the Tesouro-native implementation. This is the default and the * implicit fallback, so consumers that select nothing keep rendering native. * - `monite` — the Monite SDK implementation. * * Declared as an `as const` object (not a TypeScript `enum`) per repo * convention. */ declare const Implementation: { readonly Native: "native"; readonly Monite: "monite"; }; type Implementation = (typeof Implementation)[keyof typeof Implementation]; /** * The settable fields of the widget config cascade. * * This is the type accepted by {@link setGlobalWidgetConfig} and all provider props. * It intentionally excludes `initResponse`, which is populated automatically by the * provider after a successful fetch and must never be set manually. * * The `null` vs `undefined` distinction on `widgetToken` and `organizationId` is intentional: * - `undefined` — not set at this level; inherit from the nearest ancestor or global store. * - `null` — explicitly cleared; downstream sees "no value" even if an ancestor had one * (e.g. after logout or deliberate de-scoping). * * @see {@link WidgetConfig} for the resolved output type (includes `initResponse`) * @see {@link RootWidgetProvider} * @see {@link WidgetProvider} * @see {@link setGlobalWidgetConfig} */ interface WidgetConfigInput { /** * Base URL of the Tesouro embedded API (e.g. `"https://api.tesouro.com"`). * * When omitted the nearest ancestor's `baseUrl` or the global store value is used. * Changing this recreates the underlying HTTP client so all subsequent requests * go to the new host. */ baseUrl?: BaseUrl; /** * Bearer token used to authenticate widget requests. * * Injected as `Authorization: Bearer ` on every outgoing request via an * interceptor on the scoped HTTP client. Token updates are picked up immediately * without recreating the client. * * - `string` — send this token on all requests from this level downward. * - `null` — explicitly cleared; no auth header is sent and fetching is suppressed. * - `undefined` — not set at this level; inherit from the nearest ancestor or global store. */ widgetToken?: string | null; /** * Organization ID forwarded as the `x-organization-id` request header. * * Passed through {@link EmbedApiProvider} context rather than the auth interceptor, * so individual data-access hooks can opt in per-request. * * - `string` — use this organization for downstream data requests. * - `null` — explicitly cleared; queries that require an org ID will be disabled. * - `undefined` — not set at this level; inherit from the nearest ancestor or global store. * * When `undefined` across the **whole** cascade (no prop, no ancestor, no global * value), the resolved org defaults to the loaded `initResponse.organizationId` * (see {@link WidgetConfig.initResponse}) once the widget-init fetch settles. This * is the lowest-priority fallback — any explicit `string` or `null` at any cascade * level wins, and an explicit `null` is preserved and never falls back. * * Only an **explicit** ancestor org is inherited. An ancestor's *init-derived* * default does not propagate into a descendant that owns its own fetch (its own * `baseUrl`/`widgetToken`); such a descendant defaults to its own * `initResponse.organizationId` instead, so it never sends an ancestor's org with * its own token. */ organizationId?: string | null; /** * Optional post-creation hook for the scoped HTTP client. * * Called once after the provider creates its scoped {@link EmbeddedClient} and * applies the built-in `Authorization: Bearer` interceptor. Receives the * fully-configured client and must return the client to be used for the lifetime of * this provider level — either the same instance (with additional interceptors * attached) or a new client entirely. * * **Order:** The built-in auth interceptor is always applied first. `configClient` * is called on top of it, so any interceptors you add here run after auth is set. * * **Any prop triggers a scoped client.** A {@link WidgetProvider} creates its own * scoped client whenever any prop is set — including `configClient` alone, without * `baseUrl` or `widgetToken`. Only a fully props-free pass-through provider skips * client creation and never calls this function. * * **Stability:** The function reference is included in the client creation memo's * dependency array. Passing an unstable (inline) function recreates the client on * every render. Stabilize with `useCallback` or define the function outside the * component. * * **Cascade:** Inherits from the nearest ancestor when `undefined`. A child * {@link WidgetProvider} that creates its own scoped client will use the resolved * `configClient` from the cascade unless it provides its own override. * * @example * ```tsx * const addLogging = useCallback( * (client: EmbeddedClient) => { * client.interceptors.request.use((req) => { * console.log('[widget]', req.method, req.url); * return req; * }); * return client; * }, * [], * ); * * * * * ``` */ configClient?: (client: EmbeddedClient) => EmbeddedClient; /** * Overrides the widget-gateway routing decision for the scoped HTTP client. * * Any caller reaching the Tesouro API with a widget token must route data * requests through the widget gateway: prefix the path with * `/api/widget-gateway/proxy` and carry the token as `X-Widget-Token`. The * provider applies both automatically per request when the request origin is * a known Tesouro API host (`WIDGET_GATEWAY_HOSTS`, derived from the * generated `ClientOptions['baseUrl']`); `/api/widget-gateway/*` paths (the * init round-trip) always pass through untouched. * * - `undefined` — decide from the request origin, as above. Inherits from * the nearest ancestor or global store like every other config field. * - `true` — always apply the rewrite, even for an unlisted base URL (e.g. a * custom domain in front of the gateway). * - `false` — never apply it. For hosts that route widget requests their own * way, such as a same-origin BFF whose `configClient` retargets every * request. * * Independent of {@link configClient}: a host that only adds a header keeps * the built-in routing, and the built-in interceptor runs before any * `configClient` interceptor. */ gatewayRouting?: boolean; /** * Component the embedded widgets should render in place of plain `` tags. * * Pass e.g. Next.js's `Link` to make in-app navigation use the host router. * Cascades like other config: provider prop > nearest ancestor > global store. * When no value is set anywhere, widgets fall back to a plain `` element. */ linkComponent?: LinkComponent; /** * Which UI framework the widget UI layer should render with. * * Lets a consuming context bind widgets to either the shadcn/Tailwind or the * Tecton implementation behind the same outward-facing API. The selection is * a presentation concern only — it cascades through the provider tree exactly * like {@link linkComponent} and is read by UI libraries via `useUIFramework`; * it never appears in any widget's feature-library or component props. * * - `'shadcn'` — the shadcn/Tailwind implementation. * - `'tecton'` — the Tecton implementation. * - `null` / `undefined` — not set at this level; inherit from the nearest * ancestor or global store, falling back to `shadcn` when unset everywhere. * `shadcn` is the implicit default, so existing consumers need no changes. */ uiFramework?: UIFramework | null; /** * Which implementation a widget renders with. * * Lets a consuming context bind widgets to either the Tesouro-native or the * Monite SDK implementation behind the same outward-facing API. It cascades * through the provider tree exactly like {@link linkComponent} and * {@link uiFramework} — provider prop > nearest ancestor > global store — and * is read via `useImplementation`. * * - `'native'` — the Tesouro-native implementation. * - `'monite'` — the Monite SDK implementation. * - `null` / `undefined` — not set at this level; inherit from the nearest * ancestor or global store, falling back to `native` when unset everywhere. * `native` is the implicit default, so existing consumers need no changes. */ implementation?: Implementation | null; } /** * Props shared by every analytics-owner-capable widget provider. * * Combines the full settable cascade ({@link WidgetConfigInput}) with the * analytics opt-out honored by analytics owners. Both {@link RootWidgetProvider} * and {@link WidgetProvider} build their public props on top of this; the latter * adds error-boundary props of its own. * * @see {@link WidgetConfigInput} for per-field cascade and `null` vs omitted semantics */ interface WidgetProviderBaseProps extends WidgetConfigInput { /** * Opt out of all analytics capture and prevent PostHog from loading. Default `true`. * * Honored only by an analytics **owner** — a {@link RootWidgetProvider} or a * standalone {@link WidgetProvider} with no parent provider. When `false`, * owner-bound `track` calls in this subtree become no-ops and the PostHog * installer is never dynamically imported for this owner's environment. * Setting it on a nested {@link WidgetProvider} is ignored in v1 (a one-time * `console.warn` is emitted to make the no-op discoverable). */ analytics?: boolean; } /** * Props for {@link WidgetProvider}. * * All fields are optional. When **all** are omitted the provider is a transparent * pass-through: no fetch is issued and all resolved values cascade unchanged from * the nearest ancestor. */ interface WidgetProviderProps extends WidgetProviderBaseProps { /** * Fallback rendered when a render-time exception is caught inside this * provider's subtree. Pass either a `ReactNode` (rendered directly) or a * render-prop receiving `{ error, resetErrorBoundary }` from * `react-error-boundary`. Default is a plain `role="alert"` div with * generic copy from `DEFAULT_LABELS.errorBoundaryFallback`. */ errorFallback?: ReactNode | ((props: FallbackProps) => ReactNode); /** * Called once when the boundary catches an error, before the fallback * renders. Use for telemetry / Sentry / partner logging. Exceptions * thrown from `onError` propagate per `react-error-boundary` semantics. */ onError?: (error: unknown, info: ErrorInfo) => void; /** * Accept surface shown when an ACTIVE user owes a new disclosure version. * Pass `` (no invite * credentials). Cascades like `linkComponent`. Omit on INVITED — that * path still uses invite-link `invitationToken`/`userId` on the host * landing page. WidgetProvider cannot import the widget itself (cycle). */ disclosuresAcceptance?: ReactNode; } /** * Which issuing product a card belongs to. A card list shows exactly one * program at a time, and the value selects the endpoint the data-access layer * calls: `credit` → `/embedded-banking/v1/credit-cards`, `debit` → * `/embedded-banking/v1/debit-cards`. * * Defined here rather than in either widget because `CardsWidget` and * `CardDetailsWidget` both publish it as a required public prop. Declared * inline in each, the literal would become public API twice with no single * definition — and `cards-widget/ui` ↔ `card-details-widget/ui` imports are * lint-banned while the reverse feature import would be an Nx cycle, so * `shared/feature` is the only home that serves both without duplication. * * Deliberately **not** the generated `CardTypeEnum` (`credit | debit | prepaid * | unknown`), which greps as an exact match for this concept but belongs to * the unrelated snake_case third-party schema family (its sibling fields are * `card_type`, `last4`, `background_color`) and carries two members neither * widget supports. In this codebase "card type" is the DIGITAL/PHYSICAL form * factor instead — see `CardType` in `./cardPresentation`. * * Const-object-plus-type rather than a bare union, mirroring `UIFramework` in * `shared/ui` — the other two-member literal that ships as a public prop type. */ declare const CardProgram: { readonly Credit: "credit"; readonly Debit: "debit"; }; type CardProgram = (typeof CardProgram)[keyof typeof CardProgram]; /** * A card's lifecycle status, program-agnostic. Aliases the credit union because * one of the two has to be the base; the parity assertions below are what keep * that choice arbitrary. */ type CardStatus = CreditCardStatus; /** * A card's physical form factor — the codebase's meaning of "card type". The * credit/debit axis is `CardProgram`, not this. */ type CardType = CreditCardType; /** Accessible copy for the panel header's controls. */ interface CardDetailsHeaderLabels { /** Fallback title when the card has no nickname. */ untitledCard: string; /** Accessible name for the kebab that opens the card actions menu. */ menuTriggerAriaLabel: string; /** Accessible name for the close (X) control. */ closeAriaLabel: string; } /** Accessible copy for the simplified card face. */ interface CardDetailsCardFaceLabels { /** Alt text for the bank logo when the caller supplies no `bankLogoAlt`. */ bankLogoAlt: string; } /** Row headings and per-row copy affordance names for the details table. */ interface CardDetailsFieldLabels { cardholder: string; nickname: string; billingAddress: string; allowedCategories: string; /** Stands in for a row whose value the card does not carry. */ emptyValue: string; copyCardholderAriaLabel: string; copyNicknameAriaLabel: string; copyBillingAddressAriaLabel: string; } /** Copy for the three non-loaded screens. */ interface CardDetailsStatusScreenLabels { /** Accessible name announced while the panel is loading. */ loadingAriaLabel: string; errorTitle: string; errorDescription: string; errorRetry: string; notFoundTitle: string; notFoundDescription: string; } interface CardDetailsPanelLabels { header: CardDetailsHeaderLabels; cardFace: CardDetailsCardFaceLabels; fields: CardDetailsFieldLabels; status: CardDetailsStatusScreenLabels; } /** * Deep partial for label overrides. * * Both label surfaces this widget exposes have nested groups, and a shallow * `Partial` would let a consumer who overrides one nested string drop the rest * of that group. The repo has no shared `PartialDeep` and does not depend on * `type-fest`, so each labels module defines its own — `card-details-widget/ui` * has an identical one for the panel's labels, and this declaration also types * that prop here so the widget carries one such helper rather than two. */ type PartialDeep$2 = { [K in keyof T]?: T[K] extends object ? PartialDeep$2 : T[K]; }; /** * Copy the **feature** layer owns, as opposed to the panel's own * `CardDetailsPanelLabels`. * * The split follows where the string is resolved, not where it is painted. A * status badge word is chosen by mapping a generated `cardStatus` enum member, * which is a data-access-typed decision the presentational layer is not allowed * to make — so it is overridable here even though the panel renders it. The * panel's own labels stay with the panel. */ interface CardDetailsFeatureLabels { /** Confirmation toast after a copy affordance writes to the clipboard. */ copySuccessToast: string; /** Program wording on the card face, keyed on the widget's `cardProgram`. */ programLabels: Record; /** Status badge wording, keyed on the generated card status. */ statusLabels: Record; /** Form-factor subtitle wording, keyed on the generated card type. */ formFactorLabels: Record; } interface CardDetailsWidgetProps extends WidgetProviderProps { /** Id of the card to show. */ cardId: string; /** * Which issuing product `cardId` belongs to. **Required, with no default** — * it selects the endpoint the card is fetched from, and a wrong guess would * 404 a card that exists. `CardsWidget` publishes the same required prop, so * one value configures a list and its detail panel together. * * A JavaScript consumer, or a host passing a route param straight through, can * still get a value past the type. **There is no catch-all and no default:** * anything that is not explicitly one of the two programs fetches nothing and * renders the panel's error state with no retry, and the reason is named on the * console. That covers an absent prop (`undefined` / `null`) as well as an * unrecognised one (`'prepaid'`, a case-wrong `'Credit'`), because the widget * cannot know which product to ask about in either case. * * A host that resolves the program asynchronously should gate its own render on * it rather than mounting this widget without it — an absent program is not * read as "still loading". */ cardProgram: CardProgram; /** * Called when the header's close control is pressed. Omitting it renders no * close control at all: a standalone card page has nothing to close back to, * while a host rendering the panel in a drawer supplies this and suppresses * its own chrome's close button so the two do not sit side by side. */ onClose?: () => void; /** Overrides for the panel's own copy. */ labels?: PartialDeep$2; /** Overrides for the copy this layer resolves — see `CardDetailsFeatureLabels`. */ featureLabels?: PartialDeep$2; /** * Bank logo for the card face. The widget ships no bank artwork of its own and * resolves none from the init response: an embeddable library must not depend * on a Tesouro-hosted asset a host page's content-security policy can block, * and a bundled bank-name→URL table would put internal CDN links in the * published package (PLAT-1179, embedded ADR 0005). Omit it and the card face * renders without a logo rather than with a placeholder. */ bankLogoSrc?: string; bankLogoAlt?: string; } type PartialDeep$1 = { [K in keyof T]?: T[K] extends object ? PartialDeep$1 : T[K]; }; interface CreateCardWidgetLabels { header: { title: string; closeAriaLabel: string; }; cardArtAlt: string; setup: { sectionTitle: string; sectionDescription: string; cardholderLabel: string; cardholderPlaceholder: string; cardFormatLabel: string; cardFormatPlaceholder: string; cardFormatVirtual: string; cardFormatPhysical: string; fundingAccountLabel: string; fundingAccountPlaceholder: string; }; mailing: { sectionTitle: string; sectionDescription: string; businessTitle: string; businessDescription: string; customTitle: string; customDescription: string; }; manualAddress: { streetLabel: string; cityLabel: string; stateLabel: string; statePlaceholder: string; zipLabel: string; }; preparing: { title: string; description: string; }; success: { title: string; description: string; createAnother: string; viewCard: string; }; footer: { cancel: string; createCard: string; }; cardholderError: { title: string; description: string; retry: string; }; fundingAccountError: { title: string; description: string; retry: string; }; } interface CreateCardFeatureLabels { toast: { creating: string; success: string; error: string; }; untitledFundingAccount: string; /** * Success-screen copy chosen from the create response's `cardStatus`. * Active/ready wording lives on the UI defaults; these cover statuses that * must not claim the card is already usable. */ success: { pendingActivationTitle: string; pendingActivationDescription: string; createdTitle: string; createdDescription: string; }; } type CreateCardWidgetProps = WidgetProviderProps & { /** Static card plastic image URL (no overlays). Host / white-label supplied. */ cardArtSrc: string; labels?: PartialDeep$1; featureLabels?: Partial<{ toast: Partial; untitledFundingAccount: string; success: Partial; }>; className?: string; onClose?: () => void; onCancel?: () => void; /** Fired with the new debit card id after a successful create. */ onViewCard?: (cardId: string) => void; }; /** * Every key of `T` optional, recursively, so a consumer can override one nested * label without restating its siblings. Defined locally because the repo has no * shared deep-partial type and does not depend on `type-fest` — same helper the * two card `ui` libs declare. */ type PartialDeep = { [K in keyof T]?: T[K] extends object ? PartialDeep : T[K]; }; /** * Strings this layer produces rather than passes through. * * They are separate from `CardsListLabels` (the `ui` lib's) because the cells * reaching that library are already formatted: the em-dash, the nickname * fallback and the "Viewing" prefix are all written *here*, so the UI lib has * no key to override them with. `bank-accounts-widget`'s `featureLabels` is the * precedent for the split. * * The status and form-factor maps live here for the same reason. EMBD-4503's * amendment put them in `shared/feature` keyed on the generated unions, and the * row arrives with `statusLabel` / `typeLabel` resolved — so this is the only * layer a consumer could reach them through. */ interface CardsFeatureLabels { /** * Stands in for a cell the card program carries no value for — credit has no * funding account, and a debit card's funding account is unresolvable without * the bank-account read scope. */ emptyValue: string; /** Name shown for a card with no nickname set. */ untitledCard: string; /** * Last-resort name for a funding account with neither a nickname nor an * account number to mask. An account with no nickname shows `••••1234` * instead, so that two unnamed accounts stay distinguishable — this is only * for the case where there is nothing at all to show. */ untitledFundingAccount: string; /** Display copy per card lifecycle status; keys are the generated code terms. */ cardStatus: Record; /** Display copy per card form factor; keys are the generated code terms. */ cardType: Record; } interface CardsWidgetPagination { /** Cursor for the page on screen. Omit for the first page. */ paginationToken?: string; /** Number of rows requested per page. */ pageSize: number; } interface CardsWidgetPaginationInput { paginationToken?: string; pageSize?: number; } interface CardsWidgetProps extends WidgetProviderProps { /** * Which issuing program the list shows — `'credit'` or `'debit'`. * * **Required, with no default.** A cards list shows exactly one program, and * the value selects the endpoint that is read as well as which scopes gate the * affordances. Defaulting it would make the choice invisible at the call site * and would silently pick a program for a host that meant the other one. */ cardProgram: CardProgram; /** * Controlled cursor/page-size metadata. Supply with `onPaginationChange` when * a host owns the list position, e.g. URL-backed pagination. */ pagination?: CardsWidgetPaginationInput; /** * Initial cursor/page-size metadata for uncontrolled usage. Omit for first * page with the default page size. Ignored when `pagination` is supplied. */ defaultPagination?: CardsWidgetPaginationInput; /** * Called whenever the widget changes its cursor/page-size pair through pagination * controls or a cursor-invalidating reset such as page-size changes. Hosts that * persist list position should store this whole object, not the token alone. */ onPaginationChange?: (pagination: CardsWidgetPagination) => void; /** * Overrides for the list's own copy, merged per nested group. Typed with the * `ui` lib's own deep-partial helper (each labels module declares one — the * repo has no shared version) so this prop follows that library's contract. */ labels?: PartialDeep$3; /** * Overrides for the copy this layer produces rather than passes through — the * status and form-factor vocabulary, the empty-cell placeholder, the nickname * fallbacks, and the pagination range prefix. Separate from `labels` because * the list library receives those values already formatted and so has no key * for them; `BankAccountsWidget.featureLabels` is the same split. */ featureLabels?: PartialDeep; /** * The card whose details panel is open. Supply with `onSelectedCardIdChange` * when the host owns that state — a deep-linked `/cards/[id]`, say. `null` * closes the panel; omit the prop for uncontrolled behaviour. * * Pinning it to `null` and navigating from `onSelectedCardIdChange` is how a * host suppresses the built-in panel entirely and owns navigation itself: the * click is still reported, and because the value never comes back non-null, * nothing ever opens. */ selectedCardId?: string | null; /** Initial selection when uncontrolled. Ignored when `selectedCardId` is supplied. */ defaultSelectedCardId?: string | null; /** * Called whenever the open card changes, including on close (`null`). * * Supplying it does **not** change what renders — a host can observe row clicks * for analytics, or mirror the selection into a query param, and still get the * built-in panel. (The removed `onCardSelect` could not: its presence * suppressed the panel, so those two intents were unexpressible together.) */ onSelectedCardIdChange?: (cardId: string | null) => void; /** * Label overrides forwarded into the nested card details panel, mirroring * `BankAccountsWidgetProps.accountDetailsLabels`. * * Derived from the receiving prop rather than restated, so the forwarded and * received types cannot drift. Naming the panel's labels type directly is not * an option anyway: a cross-widget `type:ui` import is banned by * `EMBEDDED_DEP_CONSTRAINTS`, and this indexed access reaches it through the * sanctioned feature → feature edge without re-exporting anything. It already * carries `card-details-widget`'s own deep partial, so no wrapper here. */ cardDetailsLabels?: CardDetailsWidgetProps['labels']; /** * Overrides for the copy the panel's *feature* layer resolves — its status * vocabulary, form-factor wording, program label and copy-success toast. * * Distinct from `featureLabels`, which covers the list's own vocabulary. * Without this prop the panel is unreachable for that copy, so a host that * renames a status in the list would still read the default inside the panel. */ cardDetailsFeatureLabels?: CardDetailsWidgetProps['featureLabels']; /** * Bank logo for the details panel's card face. Forwarded verbatim; the panel * renders no logo without it, so omitting these leaves the built-in sheet * showing a logo-less card rather than a placeholder. * * These stay props because the package ships no bank artwork and resolves none * from the init response (PLAT-1179, embedded ADR 0005). */ bankLogoSrc?: string; bankLogoAlt?: string; /** * Plastic art for the built-in debit create sheet. Forwarded verbatim into * nested `CreateCardWidget`. Required for that sheet: omitting it (with no * host `onCreateCard`) hides Create card rather than opening a panel that * cannot render. Same PLAT-1179 / ADR 0005 rule as `bankLogoSrc` — the package * ships no card artwork. */ cardArtSrc?: string; /** * Label overrides forwarded into the nested create-card panel. Indexed off * `CreateCardWidgetProps` so the forwarded and received types cannot drift, * the same feature → feature edge as `cardDetailsLabels`. */ createCardLabels?: CreateCardWidgetProps['labels']; /** * Overrides for the copy the create panel's *feature* layer resolves — mutation * toasts, the untitled funding-account fallback, and pending-activation success * copy. */ createCardFeatureLabels?: CreateCardWidgetProps['featureLabels']; /** * Called when Create card is clicked. When supplied, the host owns the * gesture: the built-in debit sheet does **not** open. Omit it on a debit list * with `cardArtSrc` to use the built-in `CreateCardWidget` sheet. Credit has * no in-package issuance widget, so credit Create card still requires this * callback — omitting it hides the button rather than offering a control that * does nothing. */ onCreateCard?: () => void; /** * Called with the card's id when a row's Activate button is clicked. The button * renders only on cards in `PENDING_ACTIVATION`, and only when the widget token * also holds the program's activate scope. * * Host-owned for the same reason as `onCreateCard`: EMBD-4398 designs no * activation flow, and `POST /debit-cards/{id}/activate` does not exist even * though `debit_card:activate:org` does — so a built-in flow could serve only * one of the two programs. */ onActivateCard?: (cardId: string) => void; } /** * The cards list widget: one page of an organization's credit or debit cards, * with scope-gated Show my cards, Create card and per-row Activate affordances. * * Selecting a row opens that card's read-only details in a sheet, composed from * `CardDetailsWidget` over the sanctioned feature → feature edge. Which card is * open is a controllable value (`selectedCardId` / `defaultSelectedCardId` / * `onSelectedCardIdChange`) so a host can deep-link into it, mirror it into a * query param, or take navigation over entirely — the widget itself reads no * router and no search params. * * On a debit list with `cardArtSrc`, Create card opens the same sheet with * nested `CreateCardWidget`. A host `onCreateCard` still takes over that * gesture (credit, or a custom debit flow). The two panels are mutually * exclusive: opening one closes the other. Success **View card** selects the * new debit card so its details open. * * A pure provider wrapper — every hook lives in `CardsWidgetInner` so it runs * inside `WidgetProvider`'s subtree, which is what the data-access hooks read * their client, org and token from. */ declare function CardsWidget({ baseUrl, widgetToken, organizationId, configClient, gatewayRouting, linkComponent, implementation, uiFramework, errorFallback, onError, analytics, disclosuresAcceptance, ...innerProps }: CardsWidgetProps): React.JSX.Element; export { CardsWidget }; export type { CardsFeatureLabels as CardsWidgetFeatureLabels, CardsListLabels as CardsWidgetLabels, CardsWidgetPagination, CardsWidgetProps };