@owlmeans/web-oauth 0.1.18-rc.1

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 (109) hide show
  1. package/README.md +15 -0
  2. package/agent-meta/manifest.json +16 -0
  3. package/agent-meta/skills/web-oauth/SKILL.md +131 -0
  4. package/build/@/components/ui/button.d.ts +11 -0
  5. package/build/@/components/ui/button.d.ts.map +1 -0
  6. package/build/@/components/ui/button.js +32 -0
  7. package/build/@/components/ui/button.js.map +1 -0
  8. package/build/@/components/ui/card.d.ts +10 -0
  9. package/build/@/components/ui/card.d.ts.map +1 -0
  10. package/build/@/components/ui/card.js +25 -0
  11. package/build/@/components/ui/card.js.map +1 -0
  12. package/build/@/components/ui/input.d.ts +4 -0
  13. package/build/@/components/ui/input.d.ts.map +1 -0
  14. package/build/@/components/ui/input.js +7 -0
  15. package/build/@/components/ui/input.js.map +1 -0
  16. package/build/@/components/ui/label.d.ts +5 -0
  17. package/build/@/components/ui/label.d.ts.map +1 -0
  18. package/build/@/components/ui/label.js +8 -0
  19. package/build/@/components/ui/label.js.map +1 -0
  20. package/build/@/lib/utils.d.ts +3 -0
  21. package/build/@/lib/utils.d.ts.map +1 -0
  22. package/build/@/lib/utils.js +6 -0
  23. package/build/@/lib/utils.js.map +1 -0
  24. package/build/append.d.ts +14 -0
  25. package/build/append.d.ts.map +1 -0
  26. package/build/append.js +19 -0
  27. package/build/append.js.map +1 -0
  28. package/build/components/consent-screen.d.ts +12 -0
  29. package/build/components/consent-screen.d.ts.map +1 -0
  30. package/build/components/consent-screen.js +30 -0
  31. package/build/components/consent-screen.js.map +1 -0
  32. package/build/components/device-screen.d.ts +10 -0
  33. package/build/components/device-screen.d.ts.map +1 -0
  34. package/build/components/device-screen.js +48 -0
  35. package/build/components/device-screen.js.map +1 -0
  36. package/build/components/done-screen.d.ts +8 -0
  37. package/build/components/done-screen.d.ts.map +1 -0
  38. package/build/components/done-screen.js +18 -0
  39. package/build/components/done-screen.js.map +1 -0
  40. package/build/components/index.d.ts +4 -0
  41. package/build/components/index.d.ts.map +1 -0
  42. package/build/components/index.js +4 -0
  43. package/build/components/index.js.map +1 -0
  44. package/build/consts.d.ts +6 -0
  45. package/build/consts.d.ts.map +1 -0
  46. package/build/consts.js +6 -0
  47. package/build/consts.js.map +1 -0
  48. package/build/entrypoints.d.ts +8 -0
  49. package/build/entrypoints.d.ts.map +1 -0
  50. package/build/entrypoints.js +20 -0
  51. package/build/entrypoints.js.map +1 -0
  52. package/build/hooks/use-oauth-consent.d.ts +27 -0
  53. package/build/hooks/use-oauth-consent.d.ts.map +1 -0
  54. package/build/hooks/use-oauth-consent.js +128 -0
  55. package/build/hooks/use-oauth-consent.js.map +1 -0
  56. package/build/i18n/be.json +35 -0
  57. package/build/i18n/de.json +35 -0
  58. package/build/i18n/en.json +35 -0
  59. package/build/i18n/es.json +35 -0
  60. package/build/i18n/pl.json +35 -0
  61. package/build/i18n/ru.json +35 -0
  62. package/build/i18n/uk.json +35 -0
  63. package/build/i18n.d.ts +2 -0
  64. package/build/i18n.d.ts.map +1 -0
  65. package/build/i18n.js +17 -0
  66. package/build/i18n.js.map +1 -0
  67. package/build/index.d.ts +7 -0
  68. package/build/index.d.ts.map +1 -0
  69. package/build/index.js +7 -0
  70. package/build/index.js.map +1 -0
  71. package/components.json +21 -0
  72. package/package.json +77 -0
  73. package/src/@/components/ui/button.tsx +60 -0
  74. package/src/@/components/ui/card.tsx +93 -0
  75. package/src/@/components/ui/input.tsx +22 -0
  76. package/src/@/components/ui/label.tsx +23 -0
  77. package/src/@/globals.css +57 -0
  78. package/src/@/lib/utils.ts +6 -0
  79. package/src/append.ts +24 -0
  80. package/src/components/consent-screen.tsx +95 -0
  81. package/src/components/device-screen.tsx +81 -0
  82. package/src/components/done-screen.tsx +30 -0
  83. package/src/components/index.ts +3 -0
  84. package/src/consts.ts +6 -0
  85. package/src/entrypoints.ts +22 -0
  86. package/src/hooks/use-oauth-consent.ts +163 -0
  87. package/src/i18n/be.json +35 -0
  88. package/src/i18n/de.json +35 -0
  89. package/src/i18n/en.json +35 -0
  90. package/src/i18n/es.json +35 -0
  91. package/src/i18n/pl.json +35 -0
  92. package/src/i18n/ru.json +35 -0
  93. package/src/i18n/uk.json +35 -0
  94. package/src/i18n.ts +18 -0
  95. package/src/index.ts +6 -0
  96. package/tests/consent.spec.ts +260 -0
  97. package/tests/context.ts +48 -0
  98. package/tests/device.spec.ts +64 -0
  99. package/tests/done.spec.ts +41 -0
  100. package/tests/harness/css.d.ts +1 -0
  101. package/tests/harness/frame.html +15 -0
  102. package/tests/harness/index.html +11 -0
  103. package/tests/harness/mount.tsx +89 -0
  104. package/tests/helpers.ts +97 -0
  105. package/tests/i18n.spec.ts +41 -0
  106. package/tests/languages.spec.ts +38 -0
  107. package/tests/package-boundary.spec.ts +19 -0
  108. package/tests/tsconfig.json +12 -0
  109. package/tsconfig.json +14 -0
