@benji-money/connect-sdk 1.1.3 → 1.1.4-beta.10

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/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A JavaScript Github Package SDK for integrating Benji Connect, Benji's authentication and verification services.
4
4
 
5
+ LOGIN mode (surfaces, timers, host API): [docs/login-mode.md](./docs/login-mode.md).
6
+
5
7
  ## Installation
6
8
 
7
9
  ```bash
@@ -87,11 +89,21 @@ The SDK accepts the following configuration options:
87
89
  - `environment` (required): One of `local`, `development`, `sandbox`, or `production`
88
90
  - `token` (required): Your API connect token
89
91
  - `mode` (optional): `BenjiConnectMode` — `CONNECT` (default), `TRANSFER`, `REDEEM`, or `LOGIN`
90
- - `authType` (optional): `PartnerIntegrationType` — LOGIN only; omit or set `DUMMY` for the visible modal iframe; set to your partner type (1–6) for popup-only auth
92
+ - `authType` (optional): `PartnerIntegrationType` — LOGIN only; omit or set `DUMMY` for the visible modal iframe; set to your partner type (1–6) for the embedded sign-in button. Prefer `tokenData.authType` when using `tokenData`.
93
+ - `login` (optional): `BenjiConnectLoginConfig` — LOGIN-only options:
94
+ - `container`: `HTMLElement | string` — **required** for the embedded LOGIN button. The element the visible Benji Connect iframe mounts into. The SDK never appends to `document.body` for this surface; a missing container reports through `onError`.
95
+ - `surface`: `BenjiConnectLoginSurface` — `EMBEDDED_BUTTON` (default for non-DUMMY LOGIN) or `MODAL` (default for DUMMY). Override only when a partner on a real integration type needs the modal.
96
+ - `windowTarget`: `BenjiConnectLoginWindowTarget` — LOGIN non-DUMMY only; `tab` (default) or `popup`. Forwarded to Benji Connect, which opens the window.
97
+ - `buttonText`: host-owned label. Omitted or empty → Connect paints `Login`.
98
+ - `buttonTheme`: resolved CSS values for the in-iframe button (fill, hover, type, radius).
99
+ - `tokenData` (optional): `BenjiConnectTokenData` — LOGIN only; pass `partnerAuthLink` (Auth Service `connect_url`), `configToken` (mint `config_token`, used as OAuth `state`), and `authType`. Benji Connect resolves the auth link at iframe load, before any click.
91
100
  - `onSuccess` (optional): Callback function called when connect completed successfully
92
101
  - `onError` (optional): Callback function called when error occurs in the connect flow
93
102
  - `onExit` (optional): Callback function called when the user exits the connect flow
94
103
  - `onEvent` (optional): Callback function for handling various events
104
+ - `onLoginReady` (optional): Embedded LOGIN button only — Benji Connect rendered the button, so the host can drop its skeleton
105
+ - `onLoginHover` (optional): Embedded LOGIN button only — pointer or focus entered the in-iframe button, for a host-owned tooltip
106
+ - `onLoginClicked` (optional): Embedded LOGIN button only — the button was pressed, before the tab opens, for a host-owned pending state
95
107
  - `anchor` (optional): Live anchor binding — `HTMLElement`, CSS selector, getter `() => HTMLElement | null`, or ref `{ value: HTMLElement | null }`. Re-resolved on every layout pass. Falls back to centered when missing or invalid. See [Placement](#placement)
96
108
  - `placement` (optional): Placement relative to `anchor` — see [Placement](#placement) below
97
109
  - `offset` (optional): Pixel gap after placement — `{ top?: number; left?: number }` (default `{ top: 0, left: 0 }`)
@@ -102,7 +114,7 @@ The SDK accepts the following configuration options:
102
114
  | ---- | ---------- | ----- |
103
115
  | **CONNECT** (default) | Centered or anchored modal iframe | No `authType`; standard connect / verify flow |
104
116
  | **LOGIN + DUMMY / no `authType`** | Same visible modal iframe | Partner auth runs in a nested iframe inside Benji Connect |
105
- | **LOGIN + non-DUMMY** | Partner popup only | Pass `authType`; Benji Connect iframe is headless popup shows a loading spinner until partner auth navigates see [LOGIN popup example](#login-popup-example) below |
117
+ | **LOGIN + non-DUMMY** | **Embedded sign-in button** plus a partner auth tab | Pass `authType` (or `tokenData.authType`) and `login.container`. Benji Connect renders the button inside a visible iframe and opens the partner tab itself, on every device. See [embedded LOGIN button example](#embedded-login-button-example) below. |
106
118
 
107
119
  ### Placement
108
120
 
@@ -117,7 +129,7 @@ Placement uses [Floating UI](https://floating-ui.com/docs/computePosition#placem
117
129
  **What `anchor` positions:**
118
130
 
119
131
  - **CONNECT, TRANSFER, REDEEM, and LOGIN + DUMMY:** the modal iframe
120
- - **LOGIN + non-DUMMY:** the partner-auth popup window (modal iframe stays headless)
132
+ - **LOGIN + non-DUMMY:** nothing. The embedded button takes its box from `login.container`, so omit `anchor` / `placement` / `offset`.
121
133
 
122
134
  **Defaults:**
123
135
 
@@ -144,15 +156,18 @@ Prefer selector, ref, or getter when the anchor can re-render (e.g. disabled/loa
144
156
  - **Anchored** popovers use the full design size when width and height checks pass; otherwise they fall back to a scaled centered modal
145
157
  - Scroll, resize, and visual viewport changes while open recompute placement and size
146
158
 
147
- #### LOGIN popup example
159
+ #### Embedded LOGIN button example
160
+
161
+ Reserve a box in your own layout, hand it to the SDK, and let Benji Connect render the button inside it:
148
162
 
149
- Popup below a top-right login button; pass `authType` for non-DUMMY partners:
163
+ ```html
164
+ <div id="benji-login" style="width: 140px; height: 40px"></div>
165
+ ```
150
166
 
151
167
  ```typescript
