@poly-x/react 0.1.0-alpha.1 → 0.1.0-alpha.11

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/dist/index.d.mts CHANGED
@@ -18,6 +18,14 @@ declare function PolyXProvider({
18
18
  children
19
19
  }: PolyXProviderProps): ReactNode;
20
20
  //#endregion
21
+ //#region src/bff-session.d.ts
22
+ interface BffSignOutOptions {
23
+ /** `everywhere` ends every session for the user (FR-SSO-5). Default `device`. */
24
+ scope?: "device" | "everywhere";
25
+ /** Where to land afterwards. Resolved here, client-side — the server takes no redirect target. */
26
+ redirectTo?: string;
27
+ }
28
+ //#endregion
21
29
  //#region src/auth-channel.d.ts
22
30
  /**
23
31
  * Same-origin popup→opener handoff of the authorization `code` (F006). The
@@ -115,8 +123,11 @@ interface UseAuth {
115
123
  isLoaded: boolean;
116
124
  isSignedIn: boolean;
117
125
  signIn: (options?: SignInOptions) => Promise<void>;
118
- signOut: () => Promise<void>;
119
- /** Current access token, refreshing if needed; null when signed out. */
126
+ signOut: (options?: BffSignOutOptions) => Promise<void>;
127
+ /**
128
+ * Current access token, refreshing if needed; null when signed out — and always null under
129
+ * BFF custody, where the token is httpOnly server-side by design (FR-SES-3).
130
+ */
120
131
  getToken: () => Promise<string | null>;
121
132
  }
122
133
  declare function useAuth(): UseAuth;
@@ -191,16 +202,179 @@ declare function Protected({
191
202
  }: ProtectedProps): ReactNode;
192
203
  //#endregion
193
204
  //#region src/components/sign-in.d.ts