package/README.md ADDED
@@ -0,0 +1,15 @@
1
+ <!-- owlmeans:agent-guidance:start -->
2
+ ## Agent guidance
3
+
4
+ This package ships embedded agent skills under `agent-meta/`. After installing your
5
+ `@owlmeans/*` packages, run the OwlMeans agent-skills installer to place them into
6
+ your project's skill store (`.agents/skills/`):
7
+
8
+ ```sh
9
+ npx @owlmeans/agent-skills@^0.1.18-rc.28
10
+ ```
11
+
12
+ The embedded files are version-matched to this package release. Do not edit them
13
+ directly — they are regenerated on each publish. To contribute guidance edits,
14
+ open a PR against the source monorepo.
15
+ <!-- owlmeans:agent-guidance:end -->
@@ -0,0 +1,16 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "package": "@owlmeans/web-oauth",
4
+ "version": "0.1.18-rc.1",
5
+ "generatedAt": "2026-09-18T18:24:55.976Z",
6
+ "canonicalRepo": "https://github.com/owlmeans/common",
7
+ "entries": [
8
+ {
9
+ "kind": "skill",
10
+ "name": "web-oauth",
11
+ "category": "package-specific",
12
+ "file": "skills/web-oauth/SKILL.md",
13
+ "canonicalPath": ".agents/skills/web-oauth/SKILL.md"
14
+ }
15
+ ]
16
+ }
@@ -0,0 +1,131 @@
1
+ ---
2
+ name: web-oauth
3
+ description: How to use @owlmeans/web-oauth — the browser half of OAuth sign-in: the consent, device-code and done screens, oauthEntrypoints, appendOAuthScreens, the useOAuthConsent hook, the suspend-then-dispatcher sign-in leg, the mandatory Tailwind @source line, the i18n resource and the data-testid contract. Auto-invoked when binding the OAuth screens in a web app, changing what the consent screen shows, diagnosing a person who is not returned to consent after signing in, or writing a test against these screens.
4
+ user-invocable: false
5
+ ---
6
+ <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
7
+
8
+ # @owlmeans/web-oauth
9
+
10
+ **Layer:** Web (React, shadcn + Tailwind v4)
11
+ **Install:** `"@owlmeans/web-oauth": "^0.1.18-rc.1"` in `dependencies`
12
+ **Contracts:** `@owlmeans/oauth` — aliases, `makeOAuthProtocols`, `oauthFlow`, `ConsentView`
13
+ **Server half:** `@owlmeans/server-oauth` (its `consentUrl`/`deviceUrl` must point at these screens)
14
+
15
+ ## Key Exports
16
+
17
+ | Export | Description |
18
+ |--------|-------------|
19
+ | `oauthEntrypoints(opts?)` | `[bindScreen(consentScreen), bindScreen(deviceScreen), bindScreen(doneScreen)]` — spread into the app's entrypoint list. `opts` is `OAuthEntrypointOptions` (`parent?`, `path?`, `guard?`) |
20
+ | `appendOAuthScreens(ctx)` | Precondition check only: throws unless a `FLOW_STATE` resource is registered (call `appendFlowService` first). Returns the context |
21
+ | `OAuthConsentScreen` · `OAuthDeviceScreen` · `OAuthDoneScreen` | The screens (`RoutedComponent`s) |
22
+ | `useOAuthConsent(ref, aliases?)` | The headless logic: `{ stage, view, error, errorKind, approve, deny, switchAccount }` with `stage` in `checking | signing-in | loading | ready | deciding | done | error`; `errorKind` in `missing | not-found | expired | forbidden | failed` (`error` is the raw wire text, for a log — never rendered) |
23
+ | `OAUTH_I18N` (`'oauth'`) · `OAUTH_SUSPEND_TTL_MS` (10 min) | The library-tier i18n resource; how long a suspended sign-in stays valid |
24
+
25
+ The **consent API** (`load`/`approve`/`deny`) is bound by the *server* app, not here — the app binds
26
+ `loadConsent`/`approveConsent`/`denyConsent` from `@owlmeans/server-oauth` in its API context and
27
+ registers the same protocols in the web context's `bindAll` so `context.entrypoint(protocols.load)`
28
+ resolves. The three screens are `sticky`, parentless frontend routes (`/oauth/consent`,
29
+ `/oauth/device`, `/oauth/done`).
30
+
31
+ ## Wiring
32
+
33
+ ```tsx
34
+ import { appendOAuthScreens, oauthEntrypoints } from '@owlmeans/web-oauth'
35
+
36
+ appendFlowService(context) // registers FLOW_STATE
37
+ appendOAuthScreens(context)
38
+ // entrypoints: ...oauthEntrypoints({ parent: account.base }) — the SAME opts the server passed
39
+ ```
40
+
41
+ An app that builds its entrypoints from shared `managerProtocols` binds the three screens with
42
+ `bindScreen(protocols.consentScreen, handler(OAuthConsentScreen))` etc. — the components are
43
+ exported for exactly that. Translations register as a side effect of importing the package.
44
+
45
+ ## The `@source` line — a consumer rule
46
+
47
+ Tailwind's scanner reads the CSS root plus `@source` directives and excludes `node_modules`, so a
48
+ class used only inside this package never reaches the app's stylesheet and the screens render
49
+ unstyled with nothing in the app's own sources to blame. Every consuming app adds:
50
+
51
+ ```css
52
+ @source "../../../node_modules/@owlmeans/web-oauth/src";
53
+ ```
54
+
55
+ Point at the shipped `src`, not `build`. Primitives (`button`, `card`, `input`, `label`) are private
56
+ under `src/@/` and imported only by relative specifiers — the consuming app's `@` alias is never part
57
+ of this package's runtime, and `tests/package-boundary.spec.ts` fails on any `from '@/…'`.
58
+
59
+ ## The screens
60
+
61
+ - **Consent** — reads `?ref=` (a code grant's request id, or a device grant's user code; the server
62
+ resolves which). Nothing is shown until the app is known to be authenticated; signed in, it calls
63
+ `load`, shows the client's name and how it is known, the device name and `XXXX-XXXX` code, the
64
+ redirect host (code grant), a localhost warning, and the scopes; **Approve** / **Deny**. Approve
65
+ on a code grant does `window.location.href = redirect`; on a device grant it transits the flow to
66
+ **Done** with `kind`/`ref` in the query. **It refuses to render when framed**
67
+ (`window.top !== window.self`) — the approval click is exactly what a clickjacking overlay steals.
68
+ **Use another account** (`oauth-consent-switch`) signs the session out (`auth.update(undefined)`) and
69
+ goes through the same suspension, returning to this `ref`. Every failure is ONE translated sentence
70
+ in `oauth-consent-error`, chosen by `errorKind` (`error-missing`, `error-not-found`, `error-expired`,
71
+ `error-forbidden`, else the generic `error`) — the wire marker and stack are never shown. The kind is
72
+ read from the marker in the message (`request-expired`, `request-not-found`, `forbidden`).
73
+ - **Device** — RFC 8628's `verification_uri`. Opened bare it shows an input for the code; opened
74
+ with `?user_code=…` (`verification_uri_complete`) it goes straight on. Either way it runs the same
75
+ `verify` → `next` → `consent` transition, so the two entries converge before anything else runs.
76
+ - **Done** — "you may close this window". The device variant says the connector will catch up on
77
+ its own (`?kind=device`). Nothing to click; the MCP/CLI is polling.
78
+
79
+ ## Signed out: suspend, dispatcher, come back
80
+
81
+ The consent screen never assumes a session. When `auth.authenticated()` is empty it builds
82
+ `makeFlowModel(oauthFlow)` (never the live flow slot), sets `ref`, transits the explicit `sign-in`
83
+ step, calls `suspendFlow(context, model, { expiresAt: now + OAUTH_SUSPEND_TTL_MS })` and sends the
84
+ browser to `DISPATCHER`. The chooser / Google / supervisor sign-in then lands through
85
+ `resumeSuspendedFlow` (the landing rule in `/login-plugins`, `/client-flow`) — back on the consent
86
+ screen with the **same `ref`**, now authenticated. What is stored is the destination entrypoint alias
87
+ plus the payload query, delete-on-read and expiry-checked, in `FLOW_STATE` (IndexedDB, so it survives
88
+ Google's full-page round trip). A plugin that still navigates to `HOME` instead of the landing breaks
89
+ this leg silently.
90
+
91
+ ## `data-testid` contract
92
+
93
+ `oauth-consent-card`, `oauth-consent-client`, `oauth-consent-code`, `oauth-consent-approve`,
94
+ `oauth-consent-deny`, `oauth-consent-switch`, `oauth-consent-error`, `oauth-device-card`, `oauth-device-input`,
95
+ `oauth-device-submit`, `oauth-done-card`. Do not rename them — the end-to-end suites that drive
96
+ sign-in address these.
97
+
98
+ ## i18n
99
+
100
+ Library-tier resource `oauth`, all seven languages (`en pl ru be uk es de`) under `src/i18n/`;
101
+ sections `consent`, `device`, `done`. `tests/i18n.spec.ts` fails when a language lacks a key English
102
+ has — add a key to all seven. An app overrides a string at its own tier; it does not fork a screen.
103
+
104
+ ## Testing
105
+
106
+ Category D (`/testing-ui`) — `bun test ./tests` drives a real chromium against a real app, with only
107
+ the server absent:
108
+
109
+ - **Harness** (`tests/context.ts` boots Vite; `tests/harness/mount.tsx` is the app). It is the real
110
+ `@owlmeans/web-client` context (auth service, IndexedDB resources, History-API router, the real
111
+ dispatcher), the real flow service, `oauthEntrypoints()`, and the consent API bound with `bindAll`
112
+ under a backend parent declared on the harness's own origin. The context stays un-initialized so the
113
+ router compiles its routes.
114
+ - **Server stubs** are `page.route` answers on that origin (`tests/helpers.ts` `open(path, { stubs })`):
115
+ `load`/`approve`/`deny` return a `ConsentView`, a `{ redirect }`, or a refusal in the wire shape
116
+ `type|||message|||stack`. Nothing needs CORS and no live server is reached. `authenticate: true`
117
+ also answers the dispatcher's token exchange.
118
+ - **A signed-in visit** is `?bearer=<makeBearer(USER)>`: the harness writes the record the auth
119
+ service reads back (`idb-keyval` `auth:user`) BEFORE the app renders — services are not initialized
120
+ yet, so `context.auth().update()` is not available at that point. `?lng=` picks the language.
121
+ `window.__oauth.suspended()` / `.token()` read the real flow store and auth service back.
122
+ - **What is covered:** signed-out suspension (record, expiry, dispatcher, no request made); the full
123
+ sign-in round trip back to the same `ref`; device and code grants (client, code, device, redirect
124
+ host, the localhost warning, approve/deny each way, `location` follows the redirect); every failure as
125
+ one sentence; the framed refusal (an iframe of `tests/harness/frame.html`, the framed app carrying its
126
+ own `bearer`); use-another-account; the device screen bare and linked; the done screen; and the
127
+ consent screen in all seven languages.
128
+ - Also `package-boundary.spec.ts` (no consumer aliases in source) and `i18n.spec.ts` (7-language parity).
129
+
130
+ A test of a refusal that the screen would otherwise hide still asserts what is ABSENT (no approve or
131
+ deny button, no wire text) — the point of those cases is that nothing can be approved.
@@ -0,0 +1,11 @@
1
+ import * as React from 'react';
2
+ import { type VariantProps } from 'class-variance-authority';
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
5
+ size?: "default" | "icon" | "lg" | "sm" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
8
+ asChild?: boolean;
9
+ }): React.JSX.Element;
10
+ export { Button, buttonVariants };
11
+ //# sourceMappingURL=button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.d.ts","sourceRoot":"","sources":["../../../../src/@/components/ui/button.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAIjE,QAAA,MAAM,cAAc;;;8EA6BnB,CAAA;AAED,iBAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAe,EACf,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,GAC/B,YAAY,CAAC,OAAO,cAAc,CAAC,GAAG;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB,qBAUF;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva } from 'class-variance-authority';
4
+ import { cn } from '../../lib/utils.js';
5
+ const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive cursor-pointer", {
6
+ variants: {
7
+ variant: {
8
+ default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
9
+ destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
10
+ outline: "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
11
+ secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
12
+ ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
13
+ link: "text-primary underline-offset-4 hover:underline",
14
+ },
15
+ size: {
16
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
17
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
18
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
19
+ icon: "size-9",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ size: "default",
25
+ },
26
+ });
27
+ function Button({ className, variant, size, asChild = false, ...props }) {
28
+ const Comp = asChild ? Slot : "button";
29
+ return (_jsx(Comp, { "data-slot": "button", className: cn(buttonVariants({ variant, size, className })), ...props }));
30
+ }
31
+ export { Button, buttonVariants };
32
+ //# sourceMappingURL=button.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"button.js","sourceRoot":"","sources":["../../../../src/@/components/ui/button.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAA;AAC3C,OAAO,EAAE,GAAG,EAAqB,MAAM,0BAA0B,CAAA;AAEjE,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC,MAAM,cAAc,GAAG,GAAG,CACxB,4cAA4c,EAC5c;IACE,QAAQ,EAAE;QACR,OAAO,EAAE;YACP,OAAO,EACL,kEAAkE;YACpE,WAAW,EACT,6JAA6J;YAC/J,OAAO,EACL,uIAAuI;YACzI,SAAS,EACP,wEAAwE;YAC1E,KAAK,EACH,sEAAsE;YACxE,IAAI,EAAE,iDAAiD;SACxD;QACD,IAAI,EAAE;YACJ,OAAO,EAAE,+BAA+B;YACxC,EAAE,EAAE,+CAA+C;YACnD,EAAE,EAAE,sCAAsC;YAC1C,IAAI,EAAE,QAAQ;SACf;KACF;IACD,eAAe,EAAE;QACf,OAAO,EAAE,SAAS;QAClB,IAAI,EAAE,SAAS;KAChB;CACF,CACF,CAAA;AAED,SAAS,MAAM,CAAC,EACd,SAAS,EACT,OAAO,EACP,IAAI,EACJ,OAAO,GAAG,KAAK,EACf,GAAG,KAAK,EAIP;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAA;IAEtC,OAAO,CACL,KAAC,IAAI,iBACO,QAAQ,EAClB,SAAS,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,KACvD,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA"}
@@ -0,0 +1,10 @@
1
+ import * as React from 'react';
2
+ declare function Card({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
3
+ declare function CardHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
4
+ declare function CardTitle({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
5
+ declare function CardDescription({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
6
+ declare function CardAction({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
7
+ declare function CardContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
8
+ declare function CardFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
9
+ export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent, };
10
+ //# sourceMappingURL=card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../../../../src/@/components/ui/card.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWjE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQtE;AAED,iBAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQ5E;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWvE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQvE;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,GACZ,CAAA"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../../lib/utils.js';
3
+ function Card({ className, ...props }) {
4
+ return (_jsx("div", { "data-slot": "card", className: cn("bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm", className), ...props }));
5
+ }
6
+ function CardHeader({ className, ...props }) {
7
+ return (_jsx("div", { "data-slot": "card-header", className: cn("@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6", className), ...props }));
8
+ }
9
+ function CardTitle({ className, ...props }) {
10
+ return (_jsx("div", { "data-slot": "card-title", className: cn("leading-none font-semibold", className), ...props }));
11
+ }
12
+ function CardDescription({ className, ...props }) {
13
+ return (_jsx("div", { "data-slot": "card-description", className: cn("text-muted-foreground text-sm", className), ...props }));
14
+ }
15
+ function CardAction({ className, ...props }) {
16
+ return (_jsx("div", { "data-slot": "card-action", className: cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className), ...props }));
17
+ }
18
+ function CardContent({ className, ...props }) {
19
+ return (_jsx("div", { "data-slot": "card-content", className: cn("px-6", className), ...props }));
20
+ }
21
+ function CardFooter({ className, ...props }) {
22
+ return (_jsx("div", { "data-slot": "card-footer", className: cn("flex items-center px-6 [.border-t]:pt-6", className), ...props }));
23
+ }
24
+ export { Card, CardHeader, CardFooter, CardTitle, CardAction, CardDescription, CardContent, };
25
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"card.js","sourceRoot":"","sources":["../../../../src/@/components/ui/card.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC,SAAS,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAChE,OAAO,CACL,2BACY,MAAM,EAChB,SAAS,EAAE,EAAE,CACX,mFAAmF,EACnF,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CACX,4JAA4J,EAC5J,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,SAAS,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACrE,OAAO,CACL,2BACY,YAAY,EACtB,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,KAClD,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,eAAe,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IAC3E,OAAO,CACL,2BACY,kBAAkB,EAC5B,SAAS,EAAE,EAAE,CAAC,+BAA+B,EAAE,SAAS,CAAC,KACrD,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CACX,gEAAgE,EAChE,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACvE,OAAO,CACL,2BACY,cAAc,EACxB,SAAS,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC,KAC5B,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAA+B;IACtE,OAAO,CACL,2BACY,aAAa,EACvB,SAAS,EAAE,EAAE,CAAC,yCAAyC,EAAE,SAAS,CAAC,KAC/D,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,OAAO,EACL,IAAI,EACJ,UAAU,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,eAAe,EACf,WAAW,GACZ,CAAA"}
@@ -0,0 +1,4 @@
1
+ import * as React from 'react';
2
+ declare function Input({ className, type, ...props }: React.ComponentProps<"input">): React.JSX.Element;
3
+ export { Input };
4
+ //# sourceMappingURL=input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../../../src/@/components/ui/input.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iBAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,qBAc1E;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../../lib/utils.js';
3
+ function Input({ className, type, ...props }) {
4
+ return (_jsx("input", { type: type, "data-slot": "input", className: cn("file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", className), ...props }));
5
+ }
6
+ export { Input };
7
+ //# sourceMappingURL=input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input.js","sourceRoot":"","sources":["../../../../src/@/components/ui/input.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,KAAK,EAAiC;IACzE,OAAO,CACL,gBACE,IAAI,EAAE,IAAI,eACA,OAAO,EACjB,SAAS,EAAE,EAAE,CACX,icAAic,EACjc,+EAA+E,EAC/E,wGAAwG,EACxG,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -0,0 +1,5 @@
1
+ import * as React from 'react';
2
+ import * as LabelPrimitive from '@radix-ui/react-label';
3
+ declare function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>): React.JSX.Element;
4
+ export { Label };
5
+ //# sourceMappingURL=label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../../src/@/components/ui/label.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AAIvD,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,qBAWlD;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as LabelPrimitive from '@radix-ui/react-label';
3
+ import { cn } from '../../lib/utils.js';
4
+ function Label({ className, ...props }) {
5
+ return (_jsx(LabelPrimitive.Root, { "data-slot": "label", className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className), ...props }));
6
+ }
7
+ export { Label };
8
+ //# sourceMappingURL=label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.js","sourceRoot":"","sources":["../../../../src/@/components/ui/label.tsx"],"names":[],"mappings":";AAEA,OAAO,KAAK,cAAc,MAAM,uBAAuB,CAAA;AAEvD,OAAO,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAA;AAEvC,SAAS,KAAK,CAAC,EACb,SAAS,EACT,GAAG,KAAK,EACyC;IACjD,OAAO,CACL,KAAC,cAAc,CAAC,IAAI,iBACR,OAAO,EACjB,SAAS,EAAE,EAAE,CACX,qNAAqN,EACrN,SAAS,CACV,KACG,KAAK,GACT,CACH,CAAA;AACH,CAAC;AAED,OAAO,EAAE,KAAK,EAAE,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { type ClassValue } from 'clsx';
2
+ export declare function cn(...inputs: ClassValue[]): string;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/@/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAA;AAG5C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
@@ -0,0 +1,6 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
6
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/@/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAA;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAExC,MAAM,UAAU,EAAE,CAAC,GAAG,MAAoB;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { ClientContext } from '@owlmeans/client-context';
2
+ import type { ClientConfig } from '@owlmeans/client-context';
3
+ /**
4
+ * Fail fast when the one precondition these screens actually depend on is missing, rather than
5
+ * deep inside `suspendFlow` the first time somebody who is not signed in opens a consent screen.
6
+ *
7
+ * There is nothing else to register here: the three screens are bound through `oauthEntrypoints`
8
+ * (spread into the application's own entrypoint list, exactly like every other screen package in
9
+ * this framework), and the translations register themselves as a side effect of importing this
10
+ * package's barrel — `appendOAuthScreens` is the documented call an application makes, but the
11
+ * strings are already there whether it is called or not.
12
+ */
13
+ export declare const appendOAuthScreens: <C extends ClientConfig, T extends ClientContext<C>>(context: T) => T;
14
+ //# sourceMappingURL=append.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"append.d.ts","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,KAAG,CASnG,CAAA"}
@@ -0,0 +1,19 @@
1
+ import { FLOW_STATE } from '@owlmeans/client-flow';
2
+ /**
3
+ * Fail fast when the one precondition these screens actually depend on is missing, rather than
4
+ * deep inside `suspendFlow` the first time somebody who is not signed in opens a consent screen.
5
+ *
6
+ * There is nothing else to register here: the three screens are bound through `oauthEntrypoints`
7
+ * (spread into the application's own entrypoint list, exactly like every other screen package in
8
+ * this framework), and the translations register themselves as a side effect of importing this
9
+ * package's barrel — `appendOAuthScreens` is the documented call an application makes, but the
10
+ * strings are already there whether it is called or not.
11
+ */
12
+ export const appendOAuthScreens = (context) => {
13
+ if (!context.hasResource(FLOW_STATE)) {
14
+ throw new SyntaxError('web-oauth: no FLOW_STATE resource registered. Call appendFlowService (@owlmeans/web-flow) — '
15
+ + 'or whatever registers it in this app\'s makeContext — before appendOAuthScreens.');
16
+ }
17
+ return context;
18
+ };
19
+ //# sourceMappingURL=append.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"append.js","sourceRoot":"","sources":["../src/append.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAIlD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAqD,OAAU,EAAK,EAAE;IACtG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,WAAW,CACnB,8FAA8F;cAC5F,kFAAkF,CACrF,CAAA;IACH,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA"}
@@ -0,0 +1,12 @@
1
+ import type { RoutedComponent } from '@owlmeans/client';
2
+ /**
3
+ * The device/authorization-code consent screen. Full-page, no application chrome — the same
4
+ * shape `/dispatcher` and `/iam/interact/:uid` already render in, because a sign-in round trip is
5
+ * never a panel inside the application's own navigation.
6
+ *
7
+ * The screen refuses to render when framed: a device or code approval is exactly the click a
8
+ * clickjacking overlay would want to steal, and nothing about this decision needs to happen
9
+ * inside a frame.
10
+ */
11
+ export declare const OAuthConsentScreen: RoutedComponent;
12
+ //# sourceMappingURL=consent-screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-screen.d.ts","sourceRoot":"","sources":["../../src/components/consent-screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAOvD;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,EAAE,eA6EhC,CAAA"}
@@ -0,0 +1,30 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useContext } from '@owlmeans/client';
3
+ import { useI18nLib } from '@owlmeans/client-i18n';
4
+ import { OAUTH_I18N } from '../consts.js';
5
+ import { useOAuthConsent } from '../hooks/use-oauth-consent.js';
6
+ import { Button } from '../@/components/ui/button.js';
7
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../@/components/ui/card.js';
8
+ /**
9
+ * The device/authorization-code consent screen. Full-page, no application chrome — the same
10
+ * shape `/dispatcher` and `/iam/interact/:uid` already render in, because a sign-in round trip is
11
+ * never a panel inside the application's own navigation.
12
+ *
13
+ * The screen refuses to render when framed: a device or code approval is exactly the click a
14
+ * clickjacking overlay would want to steal, and nothing about this decision needs to happen
15
+ * inside a frame.
16
+ */
17
+ export const OAuthConsentScreen = () => {
18
+ const context = useContext();
19
+ const [query] = context.router().useSearchParams();
20
+ const ref = query.get('ref');
21
+ const t = useI18nLib(OAUTH_I18N, 'consent');
22
+ const { stage, view, errorKind, approve, deny, switchAccount } = useOAuthConsent(ref);
23
+ const framed = typeof window !== 'undefined' && window.top !== window.self;
24
+ return (_jsx("div", { style: { minHeight: '100dvh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16 }, children: _jsx(Card, { style: { width: '100%', maxWidth: 440 }, "data-testid": "oauth-consent-card", children: framed ? (_jsx(CardContent, { children: _jsx("p", { role: "alert", children: t('framed') }) })) : stage === 'checking' || stage === 'signing-in' ? (_jsx(CardContent, { children: _jsx("p", { children: t('checking') }) })) : stage === 'loading' ? (_jsx(CardContent, { children: _jsx("p", { children: t('loading') }) })) : stage === 'error' ? (_jsx(CardContent, { children: _jsx("p", { role: "alert", "data-testid": "oauth-consent-error", children: t(errorKind == null || errorKind === 'failed' ? 'error' : `error-${errorKind}`) }) })) : view != null ? (_jsxs(_Fragment, { children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { "data-testid": "oauth-consent-client", children: t('title', { client: view.client.name }) }), _jsx(CardDescription, { children: view.client.origin === 'cimd' && view.client.host != null
25
+ ? t('known-by-host', { host: view.client.host })
26
+ : view.client.origin === 'dcr'
27
+ ? t('unverified')
28
+ : t('known') })] }), _jsxs(CardContent, { style: { display: 'flex', flexDirection: 'column', gap: 12 }, children: [view.userCode != null && (_jsx("p", { "data-testid": "oauth-consent-code", children: t('device-code', { code: view.userCode }) })), view.deviceName != null && _jsx("p", { children: t('device-name', { name: view.deviceName }) }), view.redirectHost != null && _jsx("p", { children: t('redirect-host', { host: view.redirectHost }) }), view.localhostOnly === true && (_jsx("p", { role: "alert", children: t('localhost-warning') })), _jsx("p", { children: t('scope', { scopes: view.scopes.join(', ') }) }), _jsxs("div", { style: { display: 'flex', gap: 8, justifyContent: 'flex-end' }, children: [_jsx(Button, { type: "button", variant: "outline", disabled: stage === 'deciding', "data-testid": "oauth-consent-deny", onClick: () => void deny(), children: t('deny') }), _jsx(Button, { type: "button", disabled: stage === 'deciding', "data-testid": "oauth-consent-approve", onClick: () => void approve(), autoFocus: true, children: t('approve') })] }), _jsx(Button, { type: "button", variant: "link", size: "sm", disabled: stage === 'deciding', "data-testid": "oauth-consent-switch", onClick: () => void switchAccount(), children: t('switch-account') })] })] })) : null }) }));
29
+ };
30
+ //# sourceMappingURL=consent-screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-screen.js","sourceRoot":"","sources":["../../src/components/consent-screen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { RoutedComponent } from '@owlmeans/client';
2
+ /**
3
+ * The device-verification screen (RFC 8628's `verification_uri`). Opened by the MCP, either bare
4
+ * (a person types the code they were shown) or complete (`?user_code=…`, already carrying it).
5
+ *
6
+ * Either way it goes through the SAME flow transition — `verify` → `next` → `consent` — so the
7
+ * two entry shapes converge onto one path before anything else runs.
8
+ */
9
+ export declare const OAuthDeviceScreen: RoutedComponent;
10
+ //# sourceMappingURL=device-screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-screen.d.ts","sourceRoot":"","sources":["../../src/components/device-screen.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAWvD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,eA2D/B,CAAA"}
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useState } from 'react';
3
+ import { useContext, useNavigate } from '@owlmeans/client';
4
+ import { useI18nLib } from '@owlmeans/client-i18n';
5
+ import { makeFlowModel } from '@owlmeans/flow';
6
+ import { normalizeUserCode, oauthFlow, OAuthFlowStep, OAUTH_PAYLOAD_REF } from '@owlmeans/oauth';
7
+ import { OAUTH_I18N } from '../consts.js';
8
+ import { Button } from '../@/components/ui/button.js';
9
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../@/components/ui/card.js';
10
+ import { Input } from '../@/components/ui/input.js';
11
+ import { Label } from '../@/components/ui/label.js';
12
+ /**
13
+ * The device-verification screen (RFC 8628's `verification_uri`). Opened by the MCP, either bare
14
+ * (a person types the code they were shown) or complete (`?user_code=…`, already carrying it).
15
+ *
16
+ * Either way it goes through the SAME flow transition — `verify` → `next` → `consent` — so the
17
+ * two entry shapes converge onto one path before anything else runs.
18
+ */
19
+ export const OAuthDeviceScreen = () => {
20
+ const context = useContext();
21
+ const nav = useNavigate();
22
+ const [query] = context.router().useSearchParams();
23
+ const t = useI18nLib(OAUTH_I18N, 'device');
24
+ const [code, setCode] = useState(query.get('user_code') ?? '');
25
+ const proceed = useCallback(async (typed) => {
26
+ const model = await makeFlowModel(oauthFlow);
27
+ model.enter(OAuthFlowStep.Verify);
28
+ model.updatePayload({ [OAUTH_PAYLOAD_REF]: normalizeUserCode(typed) });
29
+ model.transit('next', true);
30
+ const destination = model.step();
31
+ await nav.navigate(context.entrypoint(destination.module), { query: model.payload() });
32
+ }, [nav]);
33
+ const initial = query.get('user_code');
34
+ const complete = initial != null && initial !== '';
35
+ useEffect(() => {
36
+ if (complete)
37
+ void proceed(initial);
38
+ }, [complete, initial]);
39
+ const onSubmit = (event) => {
40
+ event.preventDefault();
41
+ void proceed(code);
42
+ };
43
+ if (complete) {
44
+ return null;
45
+ }
46
+ return (_jsx("div", { style: { minHeight: '100dvh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16 }, children: _jsxs(Card, { style: { width: '100%', maxWidth: 380 }, "data-testid": "oauth-device-card", children: [_jsxs(CardHeader, { children: [_jsx(CardTitle, { children: t('title') }), _jsx(CardDescription, { children: t('description') })] }), _jsx(CardContent, { children: _jsxs("form", { onSubmit: onSubmit, style: { display: 'flex', flexDirection: 'column', gap: 12 }, children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: [_jsx(Label, { htmlFor: "oauth-device-code", children: t('code-label') }), _jsx(Input, { id: "oauth-device-code", "data-testid": "oauth-device-input", autoComplete: "off", placeholder: "XXXX-XXXX", value: code, onChange: event => setCode(event.target.value) })] }), _jsx(Button, { type: "submit", "data-testid": "oauth-device-submit", disabled: code.trim() === '', children: t('continue') })] }) })] }) }));
47
+ };
48
+ //# sourceMappingURL=device-screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-screen.js","sourceRoot":"","sources":["../../src/components/device-screen.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { RoutedComponent } from '@owlmeans/client';
2
+ /**
3
+ * The final screen of the device grant — the moment the person's part is finished and the MCP's
4
+ * poll is expected to catch up within the device-authorization's own poll interval. There is
5
+ * nothing here to click and nowhere further to go; the tab's only remaining job is to be closed.
6
+ */
7
+ export declare const OAuthDoneScreen: RoutedComponent;
8
+ //# sourceMappingURL=done-screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"done-screen.d.ts","sourceRoot":"","sources":["../../src/components/done-screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAKvD;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,eAkB7B,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useContext } from '@owlmeans/client';
3
+ import { useI18nLib } from '@owlmeans/client-i18n';
4
+ import { OAUTH_I18N } from '../consts.js';
5
+ import { Card, CardContent, CardHeader, CardTitle } from '../@/components/ui/card.js';
6
+ /**
7
+ * The final screen of the device grant — the moment the person's part is finished and the MCP's
8
+ * poll is expected to catch up within the device-authorization's own poll interval. There is
9
+ * nothing here to click and nowhere further to go; the tab's only remaining job is to be closed.
10
+ */
11
+ export const OAuthDoneScreen = () => {
12
+ const context = useContext();
13
+ const [query] = context.router().useSearchParams();
14
+ const t = useI18nLib(OAUTH_I18N, 'done');
15
+ const kind = query.get('kind');
16
+ return (_jsx("div", { style: { minHeight: '100dvh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 16 }, children: _jsxs(Card, { style: { width: '100%', maxWidth: 380, textAlign: 'center' }, "data-testid": "oauth-done-card", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: t('title') }) }), _jsx(CardContent, { children: _jsx("p", { children: kind === 'device' ? t('device-message') : t('message') }) })] }) }));
17
+ };
18
+ //# sourceMappingURL=done-screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"done-screen.js","sourceRoot":"","sources":["../../src/components/done-screen.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAErF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAoB,GAAG,EAAE;IACnD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,eAAe,EAAE,CAAA;IAClD,MAAM,CAAC,GAAG,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IACxC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IAE9B,OAAO,CACL,cAAK,KAAK,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,YAC/G,MAAC,IAAI,IAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAc,iBAAiB,aAC/F,KAAC,UAAU,cACT,KAAC,SAAS,cAAE,CAAC,CAAC,OAAO,CAAC,GAAa,GACxB,EACb,KAAC,WAAW,cACV,sBAAI,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAK,GACnD,IACT,GACH,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ export * from './consent-screen.js';
2
+ export * from './device-screen.js';
3
+ export * from './done-screen.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA"}
@@ -0,0 +1,4 @@
1
+ export * from './consent-screen.js';
2
+ export * from './device-screen.js';
3
+ export * from './done-screen.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAA;AACnC,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA"}
@@ -0,0 +1,6 @@
1
+ /** The lib-tier i18n resource this package registers its strings under. */
2
+ export declare const OAUTH_I18N = "oauth";
3
+ /** How long a consent screen's suspended sign-in stays valid — generous enough for a person to
4
+ * pick a provider and come back, short enough that a stale suspension is not a lingering hazard. */
5
+ export declare const OAUTH_SUSPEND_TTL_MS: number;
6
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,eAAO,MAAM,UAAU,UAAU,CAAA;AAEjC;oGACoG;AACpG,eAAO,MAAM,oBAAoB,QAAiB,CAAA"}
@@ -0,0 +1,6 @@
1
+ /** The lib-tier i18n resource this package registers its strings under. */
2
+ export const OAUTH_I18N = 'oauth';
3
+ /** How long a consent screen's suspended sign-in stays valid — generous enough for a person to
4
+ * pick a provider and come back, short enough that a stale suspension is not a lingering hazard. */
5
+ export const OAUTH_SUSPEND_TTL_MS = 10 * 60 * 1000;
6
+ //# sourceMappingURL=consts.js.map