@frontmcp/ui 1.3.0 → 1.4.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 (42) hide show
  1. package/auth/AuthPageWrapper.d.ts +56 -0
  2. package/auth/AuthPageWrapper.d.ts.map +1 -0
  3. package/auth/context.d.ts +23 -0
  4. package/auth/context.d.ts.map +1 -0
  5. package/auth/contract.d.ts +276 -0
  6. package/auth/contract.d.ts.map +1 -0
  7. package/auth/hooks.d.ts +83 -0
  8. package/auth/hooks.d.ts.map +1 -0
  9. package/auth/hydrate.d.ts +50 -0
  10. package/auth/hydrate.d.ts.map +1 -0
  11. package/auth/index.d.ts +23 -0
  12. package/auth/index.d.ts.map +1 -0
  13. package/auth/index.js +421 -0
  14. package/auth/vanilla/auth-flow.d.ts +96 -0
  15. package/auth/vanilla/auth-flow.d.ts.map +1 -0
  16. package/auth/vanilla/index.d.ts +14 -0
  17. package/auth/vanilla/index.d.ts.map +1 -0
  18. package/auth/vanilla/index.js +251 -0
  19. package/bridge/adapters/base-adapter.d.ts +2 -1
  20. package/bridge/adapters/base-adapter.d.ts.map +1 -1
  21. package/bridge/adapters/ext-apps.adapter.d.ts +6 -1
  22. package/bridge/adapters/ext-apps.adapter.d.ts.map +1 -1
  23. package/bridge/adapters/openai.adapter.d.ts +9 -1
  24. package/bridge/adapters/openai.adapter.d.ts.map +1 -1
  25. package/bridge/core/bridge-factory.d.ts +7 -2
  26. package/bridge/core/bridge-factory.d.ts.map +1 -1
  27. package/bridge/index.d.ts +1 -1
  28. package/bridge/index.d.ts.map +1 -1
  29. package/bridge/index.js +38 -0
  30. package/bridge/runtime/iife-generator.d.ts.map +1 -1
  31. package/bridge/types.d.ts +24 -0
  32. package/bridge/types.d.ts.map +1 -1
  33. package/components/Modal/Modal.d.ts +1 -1
  34. package/esm/auth/index.mjs +398 -0
  35. package/esm/auth/vanilla/index.mjs +228 -0
  36. package/esm/bridge/index.mjs +38 -0
  37. package/esm/index.mjs +8 -0
  38. package/esm/package.json +22 -2
  39. package/esm/react/index.mjs +8 -0
  40. package/index.js +8 -0
  41. package/package.json +22 -2
  42. package/react/index.js +8 -0
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `<AuthPageWrapper>` — outer chrome for a FrontMCP `@AuthUi` component.
3
+ *
4
+ * Responsibilities (client side):
5
+ * - Reads the server-injected {@link AuthFlowState} once and exposes it via
6
+ * React context so the `useAuthFlow*` hooks can consume it.
7
+ * - Provides the in-memory `update` so a successful `submitExtra` can refresh
8
+ * `addedItems` without a full reload.
9
+ * - Renders children inside a `<form>` whose `action`/`method` already point at
10
+ * the server's submit target (and which carries the `pending_auth_id` + `csrf`
11
+ * hidden fields), so a no-JS submit still works.
12
+ *
13
+ * CSP, anti-clickjacking headers, and minting the CSRF token are the SERVER's
14
+ * responsibility at SSR time (stage 2). The wrapper only consumes the injected
15
+ * `csrfToken` and posts it back correctly.
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+ import { type ReactElement, type ReactNode } from 'react';
20
+ import { type AuthFlowState } from './contract';
21
+ /**
22
+ * Props for {@link AuthPageWrapper}.
23
+ */
24
+ export interface AuthPageWrapperProps {
25
+ /** The developer's auth UI. */
26
+ children: ReactNode;
27
+ /**
28
+ * Override the flow state instead of reading the injected global. Primarily
29
+ * for tests and storybook; production pages omit this and let the server
30
+ * injection drive the wrapper.
31
+ */
32
+ state?: AuthFlowState;
33
+ /**
34
+ * When false, render children WITHOUT an enclosing `<form>` (the developer
35
+ * supplies their own forms and drives submits via the hooks). Defaults to
36
+ * true so a no-JS finish submit works out of the box.
37
+ */
38
+ renderForm?: boolean;
39
+ /** Extra class name applied to the wrapper element. */
40
+ className?: string;
41
+ }
42
+ /**
43
+ * Standalone provider (no chrome) — useful when the developer wants full
44
+ * control of layout but still needs the hooks. {@link AuthPageWrapper} builds
45
+ * on this.
46
+ */
47
+ export declare function AuthFlowProvider({ children, state: stateOverride, }: {
48
+ children: ReactNode;
49
+ state?: AuthFlowState;
50
+ }): ReactElement;
51
+ /**
52
+ * The outer chrome. By default wraps children in a `<form>` that posts to the
53
+ * server's submit target with the control fields pre-populated.
54
+ */
55
+ export declare function AuthPageWrapper({ children, state: stateOverride, renderForm, className, }: AuthPageWrapperProps): ReactElement;
56
+ //# sourceMappingURL=AuthPageWrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AuthPageWrapper.d.ts","sourceRoot":"","sources":["../../src/auth/AuthPageWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAiC,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAGzF,OAAO,EAAoE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAGlH;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,KAAK,EAAE,aAAa,GACrB,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;IACpB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,GAAG,YAAY,CAef;AAoBD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,KAAK,EAAE,aAAa,EACpB,UAAiB,EACjB,SAAS,GACV,EAAE,oBAAoB,GAAG,YAAY,CAQrC"}
@@ -0,0 +1,23 @@
1
+ import type { AuthFlowState } from './contract';
2
+ /**
3
+ * The value provided by {@link AuthPageWrapper} / {@link AuthFlowProvider}.
4
+ */
5
+ export interface AuthFlowContextValue {
6
+ /** The current flow state (injected by the server, mutated client-side on extra success). */
7
+ state: AuthFlowState;
8
+ /**
9
+ * Merge a partial update into the in-memory flow state (e.g. refreshed
10
+ * `addedItems` returned by a `submitExtra`). Does not touch the server.
11
+ */
12
+ update: (patch: Partial<AuthFlowState>) => void;
13
+ }
14
+ /**
15
+ * Context handle. `null` outside a provider so hooks can throw a clear error.
16
+ */
17
+ export declare const AuthFlowContext: import("react").Context<AuthFlowContextValue | null>;
18
+ /**
19
+ * Internal accessor used by the hooks; throws when used outside
20
+ * {@link AuthPageWrapper} / {@link AuthFlowProvider}.
21
+ */
22
+ export declare function useAuthFlowContext(): AuthFlowContextValue;
23
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/auth/context.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,6FAA6F;IAC7F,KAAK,EAAE,aAAa,CAAC;IACrB;;;OAGG;IACH,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;CACjD;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,sDAAmD,CAAC;AAEhF;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,oBAAoB,CAMzD"}
@@ -0,0 +1,276 @@
1
+ /**
2
+ * Framework-free Auth-UI contract (no React).
3
+ *
4
+ * This module is the SINGLE SOURCE OF TRUTH for the CLIENT side of the bridge
5
+ * between a FrontMCP authorization page (a thin server shell) and the client
6
+ * code that renders + drives it. It is the canonical client API, so it lives in
7
+ * `@frontmcp/ui/auth` (this package) co-located with the vanilla helpers + React
8
+ * hooks/mount that consume it. It has ZERO React dependency on purpose so the
9
+ * vanilla helpers (and a non-React page) can use it directly.
10
+ *
11
+ * The SERVER side (`@frontmcp/sdk`'s `auth-ui` module) does NOT import this
12
+ * file — it owns its own minimal write-shape types + the two runtime protocol
13
+ * constants as local literals, kept in sync with the values declared here. That
14
+ * JSON-serialization boundary (server-owned write-shape, client-owned
15
+ * read-shape) is intentional and deliberately avoids an `sdk → ui` dependency;
16
+ * the local-auth e2e asserts the `window.__FRONTMCP_AUTH__` wire shape to guard
17
+ * against drift.
18
+ *
19
+ * ## How the bridge works
20
+ *
21
+ * 1. When serving the shell the server serializes an {@link AuthFlowState} into
22
+ * a `<script>` that assigns it to the global named by
23
+ * {@link AUTH_FLOW_GLOBAL_KEY} (`window.__FRONTMCP_AUTH__`). This mirrors the
24
+ * `window.__mcp*` / `window.FrontMcpBridge` injection pattern used by
25
+ * `@frontmcp/uipack` and `@frontmcp/ui` for tool widgets.
26
+ * 2. The client bundle (the developer's `@AuthUi` component, client-rendered via
27
+ * `mountAuthPage` from `@frontmcp/ui/auth`) reads that global through
28
+ * `getAuthFlow()` and drives the OAuth flow with `submitFinish` /
29
+ * `submitExtra`.
30
+ *
31
+ * The server owns CSP, anti-clickjacking headers, and minting the
32
+ * {@link AuthFlowState.csrfToken}; the client only consumes the token and posts
33
+ * it back. No PII is part of the required contract — identity values the user
34
+ * types are carried by the developer's own form fields, not by this state.
35
+ *
36
+ * @packageDocumentation
37
+ */
38
+ /**
39
+ * Which built-in authorization page slot a component renders.
40
+ *
41
+ * Mirrors the server-side `@AuthUi({ slot })` slots from issue #469 and the
42
+ * existing in-tree pages produced by the OAuth authorize/callback flows:
43
+ *
44
+ * - `login` — the local sign-in page (`renderLocalLoginPage`).
45
+ * - `consent` — the tool-consent screen (`buildToolConsentPage`).
46
+ * - `incremental` — single-app incremental authorization (`buildIncrementalAuthPage`).
47
+ * - `federated` — multi-provider selection (`buildFederatedLoginPage`).
48
+ * - `error` — the OAuth error page.
49
+ */
50
+ export type AuthSlot = 'login' | 'consent' | 'incremental' | 'federated' | 'error';
51
+ /**
52
+ * The HTTP method the auth submit/extra requests use.
53
+ *
54
+ * The in-tree pages today POST the consent app-cards but GET the login,
55
+ * federated, consent, and incremental forms back to `/oauth/callback` (a GET
56
+ * round-trip mirroring the federated page). The contract carries the method so
57
+ * stage 2 can pick per-slot without the client hardcoding it; it defaults to
58
+ * `GET` to match the current callback flow.
59
+ */
60
+ export type AuthSubmitMethod = 'GET' | 'POST';
61
+ /**
62
+ * A selectable authentication provider surfaced on the federated-login slot.
63
+ *
64
+ * Derived from the `ProviderCard` the authorize flow builds for
65
+ * `buildFederatedLoginPage`. Only display + selection fields are exposed to the
66
+ * client; nothing secret (client secrets, provider tokens) is ever included.
67
+ */
68
+ export interface AuthProvider {
69
+ /** Stable provider id submitted back as a `providers` value. */
70
+ id: string;
71
+ /** Human-readable provider name for display. */
72
+ name: string;
73
+ /** Optional provider authorize URL (transparent/remote providers only). */
74
+ url?: string;
75
+ /** Auth mode label (e.g. `local`, `transparent`, `remote`). */
76
+ mode?: string;
77
+ /** App ids associated with this provider (filtered of internal sentinels). */
78
+ appIds?: string[];
79
+ /** Whether this is the primary/parent provider (pre-checked by default). */
80
+ primary?: boolean;
81
+ }
82
+ /**
83
+ * A selectable tool surfaced on the consent slot.
84
+ *
85
+ * Derived from the `ToolCard` the callback flow builds for
86
+ * `buildToolConsentPage`. The `id` is the effective runtime tool id submitted
87
+ * back as a `tools` value and enforced at call time.
88
+ */
89
+ export interface AuthTool {
90
+ /** Effective runtime tool id (submitted back as a `tools` value). */
91
+ id: string;
92
+ /** Display name. */
93
+ name: string;
94
+ /** Optional description. */
95
+ description?: string;
96
+ /** Owning app id (for grouping). */
97
+ appId?: string;
98
+ /** Owning app display name (for grouping). */
99
+ appName?: string;
100
+ /** Whether the tool is pre-selected. */
101
+ defaultSelected?: boolean;
102
+ }
103
+ /**
104
+ * The serialized authorization-flow state the server injects and the client
105
+ * reads. Field names map to what `oauth.authorize.flow.ts` /
106
+ * `oauth.callback.flow.ts` already compute for the built-in pages, so stage 2
107
+ * can populate this from existing flow state without new plumbing.
108
+ *
109
+ * NO PII is part of the contract. `clientName`/`clientId` are OAuth client
110
+ * identifiers (not end-user identity), and identity values the user enters are
111
+ * carried by the developer's own form fields — never serialized here.
112
+ */
113
+ export interface AuthFlowState {
114
+ /** Which page slot this state is for. */
115
+ slot: AuthSlot;
116
+ /**
117
+ * The pending authorization id (`pending_auth_id`). Round-tripped on every
118
+ * submit/extra request so the server can correlate the flow. Optional only
119
+ * for the `error` slot, which may render before a pending record exists.
120
+ */
121
+ pendingAuthId?: string;
122
+ /** OAuth client display name (CIMD `client_name` or the raw client id). */
123
+ clientName?: string;
124
+ /** OAuth `client_id`. */
125
+ clientId?: string;
126
+ /** Requested OAuth scopes (split from the `scope` param). */
127
+ scopes?: string[];
128
+ /** Validated OAuth `redirect_uri` (where the server sends the code). */
129
+ redirectUri?: string;
130
+ /** RFC 8707 `resource` indicator, when supplied. */
131
+ resource?: string;
132
+ /** Human-readable error text for the `error` slot (or a failed submit re-render). */
133
+ error?: string;
134
+ /**
135
+ * Anti-CSRF token the server minted at SSR time. The client posts it back in
136
+ * the `csrf` field on every submit/extra. Minting + verifying it is the
137
+ * SERVER's responsibility (stage 2); the client only echoes it.
138
+ */
139
+ csrfToken?: string;
140
+ /**
141
+ * Absolute or app-relative URL the finish submit posts to. The in-tree pages
142
+ * use `${scope.fullPath}/oauth/callback`. Required for any interactive slot.
143
+ */
144
+ submitUrl?: string;
145
+ /**
146
+ * HTTP method for the finish submit. Defaults to {@link DEFAULT_SUBMIT_METHOD}
147
+ * (`GET`) to match the current callback round-trip.
148
+ */
149
+ submitMethod?: AuthSubmitMethod;
150
+ /**
151
+ * Optional dedicated URL for `submitExtra` (the `@AuthExtra` validated-field
152
+ * endpoint, issue #469). When omitted, extras post to {@link submitUrl} with
153
+ * an {@link AUTH_EXTRA_FIELD action} field naming the extra. Stage 2 may
154
+ * expose a separate endpoint and set this.
155
+ */
156
+ extraUrl?: string;
157
+ /** Providers offered on the `federated` slot. */
158
+ providers?: AuthProvider[];
159
+ /** Tools offered on the `consent` slot. */
160
+ tools?: AuthTool[];
161
+ /**
162
+ * Server-side accumulators for multi-step inputs, keyed by extra name. Each
163
+ * value is the list of items the server has accepted so far (e.g. the
164
+ * `envs` a user added). Read by `getAddedItems(name)` / `useAddedItems(name)`.
165
+ * The server replaces this on each re-render / extra response.
166
+ */
167
+ addedItems?: Record<string, unknown[]>;
168
+ /**
169
+ * Free-form, slot-specific extras the server wants to pass to the component
170
+ * (e.g. logo URI, custom messages, incremental target app). Kept open so
171
+ * stage 2 can extend per-slot without a contract change.
172
+ */
173
+ extras?: Record<string, unknown>;
174
+ }
175
+ /**
176
+ * The global property name the server injects the {@link AuthFlowState} under.
177
+ *
178
+ * Analogous to `window.FrontMcpBridge` (the tool-widget bridge) but for auth:
179
+ * `window.__FRONTMCP_AUTH__: AuthFlowState`. The double-underscore form matches
180
+ * the `window.__mcp*` data-injection convention in `@frontmcp/uipack`.
181
+ *
182
+ * The server declares this same literal locally (`@frontmcp/sdk`'s `auth-ui`
183
+ * module) — keep the two in sync.
184
+ */
185
+ export declare const AUTH_FLOW_GLOBAL_KEY: "__FRONTMCP_AUTH__";
186
+ /**
187
+ * Default HTTP method for the finish submit when the state omits one. `GET`
188
+ * matches the current `/oauth/callback` round-trip used by the in-tree login,
189
+ * consent, federated, and incremental pages.
190
+ */
191
+ export declare const DEFAULT_SUBMIT_METHOD: AuthSubmitMethod;
192
+ /**
193
+ * Canonical wire field names shared by the server flows and the client helpers.
194
+ *
195
+ * These mirror the exact params the OAuth callback flow reads today
196
+ * (`oauth.callback.flow.ts`), so the client posts what the server already
197
+ * understands and stage 2 does not have to invent a new vocabulary.
198
+ */
199
+ export declare const AUTH_WIRE_FIELDS: {
200
+ /** Pending authorization id. */
201
+ readonly pendingAuthId: "pending_auth_id";
202
+ /** Anti-CSRF token. */
203
+ readonly csrf: "csrf";
204
+ /** Marks a consent-form submission (distinguishes empty-select from first visit). */
205
+ readonly consentSubmitted: "consent_submitted";
206
+ /** Repeated checkbox field carrying selected tool ids on the consent slot. */
207
+ readonly tools: "tools";
208
+ /** Marks a federated submission. */
209
+ readonly federated: "federated";
210
+ /** Repeated checkbox field carrying selected provider ids on the federated slot. */
211
+ readonly providers: "providers";
212
+ /** Marks an incremental authorization. */
213
+ readonly incremental: "incremental";
214
+ /** Target app id for incremental authorization. */
215
+ readonly appId: "app_id";
216
+ /** Generic action discriminator (e.g. consent `authorize`/`skip`, or an extra name). */
217
+ readonly action: "action";
218
+ };
219
+ /**
220
+ * The value placed in the {@link AUTH_WIRE_FIELDS.consentSubmitted} field to
221
+ * mark a consent submission (the callback flow checks for the literal `'1'`).
222
+ */
223
+ export declare const CONSENT_SUBMITTED_VALUE: "1";
224
+ /**
225
+ * The value placed in the {@link AUTH_WIRE_FIELDS.federated} /
226
+ * {@link AUTH_WIRE_FIELDS.incremental} markers (the callback flow checks for
227
+ * the literal `'true'`).
228
+ */
229
+ export declare const WIRE_TRUE: "true";
230
+ /**
231
+ * The field name used to carry the extra/action name when `submitExtra` posts
232
+ * to the shared {@link AuthFlowState.submitUrl} (no dedicated `extraUrl`). The
233
+ * server's `@AuthExtra(name)` handler reads this to route the validated field.
234
+ */
235
+ export declare const AUTH_EXTRA_FIELD: "action";
236
+ /**
237
+ * Default mount id the server SSRs the auth component into (and the client
238
+ * hydrates onto). The server declares this same literal locally (`@frontmcp/sdk`'s
239
+ * `auth-ui` module) — keep the two in sync.
240
+ */
241
+ export declare const DEFAULT_AUTH_MOUNT_ID = "frontmcp-auth-root";
242
+ /**
243
+ * Result of a `submitExtra` call (a validated `@AuthExtra` field round-trip).
244
+ *
245
+ * Mirrors the server-side `@AuthExtra(name)` return shape from issue #469
246
+ * (`{ ok, error?, sideEffects? }`). `addedItems` lets a successful extra hand
247
+ * back the updated accumulator so the client can refresh without a full reload.
248
+ */
249
+ export interface AuthExtraResult {
250
+ /** Whether the server accepted the field. */
251
+ ok: boolean;
252
+ /** Human-readable validation error when `ok` is false. */
253
+ error?: string;
254
+ /** Updated server-side accumulators (keyed by extra name) after a successful add. */
255
+ addedItems?: Record<string, unknown[]>;
256
+ /** Free-form side-effect data the server chooses to return. */
257
+ sideEffects?: Record<string, unknown>;
258
+ }
259
+ /**
260
+ * Form data accepted by `submitFinish` / `submitExtra`. Either a real
261
+ * `FormData`, a plain record, or a form `EventTarget` (so a React/DOM
262
+ * `onSubmit` handler can pass `event.currentTarget` directly).
263
+ */
264
+ export type AuthFormInput = FormData | Record<string, unknown> | HTMLFormElement;
265
+ /**
266
+ * Augment the global object so `window.__FRONTMCP_AUTH__` is typed wherever the
267
+ * contract is in scope. Declared on both `Window` and `globalThis` so it works
268
+ * in the browser and under jsdom/node test environments.
269
+ */
270
+ declare global {
271
+ interface Window {
272
+ [AUTH_FLOW_GLOBAL_KEY]?: AuthFlowState;
273
+ }
274
+ var __FRONTMCP_AUTH__: AuthFlowState | undefined;
275
+ }
276
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/auth/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * React hooks for FrontMCP `@AuthUi` components, built on the framework-free
3
+ * vanilla core. They read the injected {@link AuthFlowState} via context (set
4
+ * up by {@link AuthPageWrapper}) and expose typed accessors + submit handlers.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { type FormEvent } from 'react';
9
+ import type { AuthExtraResult, AuthFlowState, AuthFormInput, AuthProvider, AuthSlot, AuthTool } from './contract';
10
+ /**
11
+ * The shape returned by {@link useAuthFlow}: the injected state fields plus the
12
+ * `submitFinish` handler. `submitFinish` accepts a React form event or explicit
13
+ * data, so `<form onSubmit={submitFinish}>` works directly.
14
+ */
15
+ export interface UseAuthFlowResult {
16
+ /** Which page slot is being rendered. */
17
+ slot: AuthSlot;
18
+ /** Pending authorization id. */
19
+ pendingAuthId?: string;
20
+ /** OAuth client display name. */
21
+ clientName?: string;
22
+ /** OAuth client id. */
23
+ clientId?: string;
24
+ /** Requested scopes. */
25
+ scopes: string[];
26
+ /** Validated redirect URI. */
27
+ redirectUri?: string;
28
+ /** RFC 8707 resource indicator. */
29
+ resource?: string;
30
+ /** Error text (error slot or a failed-submit re-render). */
31
+ error?: string;
32
+ /** Providers offered on the federated slot. */
33
+ providers: AuthProvider[];
34
+ /** Tools offered on the consent slot. */
35
+ tools: AuthTool[];
36
+ /** Free-form slot extras the server passed through. */
37
+ extras: Record<string, unknown>;
38
+ /** The full raw state (escape hatch). */
39
+ state: AuthFlowState;
40
+ /**
41
+ * Finish the flow. Pass nothing to submit the enclosing wrapper form, a React
42
+ * `FormEvent` (it will `preventDefault` and serialize `event.currentTarget`),
43
+ * or explicit form data.
44
+ */
45
+ submitFinish: (formOrEvent?: FormEvent<HTMLFormElement> | AuthFormInput) => Promise<Response>;
46
+ }
47
+ /**
48
+ * Primary auth hook: returns the injected flow state plus a `submitFinish`
49
+ * handler. Everything OAuth (pending id, csrf, submit target, slot markers) is
50
+ * already wired by the vanilla core — the developer only renders UI.
51
+ */
52
+ export declare function useAuthFlow(): UseAuthFlowResult;
53
+ /**
54
+ * Return the server-side accumulator for a named multi-step input, reactively.
55
+ * Reads from context so it re-renders when {@link AuthPageWrapper} updates the
56
+ * state after a successful {@link useExtraField} submit.
57
+ */
58
+ export declare function useAddedItems<T = unknown>(name: string): T[];
59
+ /**
60
+ * The handle returned by {@link useExtraField}: an `onSubmit` you bind to a
61
+ * `<form>`, plus the last result and a pending flag.
62
+ */
63
+ export interface UseExtraFieldResult {
64
+ /**
65
+ * Form submit handler. Calls `submitExtra(name, ...)`, surfaces the
66
+ * `{ ok, error }` result, and merges any returned `addedItems` back into the
67
+ * flow state so {@link useAddedItems} updates.
68
+ */
69
+ onSubmit: (formOrEvent?: FormEvent<HTMLFormElement> | AuthFormInput) => Promise<AuthExtraResult>;
70
+ /** The most recent result (`undefined` until the first submit). */
71
+ result?: AuthExtraResult;
72
+ /** Whether a submit is in flight. */
73
+ pending: boolean;
74
+ }
75
+ /**
76
+ * Declare a custom validated field (a `@AuthExtra(name)` round-trip). Returns
77
+ * an `onSubmit` handler for the field's form; on success it refreshes the
78
+ * matching `addedItems` accumulator in context.
79
+ *
80
+ * @param name The extra's name (must match the server's `@AuthExtra(name)`).
81
+ */
82
+ export declare function useExtraField(name: string): UseExtraFieldResult;
83
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/auth/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG9D,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGlH;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,IAAI,EAAE,QAAQ,CAAC;IACf,gCAAgC;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uBAAuB;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,8BAA8B;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,yCAAyC;IACzC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,yCAAyC;IACzC,KAAK,EAAE,aAAa,CAAC;IACrB;;;;OAIG;IACH,YAAY,EAAE,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,GAAG,aAAa,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CAC/F;AAgBD;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,iBAAiB,CAwB/C;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,EAAE,CAI5D;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,SAAS,CAAC,eAAe,CAAC,GAAG,aAAa,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IACjG,mEAAmE;IACnE,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,CAgC/D"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Client mount entry for a FrontMCP auth page.
3
+ *
4
+ * The server serves a thin HTML shell with an EMPTY `#frontmcp-auth-root` mount
5
+ * node, the injected {@link AuthFlowState} global, and a bundle that calls
6
+ * {@link mountAuthPage} to render the developer's `@AuthUi` component into that
7
+ * node in the BROWSER (pure client render — no server-side React, no
8
+ * hydration). The component is wrapped in {@link AuthPageWrapper} so the
9
+ * `useAuthFlow*` hooks have their context, and the injected state is read
10
+ * automatically.
11
+ *
12
+ * @packageDocumentation
13
+ */
14
+ import { type ComponentType } from 'react';
15
+ import { type Root } from 'react-dom/client';
16
+ import { type AuthFlowState } from './contract';
17
+ /** Re-export the framework-free mount id (single source of truth in `./contract`). */
18
+ export { DEFAULT_AUTH_MOUNT_ID } from './contract';
19
+ /**
20
+ * Options for {@link mountAuthPage}.
21
+ */
22
+ export interface MountAuthPageOptions {
23
+ /**
24
+ * The container to render into. Accepts an element or a selector; defaults to
25
+ * `#frontmcp-auth-root` (the empty mount node the server shell ships).
26
+ */
27
+ container?: Element | string;
28
+ /**
29
+ * Override the flow state instead of reading the injected global (tests /
30
+ * preview). Production omits this.
31
+ */
32
+ state?: AuthFlowState;
33
+ /**
34
+ * Whether the wrapper renders its enclosing `<form>`. Mirrors
35
+ * {@link AuthPageWrapper}'s `renderForm` (default true).
36
+ */
37
+ renderForm?: boolean;
38
+ }
39
+ /**
40
+ * Render `Component` (a developer `@AuthUi` page) into the (empty) mount node in
41
+ * the browser, wrapping it in {@link AuthPageWrapper}. This is a PURE client
42
+ * render via `createRoot(...).render(...)` — the server ships no component
43
+ * markup, so there is nothing to hydrate.
44
+ *
45
+ * @param Component The page component to render.
46
+ * @param options Container / state / form overrides.
47
+ * @returns The React {@link Root} (so callers can `unmount()` in tests).
48
+ */
49
+ export declare function mountAuthPage(Component: ComponentType, options?: MountAuthPageOptions): Root;
50
+ //# sourceMappingURL=hydrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../../src/auth/hydrate.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAGzD,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE,sFAAsF;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEnD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC7B;;;OAGG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,aAAa,EAAE,OAAO,GAAE,oBAAyB,GAAG,IAAI,CAShG"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `@frontmcp/ui/auth` — client-side primitives for FrontMCP custom
3
+ * authorization UIs (issue #469): the framework-free contract (no React) plus
4
+ * React hooks + chrome built on the framework-free vanilla core.
5
+ *
6
+ * This subpath is the SINGLE SOURCE OF TRUTH for the client-side auth contract
7
+ * (`AuthFlowState`, `AuthSlot`, the wire constants, …). It imports ONLY `react`
8
+ * / `react-dom` (peer) — NEVER `@mui/material` / `@emotion` — so the auth page
9
+ * loads a lean module from esm.sh.
10
+ *
11
+ * Entry points:
12
+ * - `@frontmcp/ui/auth` — contract + vanilla helpers + React hooks/wrapper/mount.
13
+ * - `@frontmcp/ui/auth/vanilla` — framework-free flow helpers (`getAuthFlow`, `submitFinish`, `submitExtra`, `getAddedItems`).
14
+ *
15
+ * @packageDocumentation
16
+ */
17
+ export * from './contract';
18
+ export { getAddedItems, getAuthFlow, setAuthNavigator, submitExtra, submitFinish, tryGetAuthFlow, type AuthNavigator, type SubmitFinishOptions, } from './vanilla/auth-flow';
19
+ export { AuthFlowContext, type AuthFlowContextValue } from './context';
20
+ export { AuthFlowProvider, AuthPageWrapper, type AuthPageWrapperProps } from './AuthPageWrapper';
21
+ export { useAddedItems, useAuthFlow, useExtraField, type UseAuthFlowResult, type UseExtraFieldResult } from './hooks';
22
+ export { DEFAULT_AUTH_MOUNT_ID, mountAuthPage, type MountAuthPageOptions } from './hydrate';
23
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,cAAc,YAAY,CAAC;AAG3B,OAAO,EACL,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACzB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACtH,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC"}