194
- interface SignInProps extends SignInOptions {
195
- children?: ReactNode;
205
+ /** Every user-facing string, overridable for i18n / white-labelling. */
206
+ interface SignInLabels {
207
+ heading: string;
208
+ subheading: string;
209
+ /** Headline on the `page` variant's brand panel. Empty renders a clean brand panel. */
210
+ tagline: string;
211
+ emailLabel: string;
212
+ emailPlaceholder: string;
213
+ passwordLabel: string;
214
+ passwordPlaceholder: string;
215
+ /** Reveal-toggle a11y labels (aria-label / tooltip on the show-hide button). */
216
+ showPassword: string;
217
+ hidePassword: string;
218
+ submit: string;
219
+ submitting: string;
220
+ forgotPassword: string;
221
+ chooseWorkspace: string;
222
+ chooseWorkspaceSubheading: string;
223
+ securedBy: string;
224
+ setPasswordHeading: string;
225
+ setPasswordSubheading: string;
226
+ newPasswordLabel: string;
227
+ confirmPasswordLabel: string;
228
+ setPasswordSubmit: string;
229
+ passwordMismatch: string;
230
+ weakPassword: string;
231
+ invalidCredentials: string;
232
+ noAccess: string;
233
+ passwordChangeRequired: string;
234
+ genericError: string;
235
+ }
236
+ /**
237
+ * `card` renders just the card — drop it into your own layout.
238
+ * `page` owns the viewport — a split layout with a brand panel beside the form
239
+ * (the panel collapses away under 64rem, leaving the form on its own).
240
+ */
241
+ type SignInVariant = "card" | "page";
242
+ interface SignInProps {
243
+ /** Layout preset. Default `card`. */
244
+ variant?: SignInVariant;
245
+ /**
246
+ * Content for the `page` variant's brand panel. Defaults to your `logo` plus
247
+ * `labels.tagline`; pass your own node to take the panel over completely.
248
+ * Ignored by the `card` variant.
249
+ */
250
+ panel?: ReactNode;
251
+ /** BFF endpoint backed by `createAuthHandlers().authenticate`. Default `/api/polyx/authenticate`. */
252
+ action?: string;
253
+ /**
254
+ * URL of your reset flow (where `<ForgotPassword/>` lives). When set, a
255
+ * "Forgot password?" link appears under the password field. Omit to hide it.
256
+ */
257
+ forgotPasswordUrl?: string;
258
+ /** Where to send the browser after success. Overrides the server's default redirect. */
259
+ afterSignInPath?: string;
260
+ /** Pre-scope the login to a single organization (skips org discovery). */
261
+ organizationCode?: string;
262
+ /** Rendered above the heading — your wordmark or logo. */
263
+ logo?: ReactNode;
264
+ /** Show the "Secured by PolyX" attribution under the form. Default true. */
265
+ showSecuredBy?: boolean;
266
+ /** Appended to the root element's class list, for escape-hatch styling. */
196
267
  className?: string;
268
+ labels?: Partial<SignInLabels>;
269
+ /** Fired when the backend requires the user to set a new password before continuing. */
270
+ onPasswordChangeRequired?: (userId: string) => void;
197
271
  }
198
- /** Minimal sign-in trigger — popup by default. Style via `className`/children. */
199
- declare function SignIn({
200
- children,
201
- className,
202
- ...options
203
- }: SignInProps): ReactNode;
272
+ /**
273
+ * The embedded, Clerk-style sign-in form (D2b). Renders email/password inside the
274
+ * consuming app and POSTs to the SDK's BFF (`@poly-x/next` `authenticate`), which
275
+ * runs the credential authorize server-side and seals an httpOnly session — no
276
+ * redirect to a hosted PolyX login page, no tokens or credentials in the browser
277
+ * after submit. Handles the workspace picker (select_tenant) inline.
278
+ *
279
+ * Ships styled: `import "@poly-x/react/styles.css"` once, then theme it by
280
+ * overriding the `--polyx-*` custom properties on any ancestor.
281
+ */
282
+ declare function SignIn(props: SignInProps): ReactNode;
283
+ //#endregion
284
+ //#region src/components/forgot-password.d.ts
285
+ /** Every user-facing string, overridable for i18n / white-labelling. */
286
+ interface ForgotPasswordLabels {
287
+ heading: string;
288
+ subheading: string;
289
+ emailLabel: string;
290
+ emailPlaceholder: string;
291
+ submit: string;
292
+ submitting: string;
293
+ /** Shown after submit — always, regardless of whether the account exists. */
294
+ sentHeading: string;
295
+ /** Confirmation body. `{email}` is replaced with the entered address, emphasized. */
296
+ sentSubheading: string;
297
+ differentEmail: string;
298
+ backToSignIn: string;
299
+ securedBy: string;
300
+ genericError: string;
301
+ }
302
+ interface ForgotPasswordProps {
303
+ /** BFF endpoint backed by `createAuthHandlers().forgotPassword`. Default `/api/polyx/forgot-password`. */
304
+ action?: string;
305
+ /** Where the "back to sign in" link points. Default `/sign-in`. */
306
+ signInPath?: string;
307
+ /** Rendered above the heading — your wordmark or logo. */
308
+ logo?: ReactNode;
309
+ /** Show the "Secured by PolyX" attribution under the form. Default true. */
310
+ showSecuredBy?: boolean;
311
+ /** Appended to the root element's class list, for escape-hatch styling. */
312
+ className?: string;
313
+ labels?: Partial<ForgotPasswordLabels>;
314
+ }
315
+ /**
316
+ * The self-service "forgot password" form (poly-x v5 / F040). Renders an email field
317
+ * inside the consuming app and POSTs to the SDK's BFF (`@poly-x/next` `forgotPassword`),
318
+ * which asks poly-auth to email a single-use reset link SERVER-SIDE. The response is
319
+ * always the same — no token, no account-existence signal — so after submit the form
320
+ * shows an identical "check your email" state whether or not the account exists.
321
+ *
322
+ * Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
323
+ * via the `--polyx-*` custom properties. Target `.polyx-forgot` for form-specific tweaks.
324
+ */
325
+ declare function ForgotPassword(props: ForgotPasswordProps): ReactNode;
326
+ //#endregion
327
+ //#region src/components/reset-password.d.ts
328
+ /** Every user-facing string, overridable for i18n / white-labelling. */
329
+ interface ResetPasswordLabels {
330
+ heading: string;
331
+ subheading: string;
332
+ newPasswordLabel: string;
333
+ confirmPasswordLabel: string;
334
+ passwordPlaceholder: string;
335
+ submit: string;
336
+ submitting: string;
337
+ successHeading: string;
338
+ successSubheading: string;
339
+ invalidHeading: string;
340
+ invalidSubheading: string;
341
+ requestNewLink: string;
342
+ backToSignIn: string;
343
+ securedBy: string;
344
+ passwordMismatch: string;
345
+ weakPassword: string;
346
+ genericError: string;
347
+ }
348
+ interface ResetPasswordProps {
349
+ /** BFF endpoint backed by `createAuthHandlers().resetPassword`. Default `/api/polyx/reset-password`. */
350
+ action?: string;
351
+ /** The opaque reset token. Defaults to `?token=` from the URL (client-side). */
352
+ token?: string;
353
+ /** Where to send the browser after a successful reset. Default `/sign-in`. */
354
+ afterResetPath?: string;
355
+ /** Where "request a new link" / "back to sign in" point. Default `/forgot-password` and `/sign-in`. */
356
+ forgotPasswordPath?: string;
357
+ signInPath?: string;
358
+ /** Rendered above the heading — your wordmark or logo. */
359
+ logo?: ReactNode;
360
+ /** Show the "Secured by PolyX" attribution under the form. Default true. */
361
+ showSecuredBy?: boolean;
362
+ /** Client-side minimum password length (the backend enforces the real floor). Default 8. */
363
+ minLength?: number;
364
+ /** Appended to the root element's class list, for escape-hatch styling. */
365
+ className?: string;
366
+ labels?: Partial<ResetPasswordLabels>;
367
+ }
368
+ /**
369
+ * The reset-completion form (poly-x v5 / F040). Reads the opaque token from the URL,
370
+ * collects a new password, and POSTs to the SDK's BFF (`@poly-x/next` `resetPassword`),
371
+ * which redeems the token single-use server-side. The token is never decoded in the
372
+ * browser — identity, validity, and expiry are all enforced by the backend.
373
+ *
374
+ * Reuses the `<SignIn/>` styling: `import "@poly-x/react/styles.css"` once, then theme
375
+ * via the `--polyx-*` custom properties. Target `.polyx-reset` for form-specific tweaks.
376
+ */
377
+ declare function ResetPassword(props: ResetPasswordProps): ReactNode;
204
378
  //#endregion
205
379
  //#region src/components/auth-callback.d.ts
206
380
  interface AuthCallbackProps {
@@ -212,6 +386,164 @@ declare function AuthCallback({
212
386
  children
213
387
  }: AuthCallbackProps): ReactNode;
214
388
  //#endregion
389
+ //#region src/components/placement.d.ts
390
+ /**
391
+ * Collision-aware placement for the SDK's popovers.
392
+ *
393
+ * A menu pinned to one side is wrong somewhere: an avatar in a page header wants to open
394
+ * down-and-left, the same component in a sidebar footer has to open up-and-right. Rather than
395
+ * make every consumer work that out, measure the trigger against the viewport and pick.
396
+ *
397
+ * Deliberately hand-rolled: `@poly-x/react` has no runtime dependency but `@poly-x/core`, and a
398
+ * full positioning engine is a lot of surface to inherit for one menu. The component only needs
399
+ * to know *which side* — CSS does the actual placing — so this stays a pure function over
400
+ * rectangles, and is unit-testable without a layout engine.
401
+ */
402
+ type Side = "top" | "bottom" | "left" | "right";
403
+ type SideOption = Side | "auto";
404
+ type Align = "start" | "center" | "end";
405
+ interface Rect {
406
+ top: number;
407
+ bottom: number;
408
+ left: number;
409
+ right: number;
410
+ }
411
+ interface Size {
412
+ width: number;
413
+ height: number;
414
+ }
415
+ interface Viewport {
416
+ width: number;
417
+ height: number;
418
+ }
419
+ /**
420
+ * Which side the menu should open on.
421
+ *
422
+ * An explicit side is honoured when it fits and flipped to its opposite when it doesn't — a
423
+ * requested side that runs off-screen is a worse answer than the one that doesn't. `auto` takes
424
+ * the first side that fits, and if none do, the roomiest: something has to be chosen, and the
425
+ * least-bad option beats an arbitrary default.
426
+ */
427
+ declare function resolveSide(preferred: SideOption, trigger: Rect, menu: Size, viewport: Viewport, gap?: number): Side;
428
+ //#endregion
429
+ //#region src/components/user-button.d.ts
430
+ /** Every user-facing string, overridable for i18n / white-labelling. */
431
+ interface UserButtonLabels {
432
+ trigger: string;
433
+ manageAccount: string;
434
+ signOut: string;
435
+ signOutEverywhere: string;
436
+ }
437
+ interface UserButtonActionProps {
438
+ /**
439
+ * The menu entry's text — or the name of a built-in (`manageAccount`, `signOut`,
440
+ * `signOutEverywhere`) to place it at this position instead of appending a second copy.
441
+ */
442
+ label: string;
443
+ /** Icon rendered before the label. */
444
+ labelIcon?: ReactNode;
445
+ onClick?: () => void;
446
+ }
447
+ interface UserButtonLinkProps {
448
+ label: string;
449
+ labelIcon?: ReactNode;
450
+ href: string;
451
+ }
452
+ interface UserButtonSlotProps {
453
+ children?: ReactNode;
454
+ }
455
+ interface UserButtonProps {
456
+ /** Show the user's name next to the avatar. Default `false`. */
457
+ showName?: boolean;
458
+ /** Where to land after signing out. Default the app root. */
459
+ afterSignOutUrl?: string;
460
+ /**
461
+ * Destination for the "Manage account" entry. Omitted entirely when unset — PolyX has no
462
+ * hosted profile page, so the destination is the consumer's to own.
463
+ */
464
+ manageAccountUrl?: string;
465
+ /** Offer "Sign out everywhere" (ends every session for the user). Default `false`. */
466
+ showSignOutEverywhere?: boolean;
467
+ /** Start with the menu open. Default `false`. */
468
+ defaultOpen?: boolean;
469
+ /** Rendered while the session resolves, so the header doesn't jump. */
470
+ fallback?: ReactNode;
471
+ /** Appended to the root element's class list, for escape-hatch styling. */
472
+ className?: string;
473
+ labels?: Partial<UserButtonLabels>;
474
+ /**
475
+ * `<UserButton.MenuItems>` with `<UserButton.Action>` / `<UserButton.Link>` / `<UserButton.Custom>`
476
+ * entries, and/or a `<UserButton.Header>` replacing the identity block.
477
+ */
478
+ children?: ReactNode;
479
+ /** Avatar size in pixels. Default 32. */
480
+ avatarSize?: number;
481
+ /**
482
+ * What the trigger shows. Replaces the avatar (and `showName`); the SDK still owns the button
483
+ * and its menu semantics, so a custom trigger costs no accessibility.
484
+ */
485
+ trigger?: ReactNode;
486
+ /**
487
+ * Which side the menu opens on. Default `auto` — measured against the viewport, because the
488
+ * right answer differs by where the trigger sits (a header avatar opens down, a sidebar-footer
489
+ * one has to open up). An explicit side is flipped only if it would run off-screen.
490
+ */
491
+ side?: SideOption;
492
+ /** Alignment along the chosen side. Default `end`. */
493
+ align?: Align;
494
+ }
495
+ /**
496
+ * The signed-in user surface: avatar trigger + a menu with their identity and sign-out
497
+ * (FR-SIGNIN-6). Reads only the hooks, so it behaves identically under either custody model
498
+ * — an httpOnly BFF session or an in-memory SPA one — and needs no provider in a
499
+ * `@poly-x/next` app.
500
+ *
501
+ * Custom entries compose declaratively:
502
+ *
503
+ * ```tsx
504
+ * <UserButton manageAccountUrl="/account">
505
+ * <UserButton.MenuItems>
506
+ * <UserButton.Action label="signOut" /> // reposition a built-in
507
+ * <UserButton.Link label="Docs" href="/docs" />
508
+ * </UserButton.MenuItems>
509
+ * </UserButton>
510
+ * ```
511
+ */
512
+ declare const UserButton: ((props: UserButtonProps) => ReactNode) & {
513
+ MenuItems: (props: UserButtonSlotProps) => ReactNode;
514
+ Action: (props: UserButtonActionProps) => ReactNode;
515
+ Link: (props: UserButtonLinkProps) => ReactNode; /** Arbitrary JSX as a menu row — bring your own controls. */
516
+ Custom: (props: UserButtonSlotProps) => ReactNode; /** Replaces the built-in identity block. */
517
+ Header: (props: UserButtonSlotProps) => ReactNode;
518
+ };
519
+ //#endregion
520
+ //#region src/components/user-avatar.d.ts
521
+ interface UserAvatarProps {
522
+ /** Image URL. Falls back to initials when absent or when the image fails to load. */
523
+ src?: string;
524
+ /** The name initials are derived from; also the image's alt text. */
525
+ name?: string;
526
+ /** Pixel size of the (square) avatar. Default 32. */
527
+ size?: number;
528
+ /** Appended to the root element's class list, for escape-hatch styling. */
529
+ className?: string;
530
+ }
531
+ /**
532
+ * Up to two initials from a display name. Handles the shapes the platform actually
533
+ * produces — "Ali Ikram", a bare username, an email address.
534
+ */
535
+ declare function initialsFrom(name: string | undefined): string;
536
+ /**
537
+ * The user's picture, or their initials. A missing avatar is the ordinary case rather than
538
+ * an error, so initials are a first-class state, not a broken image.
539
+ */
540
+ declare function UserAvatar({
541
+ src,
542
+ name,
543
+ size,
544
+ className
545
+ }: UserAvatarProps): ReactNode;
546
+ //#endregion
215
547
  //#region src/index.d.ts
216
548
  /**
217
549
  * @poly-x/react — PolyX SDK for React SPAs. Sign-in UI + orchestration land in
@@ -220,4 +552,4 @@ declare function AuthCallback({
220
552
  declare const PACKAGE_NAME = "@poly-x/react";
221
553
  declare const version = "0.0.0";
222
554
  //#endregion
223
- export { AuthCallback, type AuthCallbackMessage, type AuthCallbackProps, type AuthChannel, BroadcastAuthChannel, BroadcastChannelSessionChannel, type BrowserBridge, type CallbackParams, type LoginController, type LoginControllerDeps, PACKAGE_NAME, PolyXContext, type PolyXContextValue, PolyXProvider, type PolyXProviderProps, PopupCancelledError, type PopupHandle, Protected, type ProtectedProps, SessionStoragePkceStore, SignIn, type SignInOptions, type SignInProps, type UseAuth, WebLocksLock, WindowBrowserBridge, createLoginController, useAuth, useAuthCallback, useSession, useUser, version };
555
+ export { type Align, AuthCallback, type AuthCallbackMessage, type AuthCallbackProps, type AuthChannel, BroadcastAuthChannel, BroadcastChannelSessionChannel, type BrowserBridge, type CallbackParams, ForgotPassword, type ForgotPasswordLabels, type ForgotPasswordProps, type LoginController, type LoginControllerDeps, PACKAGE_NAME, PolyXContext, type PolyXContextValue, PolyXProvider, type PolyXProviderProps, PopupCancelledError, type PopupHandle, Protected, type ProtectedProps, ResetPassword, type ResetPasswordLabels, type ResetPasswordProps, SessionStoragePkceStore, type Side, type SideOption, SignIn, type SignInLabels, type SignInOptions, type SignInProps, type SignInVariant, type UseAuth, UserAvatar, type UserAvatarProps, UserButton, type UserButtonActionProps, type UserButtonLabels, type UserButtonLinkProps, type UserButtonProps, type UserButtonSlotProps, WebLocksLock, WindowBrowserBridge, createLoginController, initialsFrom, resolveSide, useAuth, useAuthCallback, useSession, useUser, version };