@passflow/react 0.9.1 → 0.11.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/index.cjs.js +1 -1
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.es.js +132 -122
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/src/components/provider/index.d.ts +2 -1
  7. package/dist/src/components/provider/index.d.ts.map +1 -1
  8. package/dist/src/components/provider/passflow-provider.d.ts +39 -5
  9. package/dist/src/components/provider/passflow-provider.d.ts.map +1 -1
  10. package/dist/src/components/provider/upgrade-provider.d.ts +49 -0
  11. package/dist/src/components/provider/upgrade-provider.d.ts.map +1 -0
  12. package/dist/src/components/ui/button/index.d.ts +12 -1
  13. package/dist/src/components/ui/button/index.d.ts.map +1 -1
  14. package/dist/src/components/ui/index.d.ts +2 -0
  15. package/dist/src/components/ui/index.d.ts.map +1 -1
  16. package/dist/src/components/ui/spinner/index.d.ts +23 -0
  17. package/dist/src/components/ui/spinner/index.d.ts.map +1 -0
  18. package/dist/src/components/ui/upgrade-dialog/challenge.d.ts +12 -0
  19. package/dist/src/components/ui/upgrade-dialog/challenge.d.ts.map +1 -0
  20. package/dist/src/components/ui/upgrade-dialog/factor-list.d.ts +20 -0
  21. package/dist/src/components/ui/upgrade-dialog/factor-list.d.ts.map +1 -0
  22. package/dist/src/components/ui/upgrade-dialog/index.d.ts +8 -0
  23. package/dist/src/components/ui/upgrade-dialog/index.d.ts.map +1 -0
  24. package/dist/src/components/ui/upgrade-dialog/state-mapping.d.ts +119 -0
  25. package/dist/src/components/ui/upgrade-dialog/state-mapping.d.ts.map +1 -0
  26. package/dist/src/components/ui/upgrade-dialog/status.d.ts +27 -0
  27. package/dist/src/components/ui/upgrade-dialog/status.d.ts.map +1 -0
  28. package/dist/src/components/ui/upgrade-dialog/types.d.ts +188 -0
  29. package/dist/src/components/ui/upgrade-dialog/types.d.ts.map +1 -0
  30. package/dist/src/components/ui/upgrade-dialog/upgrade-dialog.d.ts +13 -0
  31. package/dist/src/components/ui/upgrade-dialog/upgrade-dialog.d.ts.map +1 -0
  32. package/dist/src/context/index.d.ts +1 -0
  33. package/dist/src/context/index.d.ts.map +1 -1
  34. package/dist/src/context/upgrade-context.d.ts +85 -0
  35. package/dist/src/context/upgrade-context.d.ts.map +1 -0
  36. package/dist/src/hooks/index.d.ts +1 -0
  37. package/dist/src/hooks/index.d.ts.map +1 -1
  38. package/dist/src/hooks/use-upgrade.d.ts +43 -0
  39. package/dist/src/hooks/use-upgrade.d.ts.map +1 -0
  40. package/dist/src/index.d.ts +4 -1
  41. package/dist/src/index.d.ts.map +1 -1
  42. package/dist/src/utils/index.d.ts +1 -0
  43. package/dist/src/utils/index.d.ts.map +1 -1
  44. package/dist/src/utils/upgrade-auth.d.ts +38 -0
  45. package/dist/src/utils/upgrade-auth.d.ts.map +1 -0
  46. package/dist/style.css +1 -1
  47. package/package.json +4 -4
  48. package/dist/src/components/flow/upgrade-required-placeholder.d.ts +0 -21
  49. package/dist/src/components/flow/upgrade-required-placeholder.d.ts.map +0 -1
@@ -1,3 +1,4 @@
1
1
  export { PassflowProvider, OIDCExchangeContext } from './passflow-provider';
2
- export type { OIDCExchangeContextValue } from './passflow-provider';
2
+ export type { OIDCExchangeContextValue, PassflowUpgradeOptions } from './passflow-provider';
3
+ export { UpgradeProvider, type UpgradeProviderProps } from './upgrade-provider';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,YAAY,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,YAAY,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1,10 +1,39 @@
1
+ import { UpgradeProviderProps } from './upgrade-provider';
1
2
  import { NavigateFunction, RouterType } from '../../context';
2
3
  import { PassflowConfig } from '@passflow/core';
3
4
  import { default as React, FC, ReactNode } from 'react';