152
168
  import {
153
169
  ConnectSDK,
154
170
  BenjiConnectMode,
155
- BenjiConnectPlacement,
156
171
  PartnerIntegrationType,
157
172
  } from "@benji-money/connect-sdk";
158
173
 
@@ -160,19 +175,29 @@ const sdk = new ConnectSDK({
160
175
  environment: "sandbox",
161
176
  token: connectToken,
162
177
  mode: BenjiConnectMode.LOGIN,
163
- authType: PartnerIntegrationType.OAUTH_PKCE,
164
- anchor: "#login-btn",
165
- placement: BenjiConnectPlacement.BOTTOM_END,
166
- offset: { top: 8 },
178
+ login: { container: "#benji-login" },
179
+ tokenData: {
180
+ authType: PartnerIntegrationType.OAUTH_PKCE,
181
+ partnerAuthLink: connectUrl, // from Auth Service connect_url
182
+ configToken: configToken, // from GET /connect/token — OAuth state
183
+ },
184
+ onLoginReady: () => { /* hide your skeleton */ },
185
+ onLoginHover: () => { /* show your tooltip */ },
186
+ onLoginClicked: () => { /* show your pending state */ },
167
187
  onSuccess: (token) => { /* ... */ },
168
- onError: (error) => { /* popup blocked, etc. */ },
169
- onExit: (metadata) => { /* POPUP_CLOSED when user dismisses popup */ },
188
+ onError: (error) => { /* sign-in window blocked, etc. */ },
189
+ onExit: (metadata) => { /* toast: WINDOW_CLOSE_DETECTED; the button stays mounted */ },
170
190
  });
171
191
 
192
+ // Mount on page load, not on click — the iframe resolves the partner auth link
193
+ // while the user is still reading the page.
172
194
  await sdk.open();
195
+
196
+ // Later, when your token refresh timer fires:
197
+ sdk.updateConfig({ token: freshConnectToken, tokenData: { configToken: freshConfigToken } });
173
198
  ```
174
199
 
175
- > **`bottom-end`** positions the **partner popup** below the anchor with its right edge aligned to the anchor's right edge. The Benji Connect iframe stays headless (not visible). The pre-opened popup shows generic loading UI (`Loading sign-in…`) until Benji Connect sends the partner auth URL.
200
+ > **Why the button lives in the iframe.** `window.open` needs transient user activation, and activation belongs to the document the click happened in. Because the click lands in Benji Connect's document, **Connect** opens the partner tab, so that tab's `opener` is the Connect iframe same-origin with Connect's OAuth callback. That is what removes the host-side auth relay, the message queues, and the iOS-only same-tab redirect that earlier versions needed. Reserve the box in your own CSS: the SDK's iframe fills the container at 100% × 100% and contributes no geometry of its own.
176
201
 
177
202
  ### Environments
178
203