5
+ /**
6
+ * The assurance-upgrade options a consumer may set on `PassflowProvider`.
7
+ *
8
+ * `children`, `enabled` and `backend` are owned by `PassflowProvider` itself:
9
+ * `backend` is a top-level prop (§13.5 — "where your API is" is the headline
10
+ * act, not a nested detail) and `enabled` is derived from `upgrade`/`backend`
11
+ * below, so there is exactly one source for each.
12
+ */
13
+ export type PassflowUpgradeOptions = Omit<UpgradeProviderProps, 'children' | 'enabled' | 'backend'>;
4
14
  type PassflowProviderProps = PassflowConfig & {
5
15
  children: ReactNode;
6
16
  navigate?: NavigateFunction;
7
17
  router?: RouterType;
18
+ /**
19
+ * Where the customer's own API is — domain 2 of §13.5's two-domain
20
+ * interception model. Nothing outside this and Passflow's own API is ever
21
+ * observed, and there is no allow-all opt-in. `string | string[]`, an origin
22
+ * or a same-origin path prefix (`'/api'`).
23
+ */
24
+ backend?: string | string[];
25
+ /**
26
+ * Automatic assurance upgrade (step-up). `undefined` ⇒ **off**, so no
27
+ * existing consumer changes behaviour on upgrade. `true` ⇒ on with
28
+ * defaults; an object ⇒ on with those options; `false` ⇒ off even when
29
+ * `backend` is declared.
30
+ *
31
+ * Declaring `backend` also turns it on: naming where your API is has no
32
+ * other meaning, and §13.5's acceptance configuration is `backend` plus one
33
+ * attached client. The global `window.fetch` patch is a separate, explicit
34
+ * act (`upgrade={{ interceptFetch: true }}`) and stays off by default.
35
+ */
36
+ upgrade?: boolean | PassflowUpgradeOptions;
8
37
  };
9
38
  /**
10
39
  * Read `parent_challenge_id` from the current URL's query string.
@@ -71,17 +100,22 @@ type ParentChallengeMeta = {
71
100
  * - 200 { redirect_url } → the interceptor's fetch wrapper follows
72
101
  * the redirect (sole owner of redirect_url navigation; this hook
73
102
  * must never navigate on OK responses — see the res.ok branch).
74
- * - 403 { error: "upgrade_required", ... } → SDK falls through to
75
- * `setUpgradeRequired(true)` so the consumer renders the
76
- * upgrade-required placeholder + login form. Code path is
77
- * UNREACHABLE today (server's EvaluatePolicy is a no-op
78
- * scaffold); activates when Subtask E lands.
103
+ * - 403 { error: "upgrade_required", ... } → falls through to the
104
+ * login form. Factor elevation on an existing session is
105
+ * `UpgradeProvider`'s flow, not this probe's.
79
106
  * - 401 → clear stale tokens, fall through to login form.
80
107
  *
81
108
  * On any decision-point that ends with "render login form," the
82
109
  * SDK consumer's existing PassflowFlow render path picks up
83
110
  * naturally.
84
111
  */
112
+ /**
113
+ * `'upgrade_required'` is vestigial and kept deliberately (§8.4): it is
114
+ * unreachable today — the 403 branch below sets `'fallback_to_login'` — and
115
+ * removing a member from an exported union would be a type-level breaking
116
+ * change for anyone reading `OIDCExchangeContextValue`. Assurance elevation is
117
+ * now `UpgradeProvider`'s job, not a placeholder's.
118
+ */
85
119
  type ExchangeState = 'idle' | 'exchanging' | 'upgrade_required' | 'fallback_to_login';
86
120
  /**
87
121
  * Context surface exposed to children so the SDK's own components
@@ -1 +1 @@
1
- {"version":3,"file":"passflow-provider.d.ts","sourceRoot":"","sources":["../../../../src/components/provider/passflow-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EAGrB,KAAK,UAAU,EAIhB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,SAAS,EAAiE,MAAM,OAAO,CAAC;AACtH,OAAO,oBAAoB,CAAC;AAE5B,KAAK,qBAAqB,GAAG,cAAc,GAAG;IAC5C,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB,CAAC;AAsBF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,QAAO,MAAM,GAAG,SAQxD,CAAC;AAiCF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,uBAAuB,QAAO,OAA+B,CAAC;AAiJ3E;;;GAGG;AACH,KAAK,mBAAmB,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IAKvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,KAAK,aAAa,GAAG,MAAM,GAAG,YAAY,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AA+NtF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,yCAE9B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CAsItD,CAAC"}
1
+ {"version":3,"file":"passflow-provider.d.ts","sourceRoot":"","sources":["../../../../src/components/provider/passflow-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACpG,OAAO,EAEL,KAAK,gBAAgB,EAGrB,KAAK,UAAU,EAIhB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAiC,KAAK,cAAc,EAA2B,MAAM,gBAAgB,CAAC;AAC7G,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,SAAS,EAAiE,MAAM,OAAO,CAAC;AACtH,OAAO,oBAAoB,CAAC;AAE5B;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,oBAAoB,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC,CAAC;AAEpG,KAAK,qBAAqB,GAAG,cAAc,GAAG;IAC5C,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,sBAAsB,CAAC;CAC5C,CAAC;AAsBF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,4BAA4B,QAAO,MAAM,GAAG,SAQxD,CAAC;AAiCF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,uBAAuB,QAAO,OAA+B,CAAC;AAqK3E;;;GAGG;AACH,KAAK,mBAAmB,GAAG;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IAKvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH;;;;;;GAMG;AACH,KAAK,aAAa,GAAG,MAAM,GAAG,YAAY,GAAG,kBAAkB,GAAG,mBAAmB,CAAC;AAwMtF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;CAC9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,yCAE9B,CAAC;AAEH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA+ItD,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { UpgradeDialogLabels, UpgradeDialogProps } from '../ui/upgrade-dialog';
2
+ import { ReplayPolicy, UpgradeDiagnosticSink, UpgradeFactor } from '@passflow/core';
3
+ import { FC, ReactElement, ReactNode } from 'react';
4
+ export type UpgradeProviderProps = {
5
+ children?: ReactNode;
6
+ /** Default `true`. `false` installs nothing and leaves the hook inert. */
7
+ enabled?: boolean;
8
+ /**
9
+ * Where the customer's own API is — domain 2 (§13.5). Nothing outside this
10
+ * and Passflow's own API is ever observed, and there is no allow-all opt-in.
11
+ */
12
+ backend?: string | string[];
13
+ /**
14
+ * Patches `globalThis.fetch` through the core's registry. **Off by default**,
15
+ * and a different decision from enabling the UI: one prop for both would
16
+ * bundle "show me the verification prompt" with "patch the global", and only
17
+ * the second has the blast radius.
18
+ */
19
+ interceptFetch?: boolean;
20
+ /** Requires the RFC 9470 channel. The body is then never read for a challenge. */
21
+ requireChallengeChannel?: 'header';
22
+ /** NARROWING ONLY: `false` excludes an admitted URL; `true` cannot widen. */
23
+ shouldIntercept?: (url: string) => boolean;
24
+ replay?: ReplayPolicy;
25
+ /** The fetch surface's only cancellation option. Default `'resolve-original'`. */
26
+ onCancel?: 'resolve-original' | 'reject';
27
+ onUpgradeDiagnostic?: UpgradeDiagnosticSink;
28
+ factors?: readonly UpgradeFactor[];
29
+ maxAttempts?: number;
30
+ relyingPartyId?: string;
31
+ /** Per-factor wording for the dialog. */
32
+ labels?: UpgradeDialogLabels;
33
+ title?: string;
34
+ /**
35
+ * FR5's render-prop override. It receives the **exact** props the built-in
36
+ * dialog would render — a typed, constrained override with no `className` or
37
+ * `style` leak.
38
+ *
39
+ * It carries the same obligations as the built-in dialog, the selection
40
+ * signal included: the `challenge` state's `onSelectFactor` must be called
41
+ * when the user picks a factor, because that is the only thing that reports
42
+ * §13.2's selection boundary to the controller. An override that never calls
43
+ * it leaves the controller `collecting` for the whole ceremony, so a late
44
+ * join re-ranks mid-entry — degraded, not silent.
45
+ */
46
+ renderDialog?: (props: UpgradeDialogProps) => ReactElement | null;
47
+ };
48
+ export declare const UpgradeProvider: FC<UpgradeProviderProps>;
49
+ //# sourceMappingURL=upgrade-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade-provider.d.ts","sourceRoot":"","sources":["../../../../src/components/provider/upgrade-provider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAwB,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAYpH,OAAO,EAIL,KAAK,YAAY,EAEjB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EAQnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,KAAK,EAAE,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAqD,MAAM,OAAO,CAAC;AAEtH,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,kFAAkF;IAClF,uBAAuB,CAAC,EAAE,QAAQ,CAAC;IACnC,6EAA6E;IAC7E,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3C,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CAAC;IACzC,mBAAmB,CAAC,EAAE,qBAAqB,CAAC;IAC5C,OAAO,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,YAAY,GAAG,IAAI,CAAC;CACnE,CAAC;AAkHF,eAAO,MAAM,eAAe,EAAE,EAAE,CAAC,oBAAoB,CAqWpD,CAAC"}
@@ -7,12 +7,23 @@ type RippleProps = {
7
7
  export declare const Ripple: FC<RippleProps>;
8
8
  type TButton = PropsWithChildren & ButtonHTMLAttributes<HTMLButtonElement> & {
9
9
  size: 'small' | 'medium' | 'big';
10
- variant: 'primary' | 'secondary' | 'outlined' | 'warning' | 'clean' | 'provider' | 'dark';
10
+ variant: 'primary' | 'secondary' | 'outlined' | 'warning' | 'clean' | 'provider' | 'dark' | 'option';
11
11
  type: 'button' | 'submit' | 'reset';
12
12
  withIcon?: boolean;
13
13
  asIcon?: boolean;
14
14
  className?: string;
15
15
  withRipple?: boolean;
16
+ /**
17
+ * The `option` variant's second line — the hint under the label. Rendered
18
+ * only by that variant, which owns the two-line geometry.
19
+ */
20
+ description?: string;
21
+ /**
22
+ * Toggle state for the `option` variant: mirrored to `aria-pressed` and
23
+ * styled by the variant itself, so no call site has to describe what
24
+ * "selected" looks like.
25
+ */
26
+ pressed?: boolean;
16
27
  };
17
28
  export declare const Button: FC<TButton>;
18
29
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/button/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,EAAE,EAGP,KAAK,iBAAiB,EAGvB,MAAM,OAAO,CAAC;AACf,OAAO,oBAAoB,CAAC;AAE5B,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CASlC,CAAC;AAEF,KAAK,OAAO,GAAG,iBAAiB,GAC9B,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IACxC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjC,OAAO,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;IAC1F,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,CAAC;AAEJ,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,OAAO,CA8D9B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/button/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,EAAE,EAGP,KAAK,iBAAiB,EAIvB,MAAM,OAAO,CAAC;AACf,OAAO,oBAAoB,CAAC;AAE5B,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,WAAW,CASlC,CAAC;AAEF,KAAK,OAAO,GAAG,iBAAiB,GAC9B,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IACxC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjC,OAAO,EAAE,SAAS,GAAG,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;IACrG,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEJ,eAAO,MAAM,MAAM,EAAE,EAAE,CAAC,OAAO,CA+F9B,CAAC"}
@@ -4,8 +4,10 @@ export { Button } from './button';
4
4
  export * from './fields';
5
5
  export * from './providers-box';
6
6
  export { Link } from './link';
7
+ export { Spinner, type SpinnerProps, type SpinnerSize } from './spinner';
7
8
  export { Switch } from './switch';
8
9
  export * from './popover';
9
10
  export * from './dialog';
10
11
  export * from './login-screen';
12
+ export { UpgradeDialog, UpgradeChallengeView, UpgradeFactorList, UpgradeStatus, type UpgradeStatusState, DEFAULT_FACTOR_LABELS, dialogOutcomeFromError, describeAssuranceBar, readAssuranceBar, UPGRADE_FACTOR_CODE_CONTRACTS, toDialogFactors, toDialogState, upgradeDialogDismissHandler, type ToDialogStateInput, type UpgradeChallengeSnapshot, type UpgradeDialogErrorKind, type UpgradeDialogHandlers, type UpgradeDialogLabels, type UpgradeDialogOutcome, type UpgradeDialogUiState, type UpgradeFactorSnapshot, type UpgradePromptSnapshot, type UpgradeDialogCancelledState, type UpgradeDialogChallengeState, type UpgradeDialogExhaustedState, type UpgradeDialogFactor, type UpgradeDialogInsufficientState, type UpgradeDialogProps, type UpgradeDialogState, type UpgradeDialogSuccessState, type UpgradeDialogTransportState, type UpgradeDialogUnavailableState, type UpgradeDialogUnsatisfiableState, type UpgradeDialogWorkingState, type UpgradeFactorCodeContract, } from './upgrade-dialog';
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAM/B,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,KAAK,kBAAkB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,6BAA6B,EAC7B,eAAe,EACf,aAAa,EACb,2BAA2B,EAC3B,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC7B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,6BAA6B,EAClC,KAAK,+BAA+B,EACpC,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { FC } from 'react';
2
+ export type SpinnerSize = 'small' | 'medium';
3
+ export type SpinnerProps = {
4
+ /** `small` sits inline beside a line of text; `medium` stands alone. */
5
+ size?: SpinnerSize;
6
+ /**
7
+ * The accessible name. Omit it when a sibling already announces the busy
8
+ * state — the ring is then decorative and hidden from assistive technology,
9
+ * which is what a status region with its own live text wants.
10
+ */
11
+ label?: string;
12
+ };
13
+ /**
14
+ * The indeterminate activity ring.
15
+ *
16
+ * It exists as a primitive so its diameter and stroke live in one place rather
17
+ * than in each consuming component's stylesheet. The upgrade dialog uses it;
18
+ * the login screen still draws its own identical ring in
19
+ * `login-screen.css` and should be migrated onto this when that file is next
20
+ * touched.
21
+ */
22
+ export declare const Spinner: FC<SpinnerProps>;
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/spinner/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,eAAe,CAAC;AAEvB,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG;IACzB,wEAAwE;IACxE,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CAOpC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { FC } from 'react';
2
+ import { UpgradeDialogChallengeState } from './types';
3
+ /**
4
+ * The collecting view: the suggested factor, its input affordance, the
5
+ * alternatives toggle, and the two terminal controls.
6
+ *
7
+ * Selection is reported through `onSelectFactor` before `onSubmit` ever fires —
8
+ * architecture §13.2's late-join boundary is factor selection, not submission,
9
+ * so the controller must learn of the choice while the user is still typing.
10
+ */
11
+ export declare const UpgradeChallengeView: FC<UpgradeDialogChallengeState>;
12
+ //# sourceMappingURL=challenge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/upgrade-dialog/challenge.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAoC,MAAM,OAAO,CAAC;AAKlE,OAAO,KAAK,EAAE,2BAA2B,EAAqB,MAAM,SAAS,CAAC;AAK9E;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,2BAA2B,CAoHhE,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { FC } from 'react';
2
+ import { UpgradeDialogFactor, UpgradeFactorType } from './types';
3
+ type UpgradeFactorListProps = {
4
+ factors: readonly UpgradeDialogFactor[];
5
+ selected: UpgradeFactorType;
6
+ disabled?: boolean;
7
+ label?: string;
8
+ onSelect: (factor: UpgradeFactorType) => void;
9
+ };
10
+ /**
11
+ * The "use another way" alternatives. Selecting one reports the user's choice;
12
+ * it never navigates.
13
+ *
14
+ * Each row is `Button variant='option'`: the two-line geometry and the pressed
15
+ * look belong to that variant in the button library, not to this list. The list
16
+ * contributes layout only.
17
+ */
18
+ export declare const UpgradeFactorList: FC<UpgradeFactorListProps>;
19
+ export {};
20
+ //# sourceMappingURL=factor-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factor-list.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/upgrade-dialog/factor-list.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEtE,KAAK,sBAAsB,GAAG;IAC5B,OAAO,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACxC,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAyBxD,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { UpgradeDialog } from './upgrade-dialog';
2
+ export { UpgradeChallengeView } from './challenge';
3
+ export { UpgradeFactorList } from './factor-list';
4
+ export { UPGRADE_SUCCESS_AUTO_CLOSE_MS, UpgradeStatus, type UpgradeStatusState } from './status';
5
+ export { DEFAULT_FACTOR_LABELS, dialogOutcomeFromError, describeAssuranceBar, readAssuranceBar, UPGRADE_FACTOR_CODE_CONTRACTS, toDialogFactors, toDialogState, upgradeDialogDismissHandler, } from './state-mapping';
6
+ export type { ToDialogStateInput, UpgradeChallengeSnapshot, UpgradeDialogErrorKind, UpgradeDialogHandlers, UpgradeDialogLabels, UpgradeDialogOutcome, UpgradeDialogUiState, UpgradeFactorSnapshot, UpgradePromptSnapshot, } from './state-mapping';
7
+ export type { AssuranceBar, UpgradeDialogCancelledState, UpgradeDialogChallengeState, UpgradeDialogExhaustedState, UpgradeDialogFactor, UpgradeDialogInsufficientState, UpgradeDialogProps, UpgradeDialogState, UpgradeDialogSuccessState, UpgradeDialogTransportState, UpgradeDialogUnavailableState, UpgradeDialogUnsatisfiableState, UpgradeDialogWorkingState, UpgradeFactorCodeContract, UpgradeFactorInput, UpgradeFactorType, } from './types';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/upgrade-dialog/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,6BAA6B,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACjG,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,gBAAgB,EAChB,6BAA6B,EAC7B,eAAe,EACf,aAAa,EACb,2BAA2B,GAC5B,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,kBAAkB,EAClB,wBAAwB,EACxB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,YAAY,EACZ,2BAA2B,EAC3B,2BAA2B,EAC3B,2BAA2B,EAC3B,mBAAmB,EACnB,8BAA8B,EAC9B,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,+BAA+B,EAC/B,yBAAyB,EACzB,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { AssuranceBar, UpgradeDialogFactor, UpgradeDialogState, UpgradeFactorCodeContract, UpgradeFactorInput, UpgradeFactorType } from './types';
2
+ export type UpgradeChallengeSnapshot = {
3
+ requiredLevel?: number;
4
+ acrValues?: string;
5
+ maxAge?: number;
6
+ };
7
+ export type UpgradeFactorSnapshot = {
8
+ type: UpgradeFactorType;
9
+ input: UpgradeFactorInput;
10
+ };
11
+ export type UpgradePromptSnapshot = {
12
+ challenge: UpgradeChallengeSnapshot;
13
+ /** Already ranked by `selectFactors`; index 0 is the suggested factor. */
14
+ factors: readonly UpgradeFactorSnapshot[];
15
+ previousError?: unknown;
16
+ };
17
+ export type UpgradeDialogLabels = Partial<Record<UpgradeFactorType, {
18
+ label: string;
19
+ hint?: string;
20
+ }>>;
21
+ /** How the flight ended, as the controller's outcome summary reports it (§13.4). */
22
+ export type UpgradeDialogOutcome = {
23
+ kind: 'elevated';
24
+ } | {
25
+ kind: 'insufficient';
26
+ obtained: AssuranceBar;
27
+ required: AssuranceBar;
28
+ } | {
29
+ kind: 'cancelled';
30
+ } | {
31
+ kind: 'failed';
32
+ error: unknown;
33
+ };
34
+ export type UpgradeDialogUiState = {
35
+ selected?: UpgradeFactorType | null;
36
+ busy?: boolean;
37
+ showAlternatives?: boolean;
38
+ };
39
+ export type UpgradeDialogHandlers = {
40
+ onSelectFactor: (factor: UpgradeFactorType) => void;
41
+ onToggleAlternatives: () => void;
42
+ onSubmit: (code?: string) => void;
43
+ onCancel: () => void;
44
+ onDismiss: () => void;
45
+ onRetry?: () => void;
46
+ };
47
+ export type ToDialogStateInput = {
48
+ prompt: UpgradePromptSnapshot | null;
49
+ outcome?: UpgradeDialogOutcome;
50
+ ui?: UpgradeDialogUiState;
51
+ labels?: UpgradeDialogLabels;
52
+ handlers: UpgradeDialogHandlers;
53
+ testId?: string;
54
+ };
55
+ /**
56
+ * How an elevation failure reads to the user. `rejected` is the retryable
57
+ * wrong-answer case, which keeps the dialog open on the challenge.
58
+ */
59
+ export type UpgradeDialogErrorKind = 'rejected' | 'cancelled' | 'exhausted' | 'unsatisfiable' | 'unavailable' | 'transport' | 'insufficient' | 'session-changed';
60
+ export declare const DEFAULT_FACTOR_LABELS: Record<UpgradeFactorType, {
61
+ label: string;
62
+ hint?: string;
63
+ }>;
64
+ /**
65
+ * Per-factor code contracts, keyed by the factor type, which is the only thing
66
+ * about a factor the protocol guarantees.
67
+ *
68
+ * `recovery_codes` is the reason this table exists. The server generates them
69
+ * at `DefaultRecoveryCodeLength` (12) from a 32-character alphanumeric charset
70
+ * and accepts a configured length anywhere in 6..16, so the cap is the server's
71
+ * MAXIMUM — capping at the default would reject a valid code on a deployment
72
+ * that raised it, and capping at six (the old single hardcoded number) rejected
73
+ * every code on every deployment. A shorter configured code simply types
74
+ * shorter; a cap can only ever do harm by being too small.
75
+ *
76
+ * `null` means the factor collects nothing typed: its proof comes from the
77
+ * ceremony, so there is no field and no contract to state.
78
+ */
79
+ export declare const UPGRADE_FACTOR_CODE_CONTRACTS: Readonly<{
80
+ totp: UpgradeFactorCodeContract;
81
+ email_otp: UpgradeFactorCodeContract;
82
+ sms_otp: UpgradeFactorCodeContract;
83
+ recovery_codes: UpgradeFactorCodeContract;
84
+ passkey: null;
85
+ }>;
86
+ /** Index 0 stays index 0: `selectFactors` already ranked the list, and ranking is not filtering. */
87
+ export declare const toDialogFactors: (factors: readonly UpgradeFactorSnapshot[], labels?: UpgradeDialogLabels) => UpgradeDialogFactor[];
88
+ /**
89
+ * How a failure reads to the user, as the dialog's own vocabulary.
90
+ *
91
+ * Named `dialogOutcomeFromError`, not `classifyUpgradeError`: that name belongs
92
+ * to `@passflow/core`, and holding it here shadowed core's symbol in the
93
+ * package's own star exports, which made the real classifier unreachable to
94
+ * consumers. This function decides nothing about what the error IS — core's
95
+ * classifier does — only which panel that kind is shown on.
96
+ *
97
+ * The dedicated error classes are matched before the kind table because they
98
+ * are not transport failures at all: they carry no `kind`, and core's
99
+ * classifier has nothing to say about them.
100
+ */
101
+ export declare const dialogOutcomeFromError: (error: unknown) => UpgradeDialogErrorKind;
102
+ export declare const readAssuranceBar: (value: unknown) => AssuranceBar | undefined;
103
+ /** Human wording for a bar, on whichever axis it constrains. */
104
+ export declare const describeAssuranceBar: (bar?: AssuranceBar) => string;
105
+ /**
106
+ * The single projection. A terminal `outcome` always wins over an open prompt;
107
+ * an empty offered factor list is the `no usable factor` outcome; a `busy`
108
+ * ceremony with no code to type is `working`; everything else is the challenge.
109
+ */
110
+ export declare const toDialogState: (input: ToDialogStateInput) => UpgradeDialogState;
111
+ /**
112
+ * What Escape and an overlay click mean in each state. Cancellation must reach
113
+ * the controller or the caller's promise hangs (§8.1), so this is never a bare
114
+ * close; `success` has nothing to cancel, so it closes instead of cancelling —
115
+ * returning `undefined` there made Escape and the overlay inert on the one
116
+ * state every user reaches.
117
+ */
118
+ export declare const upgradeDialogDismissHandler: (state: UpgradeDialogState) => (() => void) | undefined;
119
+ //# sourceMappingURL=state-mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-mapping.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/upgrade-dialog/state-mapping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { FC } from 'react';
2
+ import { UpgradeDialogState } from './types';
3
+ /** Every state that is not the collecting challenge. */
4
+ export type UpgradeStatusState = Exclude<UpgradeDialogState, {
5
+ kind: 'challenge';
6
+ }>;
7
+ /**
8
+ * How long `success` stays on screen before it closes itself (§13.4: "reports
9
+ * success and closes"). Long enough to be read, short enough that the app is
10
+ * never held behind a modal the user cannot see a reason for.
11
+ */
12
+ export declare const UPGRADE_SUCCESS_AUTO_CLOSE_MS = 1800;
13
+ /**
14
+ * The non-collecting views: `working`, `success` and the six terminal outcomes
15
+ * of §13.3's settlement table.
16
+ *
17
+ * `insufficient` is deliberately rendered in the problem tone with both bars
18
+ * shown: the elevation succeeded and the action still did not, and the dialog
19
+ * must not report success when the replay was re-challenged (§13.4).
20
+ *
21
+ * `success` owns its own exit: a Done control and an auto-close timer, both
22
+ * calling the state's `onDismiss`. The affordance lives here rather than in the
23
+ * provider because a modal that cannot be closed is a property of this
24
+ * component, and the Storybook story for the state has to show the way out.
25
+ */
26
+ export declare const UpgradeStatus: FC<UpgradeStatusState>;
27
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/upgrade-dialog/status.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,EAAa,MAAM,OAAO,CAAC;AAK3C,OAAO,KAAK,EAAgB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEhE,wDAAwD;AACxD,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC,CAAC;AAepF;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,OAAO,CAAC;AASlD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,EAAE,EAAE,CAAC,kBAAkB,CA4DhD,CAAC"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Presentational contract for the assurance-upgrade dialog.
3
+ *
4
+ * The dialog is a pure projection: it takes a discriminated state and emits
5
+ * callbacks. Every transition belongs to the controller (architecture §13.2),
6
+ * so nothing here is a state machine — it is the rendering union.
7
+ *
8
+ * `UpgradeFactorType` is declared locally on purpose: P4a must build and run
9
+ * with no `@passflow/core` runtime import, and the union is the only type the
10
+ * dialog needs from the protocol. A later phase re-points it at the package.
11
+ */
12
+ /** Factor types the upgrade protocol understands, named as `upgrade.type` on the wire. */
13
+ export type UpgradeFactorType = 'totp' | 'recovery_codes' | 'passkey' | 'email_otp' | 'sms_otp';
14
+ /** What the UI must collect before the factor can be asserted. */
15
+ export type UpgradeFactorInput = 'code' | 'none';
16
+ /**
17
+ * An assurance requirement or achievement, carrying both axes (§13.4).
18
+ * `level` is the parsed bar, `acrValues` the raw winning list, `maxAge` the
19
+ * freshness constraint when freshness is what was demanded.
20
+ */
21
+ export type AssuranceBar = {
22
+ acrValues?: string;
23
+ level?: number;
24
+ maxAge?: number;
25
+ };
26
+ /**
27
+ * What a factor's typed answer actually accepts — the factor's own contract,
28
+ * not the dialog's guess.
29
+ *
30
+ * It exists because the field used to cap input at a TOTP-shaped six
31
+ * characters for every factor, which silently truncated a recovery code: the
32
+ * server issues those from `services/totp/recovery.go` at
33
+ * `DefaultRecoveryCodeLength` (12) and validates a configured length anywhere
34
+ * in 6..16 (`model/two_factor.go`), from an alphanumeric charset. A six-digit
35
+ * numeric keypad is wrong for that answer on every axis — length, charset and
36
+ * autofill — so all three travel together with the factor instead of being
37
+ * restated at the input.
38
+ */
39
+ export type UpgradeFactorCodeContract = {
40
+ /** The longest answer the server can accept for this factor. */
41
+ maxLength: number;
42
+ /** A numeric OTP gets the numeric keypad; a recovery code is alphanumeric. */
43
+ inputMode: 'numeric' | 'text';
44
+ /** Only a genuine one-time code claims the OTP autofill contract. */
45
+ autoComplete: 'one-time-code' | 'off';
46
+ /** Recovery codes are issued upper-case; an OTP must not be re-cased. */
47
+ autoCapitalize: 'off' | 'characters';
48
+ };
49
+ type UpgradeDialogFactorBase = {
50
+ type: UpgradeFactorType;
51
+ /** 'Authenticator app' */
52
+ label: string;
53
+ /** 'Enter the code from your authenticator app' */
54
+ hint?: string;
55
+ };
56
+ /**
57
+ * A factor as the dialog renders it. The `input` discriminant carries the code
58
+ * contract rather than leaving it optional: a `'code'` factor with no contract
59
+ * is unrepresentable, so the truncation defect cannot return by omission.
60
+ */
61
+ export type UpgradeDialogFactor = (UpgradeDialogFactorBase & {
62
+ input: 'none';
63
+ }) | (UpgradeDialogFactorBase & {
64
+ input: 'code';
65
+ code: UpgradeFactorCodeContract;
66
+ });
67
+ export type UpgradeDialogChallengeState = {
68
+ kind: 'challenge';
69
+ /** Already ranked; index 0 is the suggested factor. */
70
+ factors: readonly UpgradeDialogFactor[];
71
+ selected: UpgradeFactorType;
72
+ reason?: string;
73
+ busy?: boolean;
74
+ error?: string | null;
75
+ showAlternatives?: boolean;
76
+ submitLabel?: string;
77
+ cancelLabel?: string;
78
+ alternativesLabel?: string;
79
+ testId?: string;
80
+ /**
81
+ * Reports the user's factor choice. Called the moment a factor is picked and
82
+ * always before `onSubmit`, which is the late-join boundary of §13.2 (T3).
83
+ */
84
+ onSelectFactor: (factor: UpgradeFactorType) => void;
85
+ onToggleAlternatives: () => void;
86
+ onSubmit: (code?: string) => void;
87
+ onCancel: () => void;
88
+ };
89
+ export type UpgradeDialogWorkingState = {
90
+ kind: 'working';
91
+ message: string;
92
+ detail?: string;
93
+ testId?: string;
94
+ onCancel?: () => void;
95
+ };
96
+ /**
97
+ * Every waiter replayed cleanly and no stated bar went unmet (§13.4).
98
+ *
99
+ * Success is the happy path, so it is the one state that must never be able to
100
+ * trap the user: §13.4's story table says the modal "reports success and
101
+ * closes". `onDismiss` is therefore required, not optional — it is what Escape,
102
+ * an overlay click, the Done control and the auto-close timer all call.
103
+ * `autoCloseMs` is the timer's dwell; `0` disables it and leaves the explicit
104
+ * control as the only path out.
105
+ */
106
+ export type UpgradeDialogSuccessState = {
107
+ kind: 'success';
108
+ message: string;
109
+ detail?: string;
110
+ dismissLabel?: string;
111
+ /** Milliseconds before the dialog closes itself. Omitted: the component's default. */
112
+ autoCloseMs?: number;
113
+ testId?: string;
114
+ onDismiss: () => void;
115
+ };
116
+ /**
117
+ * Elevated, and still not enough: the replay was re-challenged (§13.3, §13.4).
118
+ * This state must never read as success — it is the honest
119
+ * "elevated to AAL2; this action requires AAL3" message.
120
+ */
121
+ export type UpgradeDialogInsufficientState = {
122
+ kind: 'insufficient';
123
+ message: string;
124
+ obtained: AssuranceBar;
125
+ required: AssuranceBar;
126
+ detail?: string;
127
+ dismissLabel?: string;
128
+ testId?: string;
129
+ onDismiss: () => void;
130
+ };
131
+ /** The offered factor list is empty — `no usable factor` of §13.3's table. */
132
+ export type UpgradeDialogUnsatisfiableState = {
133
+ kind: 'unsatisfiable';
134
+ message: string;
135
+ /** The diagnostic line: what was demanded, and why nothing could answer it. */
136
+ detail?: string;
137
+ required?: AssuranceBar;
138
+ dismissLabel?: string;
139
+ testId?: string;
140
+ onDismiss: () => void;
141
+ };
142
+ /** 501 / BFF — the deployment cannot elevate at all. */
143
+ export type UpgradeDialogUnavailableState = {
144
+ kind: 'unavailable';
145
+ message: string;
146
+ detail?: string;
147
+ dismissLabel?: string;
148
+ testId?: string;
149
+ onDismiss: () => void;
150
+ };
151
+ /** The attempt budget ran out. */
152
+ export type UpgradeDialogExhaustedState = {
153
+ kind: 'exhausted';
154
+ message: string;
155
+ detail?: string;
156
+ dismissLabel?: string;
157
+ testId?: string;
158
+ onDismiss: () => void;
159
+ };
160
+ /** A transport failure — FR1's non-retryable 400, or a retryable network fault. */
161
+ export type UpgradeDialogTransportState = {
162
+ kind: 'transport';
163
+ message: string;
164
+ detail?: string;
165
+ retryable?: boolean;
166
+ retryLabel?: string;
167
+ dismissLabel?: string;
168
+ testId?: string;
169
+ onRetry?: () => void;
170
+ onDismiss: () => void;
171
+ };
172
+ /** The user dismissed the dialog, or a passkey ceremony was cancelled. */
173
+ export type UpgradeDialogCancelledState = {
174
+ kind: 'cancelled';
175
+ message: string;
176
+ detail?: string;
177
+ dismissLabel?: string;
178
+ testId?: string;
179
+ onDismiss: () => void;
180
+ };
181
+ export type UpgradeDialogState = UpgradeDialogChallengeState | UpgradeDialogWorkingState | UpgradeDialogSuccessState | UpgradeDialogInsufficientState | UpgradeDialogUnsatisfiableState | UpgradeDialogUnavailableState | UpgradeDialogExhaustedState | UpgradeDialogTransportState | UpgradeDialogCancelledState;
182
+ export type UpgradeDialogProps = {
183
+ open: boolean;
184
+ title?: string;
185
+ state: UpgradeDialogState;
186
+ };
187
+ export {};
188
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/upgrade-dialog/types.ts"],"names":[],"mappings":"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"}