@owlmeans/web-client 0.1.18-rc.26 → 0.1.18-rc.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,11 +6,11 @@ React web application bootstrap — context factory, entrypoint/routing utilitie
6
6
 
7
7
  - `makeContext(cfg)` — creates the web application context (includes auth, router, and DB services)
8
8
  - `renderApp(context)` — mounts the React app to the DOM
9
- - Re-exports entrypoint/routing helpers: `entrypoint`, `route`, `frontend`, `handler`, `elevate`
9
+ - Re-exports entrypoint/routing helpers: `bind`, `bindAll`, `bindScreen`, `route`, `frontend`, `handler`
10
10
  - Re-exports route constants: `BASE`, `HOME`, `ROOT`, `GUEST`
11
11
  - `entrypoints` — the base client entrypoints (dispatcher, login surrogate) every web app spreads
12
- - `ClientEntrypoint<T>` (also exported as `Module<T>`) — the typed entrypoint interface behind
13
- `call()` / `invoke()` / `url()`
12
+ - `ClientProtocolEntrypoint<Protocol>` — the context-bound entrypoint interface inferred from a
13
+ shared protocol declaration; it exposes `call()` / `invoke()` / `url()`
14
14
 
15
15
  ## Installation
16
16
 
@@ -34,20 +34,20 @@ renderApp<Config, Context>(context)
34
34
  Define entrypoints:
35
35
 
36
36
  ```typescript
37
- import { BASE, HOME, elevate, entrypoint, frontend, handler, route } from '@owlmeans/web-client'
37
+ import { bindScreen, bindAll } from '@owlmeans/client-entrypoint'
38
+ import { handler } from '@owlmeans/client'
39
+ import { appEntrypoints as protocols } from 'my-app-common'
38
40
 
39
- appEntrypoints.push(entrypoint(route(BASE, '/', frontend()), handler(PublicLayout)))
40
- appEntrypoints.push(entrypoint(route(HOME, '/', frontend({ default: true, parent: BASE })), handler(HomeScreen)))
41
- elevate(appEntrypoints, manager.back.account.base)
41
+ appEntrypoints.push(bindScreen(protocols.web.base, handler(PublicLayout)))
42
+ appEntrypoints.push(bindScreen(protocols.web.home, handler(HomeScreen)))
43
+ appEntrypoints.push(...bindAll(protocols.api))
42
44
  ```
43
45
 
44
46
  A screen entrypoint carries a renderer, so it is addressed by `url()` and never called over the
45
47
  wire. Call an API entrypoint from a component:
46
48
 
47
49
  ```typescript
48
- import type { ClientEntrypoint } from '@owlmeans/web-client'
49
-
50
- const result = await context.entrypoint<ClientEntrypoint<MyType>>(alias)
50
+ const result = await context.entrypoint(appEntrypoints.api.project)
51
51
  .call({ params: { id }, body: data })
52
52
  ```
53
53
 
@@ -78,7 +78,7 @@ Component that handles authentication routing (redirect to login, etc.).
78
78
  - [`@owlmeans/client-context`](../client-context) — `ClientContext` base extended by `makeContext`
79
79
  - [`@owlmeans/web-router`](../web-router) — default OwlMeans browser routing plugin registered by `makeContext`
80
80
  - [`@owlmeans/web-db`](../web-db) — IndexedDB service registered by `makeContext`
81
- - [`@owlmeans/client-entrypoint`](../client-entrypoint) — the `ClientEntrypoint<T>` implementation
81
+ - [`@owlmeans/client-entrypoint`](../client-entrypoint) — protocol binding helpers
82
82
 
83
83
  <!-- owlmeans:agent-guidance:start -->
84
84
  ## Agent guidance
@@ -88,7 +88,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
88
88
  your project's skill store (`.agents/skills/`):
89
89
 
90
90
  ```sh
91
- npx @owlmeans/agent-skills@^0.1.18-rc.14
91
+ npx @owlmeans/agent-skills@^0.1.18-rc.15
92
92
  ```
93
93
 
94
94
  The embedded files are version-matched to this package release. Do not edit them
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/web-client",
4
- "version": "0.1.18-rc.26",
5
- "generatedAt": "2026-09-10T23:12:07.511Z",
4
+ "version": "0.1.18-rc.27",
5
+ "generatedAt": "2026-09-12T08:39:52.726Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -1,189 +1,39 @@
1
1
  ---
2
2
  name: web-client
3
- description: How to use @owlmeans/web-client — the browser entry point — makeContext(), renderApp(), elevate() to attach React components to entrypoint declarations, context.registerEntrypoints(), context.serviceRoute(), the dispatcher and surrogate login screens, and useAuthenticated(). Auto-invoked when working with a web app entry point, attaching React components to entrypoints, or wiring browser login.
4
- user-invocable: false
3
+ description: Bind OwlMeans shared entrypoint protocols in a browser application. Use when registering client routes, attaching React screens, calling API protocols, or configuring the browser context.
5
4
  ---
6
5
  <!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
7
6
 
8
- # @owlmeans/web-client
7
+ # Browser protocol entrypoints
9
8
 
10
- **Layer:** Web (React)
11
- **Install:** `"@owlmeans/web-client": "^0.1.18-rc.26"` in `dependencies`
12
-
13
- The browser layer over `@owlmeans/client`. It builds the context, mounts the app, and brings
14
- working authentication with nothing registered by hand.
15
-
16
- **What is here and what is not.** `@owlmeans/client` owns the React primitives and does not
17
- re-export from here; this package owns the browser wiring and re-exports only the few authoring
18
- helpers below. In particular `useNavigate`, `useEntrypoint`, `useStoreModel`, `useStoreList`,
19
- `useValue` and `useToggle` are imported from `@owlmeans/client` even in a browser-only app.
20
-
21
- ## Key Exports
22
-
23
- | Export | Description |
24
- |--------|-------------|
25
- | `makeContext(cfg)` | Build the browser context: the client context plus the primary host, the auth service, web db, the auth client resource, the router and login |
26
- | `AppConfig` / `AppContext` | The config and context types — `ClientContext` plus `auth()` and `login()` |
27
- | `renderApp(context, opts?, children?)` | Mount the app. `children` render inside the provider and before the router — the global overlay slot |
28
- | `render(node, opts?)` / `RenderOptions` | The bare mount: `{ domId, onReady, hydrate, debug }`, default root id `root` |
29
- | `WebApp` | The mounted tree — the i18n provider around `App` from `@owlmeans/client` |
30
- | `useContext()` | The context, typed as `AppContext` |
31
- | `useAuthenticated()` | Whether this browsing context holds a session — it reports, it does not guard |
32
- | `entrypoints` | The auth entrypoint list, with the dispatcher and the login-surrogate screens already elevated. Spread it into the app's own list |
33
- | `Dispatcher` / `parametriseDispatcher(defaults, Com?)` | The post-login landing screen, and a wrapper that pre-fills its props |
34
- | `Uploader` / `ImageUploader` / `UploaderProps` / `UploaderRootProps` | Dropzone-based file input; props are `react-dropzone`'s `DropzoneOptions` plus `Root`/`rootProps`. The image variant only DEFAULTS `maxSize` to 5 MB — pass `maxSize` to override it |
35
- | `UploaderError` / `FileUploadingError` | Upload failures, on top of `ComponentError` |
36
- | `appendWebLogin(ctx)` | Register the login host plus the redirect and surrogate-window plugins |
37
- | `makeRedirectLoginPlugin()` / `makeSurrogateLoginPlugin()` / `awaitSurrogate(win, type, onMessage)` | The two browser login plugins and the window pump they share |
38
- | `SurrogateScreen` / `LoginSurrogateView` / `SurrogateStage` / `SurrogateViewProps` | What the surrogate login window renders |
39
- | `makeAuthWebService(alias?)` / `appendWebAuthService(ctx, alias?)` | The auth service whose `update(undefined)` leaves for the dispatcher. The append form also registers `authMiddleware` and the logout middleware |
40
- | `extractPrimaryHost(ctx)` | Fill `cfg.primaryHost` / `primaryPort` from `window.location` |
41
- | `DEFAULT_ROOT` (`root`), `REDIRECT_LOGIN`, `SURROGATE_LOGIN`, `SURROGATE_LOGIN_PRIORITY` (100) | Constants |
42
-
43
- ### Re-exported for authoring
44
-
45
- `handler` (from `@owlmeans/client`); `entrypoint`, `elevate`, `provideRequest`, `stab` and the
46
- `ClientEntrypoint` type (from `@owlmeans/client-entrypoint`); `route`, `frontend` (from
47
- `@owlmeans/route`); `config` (from `@owlmeans/client-context`); `service` (from `@owlmeans/config`);
48
- `AppType`, `HOME`, `ROOT`, `BASE`, `GUEST` (from `@owlmeans/context`). Import them from here so an
49
- app's entrypoint file needs one import.
50
-
51
- ## Usage
52
-
53
- ### Entry point
54
- ```typescript
55
- // index.tsx
56
- import { renderApp } from '@owlmeans/web-client'
57
- import { makeContext } from './context.js'
58
- import { appEntrypoints } from './entrypoints.js'
59
- import { MANAGER, MANAGER_API } from 'my-common'
60
- import config from './config.js'
61
-
62
- const context = makeContext(config)
63
- context.registerEntrypoints(appEntrypoints)
64
- context.serviceRoute(MANAGER, true)
65
- context.serviceRoute(MANAGER_API, true)
66
- renderApp<Config, Context>(context)
67
- ```
68
-
69
- `serviceRoute(alias, makeDefault?)` marks a service's routing root; an alias `cfg.services` does not
70
- carry throws a `SyntaxError` naming everything that is registered. Anything passed as `renderApp`'s
71
- third argument mounts once, above routing, and survives navigation — which is where a consent
72
- dialog or a toast surface belongs, since the same component inside a route is torn down and rebuilt
73
- on every navigation and a dialog would close itself.
74
-
75
- ### Entrypoint elevation with React components
76
- ```typescript
77
- import { elevate, route, frontend, handler, entrypoint } from '@owlmeans/web-client'
78
- import { HomeScreen, ProjectDashboardScreen } from './screens/index.js'
79
-
80
- elevate(entrypoints, manager.front.project.dashboard, handler(ProjectDashboardScreen))
81
-
82
- entrypoints.push(
83
- entrypoint(route(HOME, '/', frontend({ default: true, parent: BASE })), handler(HomeScreen))
84
- )
85
- ```
86
-
87
- `elevate` is idempotent — it replaces the declaration in the list, so re-elevating an alias (a
88
- screen swapped for a variant build, a guard added to an already-elevated one) is allowed, and
89
- guards named at elevation are unioned with the declared ones rather than replacing them. A backend
90
- alias takes no handler at all: giving one is a wiring error and throws.
91
-
92
- A **backend** alias the client calls needs a bare `elevate(entrypoints, alias)` — no handler. That
93
- opts the alias into client-side callability, so:
94
-
95
- ```typescript
96
- const project = await context.entrypoint<ClientEntrypoint<Project>>(alias)
97
- .call({ params, body, query }) // the value; the reply's error is thrown
98
- const { value, outcome } = await context.entrypoint<ClientEntrypoint<Project>>(alias)
99
- .invoke({ params }) // when the outcome decides what happens next
100
- const href = await context.entrypoint<ClientEntrypoint<Project>>(alias)
101
- .url({ params }, { absolute: true }) // the address, not the round trip
102
- ```
103
-
104
- The auth header is attached automatically for guarded entrypoints. An entrypoint that renders a
105
- screen answers `url()` and throws from `call()`/`invoke()` — a screen is navigated to, not called.
106
-
107
- A guarded call whose session the server rejects logs the user out rather than surfacing the error
108
- raw. `appendWebAuthService` registers a logout middleware for this — internal to the package, not
109
- an import — which wraps `invoke` on every guarded backend entrypoint (that covers `call`, since
110
- `call` reads `invoke` at the moment it runs), and an `AuthUnknown` ending in `:invalid` clears the
111
- token, which through the web auth service leaves for the dispatcher.
112
-
113
- ### Login comes with the context
114
-
115
- `makeContext` calls `appendWebLogin`, which registers the login host (`@owlmeans/client-auth/login`)
116
- and both browser plugins on it — redirect (`REDIRECT_LOGIN`, priority 0, applies always) and
117
- surrogate window (`SURROGATE_LOGIN`, priority 100, applies in a frame or in the surrogate itself).
118
- So every web app — and everything built on `web-panel` or `mui-panel` — has working sign-in,
119
- including from an embedded app, with nothing registered by hand:
120
-
121
- ```typescript
122
- import { useLogin, useLogout } from '@owlmeans/client-auth/login'
123
-
124
- const [, onLogIn] = useLogin() // one control, one handler, no environment checks
125
- ```
126
-
127
- The dispatcher and the surrogate screen are elevated on the auth entrypoint list this package
128
- exports, so an app that spreads `entrypoints` into its own list gets both without an edit. The
129
- surrogate screen renders `LoginSurrogateView` with plain elements and inline styles on purpose: it
130
- runs in a popup opened by apps with entirely different stylesheets, none of which is loaded there.
131
-
132
- An app that needs a different mechanic registers its own plugin at a higher priority after building
133
- the base context (`context.login().registerPlugin(...)`); it never replaces these. The contract, the
134
- cascade and the invariants are the [[login-plugins]] skill.
135
-
136
- ### Reading auth state
9
+ Shared protocol declarations are immutable. Bind a complete protocol tree for callable API routes,
10
+ then bind frontend declarations to screens.
137
11
 
138
12
  ```ts
139
- import { useAuthenticated } from '@owlmeans/web-client'
140
-
141
- const authenticated = useAuthenticated() // false until the check settles
13
+ import { bindAll, bindScreen, entrypoints as frameworkEntrypoints, handler } from '@owlmeans/web-panel'
14
+ import { projectEntrypoints, webEntrypoints } from 'project-common'
15
+ import { ProjectScreen } from './screens/project.js'
16
+
17
+ export const appEntrypoints = [
18
+ ...frameworkEntrypoints,
19
+ ...bindAll(projectEntrypoints),
20
+ bindScreen(webEntrypoints.project, handler(ProjectScreen)),
21
+ ]
142
22
  ```
143
23
 
144
- `useAuthenticated()` asks `context.auth().authenticated()` — the one channel the dispatcher and the
145
- login screen already read, answering from the auth service's token or rehydrating it from the auth
146
- resource. It is what a header uses to choose between the "Log in" and "Log out" control; nothing
147
- about it navigates, and it does not re-check, because both ways out of its answer replace the
148
- document.
149
-
150
- **It reports; it does not guard.** The guard is `useSelfAuth` from `@owlmeans/client-auth`, which
151
- sends an anonymous visitor to the dispatcher and defaults to doing so — the wrong behaviour for a
152
- component that only wants to know which control to draw. An application declares neither hook
153
- itself.
154
-
155
- ### Navigation
156
- ```typescript
157
- import { useNavigate } from '@owlmeans/client' // not re-exported by web-client
158
- import { useStoreList, useStoreModel } from '@owlmeans/client' // client state — also not re-exported
24
+ Call a protocol directly. Its request and response types come from its shared contract.
159
25
 
160
- const nav = useNavigate()
161
- <Button onClick={nav.press(manager.front.project.dashboard, { params: { projectId } })}>Open</Button>
162
- await nav.go(alias, { params }) // programmatic; nav.back() to go back
26
+ ```ts
27
+ const project = await context.entrypoint(projectEntrypoints.get).call({
28
+ params: { id: projectId },
29
+ })
163
30
  ```
164
31
 
165
- The navigator resolves its target through the entrypoint's own `url(request)`, so a screen names an
166
- alias and never assembles a path. Render a plain `<a href>` the same way — `await
167
- context.entrypoint(alias).url({ params })`, or the `Link` component from `@owlmeans/web-panel`,
168
- which does it for you.
169
-
170
- ## Depends On
171
-
172
- - `@owlmeans/client`, `@owlmeans/web-router` (default OwlMeans browser routing), `@owlmeans/web-db`
173
- (the IndexedDB store behind the client resources), `@owlmeans/client-i18n`
174
- - `@owlmeans/client-auth` — `AUTH_RESOURCE`, the dispatcher HOC, and the `./login` host the browser
175
- plugins register on; `@owlmeans/auth`, `@owlmeans/auth-common`
176
- - `@owlmeans/client-context`, `@owlmeans/client-entrypoint`, `@owlmeans/client-resource`,
177
- `@owlmeans/client-route`, `@owlmeans/route`, `@owlmeans/config`, `@owlmeans/context`,
178
- `@owlmeans/error`, `@owlmeans/i18n`, `react-dropzone`
179
- - `@owlmeans/web-panel` and `@owlmeans/mui-panel` build **on** this package, not the other way
180
- round: a UI-family app imports the panel package and gets this one with it
181
- - `react`, `react-dom` (peer). It does not depend on `react-router` — opt into it with
182
- `@owlmeans/web-router-react-router` (`appendReactRouter`). Routing needs no explicit provider:
183
- `PanelApp`/`App` compile through `context.router()`, so nothing passes a `provide` prop.
184
-
185
- ## Related
32
+ ## Rules
186
33
 
187
- - [[client]] — the React primitives and the hooks this does not re-export
188
- - [[login-plugins]] — the plugin cascade the two browser plugins take part in
189
- - [[web-router]] — the routing this context registers
34
+ - Declare paths, guards, gates and contracts once in the shared protocol tree.
35
+ - Bind every API declaration the browser calls, including route parents.
36
+ - Use `bindScreen(protocol, handler(Component))` only for frontend route declarations.
37
+ - Do not replace request/response typing at a call site; update the shared contract instead.
38
+ - Keep framework entrypoints and application entrypoints in one registered array, without mutating a
39
+ shared declaration collection.
@@ -1 +1 @@
1
- {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../src/components/dispatcher/component.tsx"],"names":[],"mappings":"AAUA,eAAO,MAAM,UAAU,6FAsGrB,CAAA"}
1
+ {"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../../../src/components/dispatcher/component.tsx"],"names":[],"mappings":"AAUA,eAAO,MAAM,UAAU,6FA+FrB,CAAA"}
@@ -3,7 +3,7 @@ import { DispatcherHOC } from '@owlmeans/client-auth';
3
3
  import { useEffect, useState } from 'react';
4
4
  import { useI18nLib } from '@owlmeans/client-i18n';
5
5
  import { AUTH_QUERY } from '@owlmeans/auth';
6
- import { FallbackLoginScreen, LoginIntent, LoginOutcome, ResumeAction, resumeAction, LOGIN_FRESH_QUERY, } from '@owlmeans/client-auth/login';
6
+ import { FallbackLoginScreen, LoginIntent, LoginOutcome, ResumeAction, resumeAction, } from '@owlmeans/client-auth/login';
7
7
  import { LoginSurrogateView, SurrogateStage } from '../../login/view.js';
8
8
  import { useContext } from '../../context.js';
9
9
  export const Dispatcher = DispatcherHOC(({ provideToken, navigate }) => {
@@ -33,13 +33,7 @@ export const Dispatcher = DispatcherHOC(({ provideToken, navigate }) => {
33
33
  provideToken({ token }, params);
34
34
  return;
35
35
  }
36
- // `fresh` says this window was opened to PRODUCE a session, so one it merely finds on this
37
- // origin is not the answer — see LOGIN_FRESH_QUERY. Kept identical to the relying party's own
38
- // dispatcher: the last time these two held their own copy of a decision they drifted.
39
- const found = query.has(LOGIN_FRESH_QUERY)
40
- ? Promise.resolve(null)
41
- : context.auth().authenticated();
42
- void found.then(async (authzToken) => {
36
+ void context.auth().authenticated().then(async (authzToken) => {
43
37
  if (authzToken == null || authzToken === '') {
44
38
  setChoose(true);
45
39
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/components/dispatcher/component.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"component.js","sourceRoot":"","sources":["../../../src/components/dispatcher/component.tsx"],"names":[],"mappings":"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"}
@@ -1,2 +1,16 @@
1
- export declare const entrypoints: import("@owlmeans/client-entrypoint").ClientEntrypoint<{}, import("@owlmeans/client-entrypoint").ClientRequest<{}>>[];
1
+ /**
2
+ * Bound here rather than in a relying-party package on purpose.
3
+ *
4
+ * The surrogate mechanic is not OIDC-specific — it is "run the login route one window up and hand
5
+ * the result back" — and every web application already spreads this list. Putting the screen here
6
+ * means `web-panel`, `mui-panel` and every generated target gain a working login window with no
7
+ * edit of their own, which is the only way an application that is already deployed can get it.
8
+ */
9
+ export declare const entrypoints: (import("@owlmeans/client-entrypoint").ClientProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<{
10
+ query: import("@owlmeans/auth").AuthToken;
11
+ }, undefined>> | import("@owlmeans/client-entrypoint").ClientProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<{
12
+ query: import("@owlmeans/auth-common").SurrogateQuery;
13
+ }, undefined>> | import("@owlmeans/client-entrypoint").ClientProtocolEntrypoint<import("@owlmeans/entrypoint").EntrypointProtocol<{
14
+ body: import("@owlmeans/auth").AuthToken;
15
+ }, import("@owlmeans/auth").AuthToken>>)[];
2
16
  //# sourceMappingURL=entrypoints.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,WAAW,uHAAO,CAAA"}
1
+ {"version":3,"file":"entrypoints.d.ts","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW;;;;;;0CAIvB,CAAA"}
@@ -1,18 +1,20 @@
1
- import { DISPATCHER, DISPATCHER_SURROGATE } from '@owlmeans/auth';
2
- import { entrypoints as list } from '@owlmeans/client-auth';
3
- import { elevate } from '@owlmeans/client-entrypoint';
1
+ import { authProtocols } from '@owlmeans/auth-common';
2
+ import { entrypoints as authBindings } from '@owlmeans/client-auth';
3
+ import { bindScreen } from '@owlmeans/client-entrypoint';
4
4
  import { handler } from '@owlmeans/client';
5
5
  import { Dispatcher } from './components/dispatcher/component.js';
6
6
  import { SurrogateScreen } from './login/screen.js';
7
- elevate(list, DISPATCHER, handler(Dispatcher));
8
7
  /**
9
- * Elevated here rather than in a relying-party package on purpose.
8
+ * Bound here rather than in a relying-party package on purpose.
10
9
  *
11
10
  * The surrogate mechanic is not OIDC-specific — it is "run the login route one window up and hand
12
11
  * the result back" — and every web application already spreads this list. Putting the screen here
13
12
  * means `web-panel`, `mui-panel` and every generated target gain a working login window with no
14
13
  * edit of their own, which is the only way an application that is already deployed can get it.
15
14
  */
16
- elevate(list, DISPATCHER_SURROGATE, handler(SurrogateScreen));
17
- export const entrypoints = list;
15
+ export const entrypoints = [
16
+ ...authBindings,
17
+ bindScreen(authProtocols.dispatcher, handler(Dispatcher)),
18
+ bindScreen(authProtocols.surrogate, handler(SurrogateScreen)),
19
+ ];
18
20
  //# sourceMappingURL=entrypoints.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AACjE,OAAO,EAAE,WAAW,IAAI,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAA;AAE9C;;;;;;;GAOG;AACH,OAAO,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,CAAA;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAA"}
1
+ {"version":3,"file":"entrypoints.js","sourceRoot":"","sources":["../src/entrypoints.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAA;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEnD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,GAAG,YAAY;IACf,UAAU,CAAC,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACzD,UAAU,CAAC,aAAa,CAAC,SAAS,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CAC9D,CAAA"}
@@ -2,7 +2,7 @@ export { handler } from '@owlmeans/client';
2
2
  export { config } from '@owlmeans/client-context';
3
3
  export { service } from '@owlmeans/config';
4
4
  export { AppType, HOME, ROOT, BASE, GUEST } from '@owlmeans/context';
5
- export { entrypoint, elevate, provideRequest, stab } from '@owlmeans/client-entrypoint';
5
+ export { bind, bindAll, bindScreen, provideRequest, stab } from '@owlmeans/client-entrypoint';
6
6
  export { route, frontend } from '@owlmeans/route';
7
7
  export type { ClientEntrypoint } from '@owlmeans/client-entrypoint';
8
8
  export type { ClientEntrypoint as Module } from '@owlmeans/client-entrypoint';
@@ -1 +1 @@
1
- {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AACvF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACjD,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,YAAY,EAAE,gBAAgB,IAAI,MAAM,EAAE,MAAM,6BAA6B,CAAA;AAC7E,YAAY,EAAE,WAAW,IAAI,KAAK,EAAE,MAAM,wBAAwB,CAAA"}
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AAC7F,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AACjD,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AACnE,YAAY,EAAE,gBAAgB,IAAI,MAAM,EAAE,MAAM,6BAA6B,CAAA;AAC7E,YAAY,EAAE,WAAW,IAAI,KAAK,EAAE,MAAM,wBAAwB,CAAA"}
package/build/exports.js CHANGED
@@ -2,6 +2,6 @@ export { handler } from '@owlmeans/client';
2
2
  export { config } from '@owlmeans/client-context';
3
3
  export { service } from '@owlmeans/config';
4
4
  export { AppType, HOME, ROOT, BASE, GUEST } from '@owlmeans/context';
5
- export { entrypoint, elevate, provideRequest, stab } from '@owlmeans/client-entrypoint';
5
+ export { bind, bindAll, bindScreen, provideRequest, stab } from '@owlmeans/client-entrypoint';
6
6
  export { route, frontend } from '@owlmeans/route';
7
7
  //# sourceMappingURL=exports.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AACvF,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"exports.js","sourceRoot":"","sources":["../src/exports.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AACpE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AAC7F,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA"}
package/build/helper.d.ts CHANGED
@@ -1,22 +1,3 @@
1
1
  import type { AppConfig, AppContext } from './types.js';
2
2
  export declare const extractPrimaryHost: <C extends AppConfig = AppConfig, T extends AppContext<C> = AppContext<C>>(context: T) => void;
3
- /**
4
- * Whether this browsing context currently holds a session — the flag a screen renders against
5
- * when it offers "Log in" or "Log out", a profile menu, or an authenticated-only panel.
6
- *
7
- * It reads the one channel the rest of the package reads, `context.auth().authenticated()`, which
8
- * answers from the auth service's token or, in a cold document, rehydrates it from the auth
9
- * resource. Nothing here touches storage or decodes a token: a second way to ask the same question
10
- * is a second thing to keep in step with logout.
11
- *
12
- * The answer is `false` until that promise settles and is not re-checked afterwards, because both
13
- * transitions out of the current answer replace the document — signing in navigates through the
14
- * dispatcher, and `auth().update(undefined)` assigns `document.location.href`. There is no in-page
15
- * change to subscribe to.
16
- *
17
- * This reports; it does not guard. `useSelfAuth` from `@owlmeans/client-auth` is the guard — it
18
- * sends an anonymous visitor to the dispatcher, which is the wrong behaviour for a component that
19
- * only wants to know which control to draw.
20
- */
21
- export declare const useAuthenticated: () => boolean;
22
3
  //# sourceMappingURL=helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvD,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,SAKtH,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,QAAO,OAgBnC,CAAA"}
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvD,eAAO,MAAM,kBAAkB,GAAI,CAAC,SAAS,SAAS,GAAG,SAAS,EAAE,CAAC,SAAS,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,SAKtH,CAAA"}
package/build/helper.js CHANGED
@@ -1,41 +1,7 @@
1
- import { useEffect, useState } from 'react';
2
- import { useContext } from '@owlmeans/client';
3
1
  export const extractPrimaryHost = (context) => {
4
2
  if (typeof window !== 'undefined') {
5
3
  context.cfg.primaryHost = window.location.hostname;
6
4
  context.cfg.primaryPort = window.location.port != null && window.location.port != '' ? parseInt(window.location.port) : undefined;
7
5
  }
8
6
  };
9
- /**
10
- * Whether this browsing context currently holds a session — the flag a screen renders against
11
- * when it offers "Log in" or "Log out", a profile menu, or an authenticated-only panel.
12
- *
13
- * It reads the one channel the rest of the package reads, `context.auth().authenticated()`, which
14
- * answers from the auth service's token or, in a cold document, rehydrates it from the auth
15
- * resource. Nothing here touches storage or decodes a token: a second way to ask the same question
16
- * is a second thing to keep in step with logout.
17
- *
18
- * The answer is `false` until that promise settles and is not re-checked afterwards, because both
19
- * transitions out of the current answer replace the document — signing in navigates through the
20
- * dispatcher, and `auth().update(undefined)` assigns `document.location.href`. There is no in-page
21
- * change to subscribe to.
22
- *
23
- * This reports; it does not guard. `useSelfAuth` from `@owlmeans/client-auth` is the guard — it
24
- * sends an anonymous visitor to the dispatcher, which is the wrong behaviour for a component that
25
- * only wants to know which control to draw.
26
- */
27
- export const useAuthenticated = () => {
28
- const context = useContext();
29
- const [authenticated, setAuthenticated] = useState(false);
30
- useEffect(() => {
31
- let mounted = true;
32
- void context.auth().authenticated().then(token => {
33
- if (mounted) {
34
- setAuthenticated(token != null && token !== '');
35
- }
36
- });
37
- return () => { mounted = false; };
38
- }, []);
39
- return authenticated;
40
- };
41
7
  //# sourceMappingURL=helper.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAA2E,OAAU,EAAE,EAAE;IACzH,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAA;QAClD,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACnI,CAAC;AACH,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAY,EAAE;IAC5C,MAAM,OAAO,GAAG,UAAU,EAAyB,CAAA;IACnD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAEzD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,GAAG,IAAI,CAAA;QAClB,KAAK,OAAO,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE;YAC/C,IAAI,OAAO,EAAE,CAAC;gBACZ,gBAAgB,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC,CAAA;YACjD,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE,GAAG,OAAO,GAAG,KAAK,CAAA,CAAC,CAAC,CAAA;IAClC,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,aAAa,CAAA;AACtB,CAAC,CAAA"}
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAA2E,OAAU,EAAE,EAAE;IACzH,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAA;QAClD,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACnI,CAAC;AACH,CAAC,CAAA"}
@@ -7,22 +7,9 @@ import type { FC } from 'react';
7
7
  * application, with its navigation, inside itself. This screen has no continuation at all — it
8
8
  * either hands something back and closes, or it says what it is waiting for.
9
9
  *
10
- * It does not run the authorization machine itself either: it forwards to the dispatcher (`next`),
11
- * which owns that flow.
12
- *
13
- * It used to short-circuit that when a session was already present on this origin — hand it back,
14
- * no provider round trip. That is wrong, and it was the whole of a reported defect. This window is
15
- * first-party on the application's origin, so what it finds there is whatever the person's own
16
- * tabs left behind, and a token being present says nothing about the record behind it still
17
- * existing: `authenticated()` reads storage and decodes an envelope, and no client asks the server.
18
- * A session that had been revoked, replaced or expired was therefore handed back to a window that
19
- * had asked for a LOGIN, adopted, and used to fail every call — and the next press of the same
20
- * button found the same dead token and did it again. Nothing recovered but clearing site data.
21
- *
22
- * So an explicit login PRODUCES a session. `fresh` says so to the dispatcher, which skips its own
23
- * resume for the same reason. The cost is one provider round trip that the provider's own session
24
- * normally answers without asking the person anything; the gain is that what comes back has just
25
- * been vouched for, and that signing in as somebody else is possible at all.
10
+ * It also never runs the authorization machine. When there is already a session here, that is the
11
+ * answer, and it goes back to the opener immediately — no provider round trip, no PKCE exchange.
12
+ * When there is not, it forwards to the dispatcher (`next`), which owns that flow.
26
13
  */
27
14
  export declare const SurrogateScreen: FC;
28
15
  //# sourceMappingURL=screen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/login/screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAW/B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,eAAe,EAAE,EAoF7B,CAAA"}
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/login/screen.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAA;AAU/B;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,EAAE,EA+F7B,CAAA"}
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useState } from 'react';
3
3
  import { useContext } from '@owlmeans/client';
4
4
  import { useI18nLib } from '@owlmeans/client-i18n';
5
- import { LoginIntent, LoginOutcome, LOGIN_FRESH_QUERY, LOGIN_INTENT_QUERY, LOGIN_METHOD_QUERY, LOGIN_NEXT_QUERY, } from '@owlmeans/client-auth/login';
5
+ import { LoginIntent, LoginOutcome, LOGIN_INTENT_QUERY, LOGIN_METHOD_QUERY, LOGIN_NEXT_QUERY, } from '@owlmeans/client-auth/login';
6
6
  import { LoginSurrogateView, SurrogateStage } from './view.js';
7
7
  /**
8
8
  * The login window an embedded application opens one level up.
@@ -12,22 +12,9 @@ import { LoginSurrogateView, SurrogateStage } from './view.js';
12
12
  * application, with its navigation, inside itself. This screen has no continuation at all — it
13
13
  * either hands something back and closes, or it says what it is waiting for.
14
14
  *
15
- * It does not run the authorization machine itself either: it forwards to the dispatcher (`next`),
16
- * which owns that flow.
17
- *
18
- * It used to short-circuit that when a session was already present on this origin — hand it back,
19
- * no provider round trip. That is wrong, and it was the whole of a reported defect. This window is
20
- * first-party on the application's origin, so what it finds there is whatever the person's own
21
- * tabs left behind, and a token being present says nothing about the record behind it still
22
- * existing: `authenticated()` reads storage and decodes an envelope, and no client asks the server.
23
- * A session that had been revoked, replaced or expired was therefore handed back to a window that
24
- * had asked for a LOGIN, adopted, and used to fail every call — and the next press of the same
25
- * button found the same dead token and did it again. Nothing recovered but clearing site data.
26
- *
27
- * So an explicit login PRODUCES a session. `fresh` says so to the dispatcher, which skips its own
28
- * resume for the same reason. The cost is one provider round trip that the provider's own session
29
- * normally answers without asking the person anything; the gain is that what comes back has just
30
- * been vouched for, and that signing in as somebody else is possible at all.
15
+ * It also never runs the authorization machine. When there is already a session here, that is the
16
+ * answer, and it goes back to the opener immediately — no provider round trip, no PKCE exchange.
17
+ * When there is not, it forwards to the dispatcher (`next`), which owns that flow.
31
18
  */
32
19
  export const SurrogateScreen = () => {
33
20
  const context = useContext();
@@ -64,6 +51,7 @@ export const SurrogateScreen = () => {
64
51
  return;
65
52
  }
66
53
  const run = async () => {
54
+ const token = await context.auth().authenticated();
67
55
  if (intent === LoginIntent.Logout) {
68
56
  // Revoked FIRST, before anything can be awaited on a channel that may never answer: a
69
57
  // window the user closes half a second later must still have ended the session it opened
@@ -75,22 +63,28 @@ export const SurrogateScreen = () => {
75
63
  : SurrogateStage.Failed);
76
64
  return;
77
65
  }
78
- // The dispatcher owns the authorization round trip, and the provider's callback lands there
79
- // rather than on this route. Two things travel with it: the method the user already chose,
80
- // so the dispatcher does not ask a second time in a window with no one to ask, and `fresh`,
81
- // which tells it that a session it happens to find here is not the answer to this request.
66
+ if (token != null && token !== '') {
67
+ // Already signed in here. The framed application is the one that asked, so the session
68
+ // goes to it rather than being displayed to this window.
69
+ const outcome = await login.resume(token);
70
+ setStage(outcome === LoginOutcome.Handled ? SurrogateStage.Handing
71
+ : outcome === LoginOutcome.Orphaned ? SurrogateStage.Orphaned
72
+ : SurrogateStage.Failed);
73
+ return;
74
+ }
75
+ // Nothing here yet — the dispatcher owns the authorization round trip, and the provider's
76
+ // callback lands there rather than on this route. The method the user already chose travels
77
+ // with it, so the dispatcher does not ask a second time in a window with no one to ask.
82
78
  const next = query.get(LOGIN_NEXT_QUERY);
83
79
  if (next == null || next === '') {
84
80
  setStage(SurrogateStage.Gesture);
85
81
  return;
86
82
  }
87
83
  const method = query.get(LOGIN_METHOD_QUERY);
88
- const params = new URLSearchParams();
89
- if (method != null && method !== '') {
90
- params.set(LOGIN_METHOD_QUERY, method);
91
- }
92
- params.set(LOGIN_FRESH_QUERY, '1');
93
- window.location.href = `${next}${next.includes('?') ? '&' : '?'}${params.toString()}`;
84
+ const target = method != null && method !== ''
85
+ ? `${next}${next.includes('?') ? '&' : '?'}${LOGIN_METHOD_QUERY}=${encodeURIComponent(method)}`
86
+ : next;
87
+ window.location.href = target;
94
88
  };
95
89
  void run().catch((e) => {
96
90
  console.error(e);
@@ -1 +1 @@
1
- {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/login/screen.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAExD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EACL,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EACpF,gBAAgB,GACjB,MAAM,6BAA6B,CAAA;AAGpC,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAO,GAAG,EAAE;IACtC,MAAM,OAAO,GAAG,UAAU,EAA2B,CAAA;IACrD,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,eAAe,EAAE,CAAA;IAClD,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;IAE5B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,WAAW,CAAC,MAAM;QACjE,CAAC,CAAC,WAAW,CAAC,MAAM;QACpB,CAAC,CAAC,WAAW,CAAC,KAAK,CAAA;IAErB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAiB,cAAc,CAAC,OAAO,CAAC,CAAA;IAC1E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,EAAsB,CAAA;IAExD,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,IAAI,KAAK,KAAK,cAAc,CAAC,UAAU,EAAE,CAAC;YACxC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAA;YAC1B,OAAM;QACR,CAAC;QACD,IAAI,KAAK,KAAK,cAAc,CAAC,OAAO,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;YACxC,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;YACjE,OAAM;QACR,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,CAAA;IAChB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;IAE3B,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAe,eAAe,CAAC,CAAA;QAC5D,yFAAyF;QACzF,yFAAyF;QACzF,iCAAiC;QACjC,KAAK,CAAC,KAAK,EAAE,CAAA;QAEb,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;QACvB,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;YACnB,0FAA0F;YAC1F,sCAAsC;YACtC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,UAAU,CAAC,CAAA;YAC3E,OAAM;QACR,CAAC;QAED,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;YACpC,IAAI,MAAM,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;gBAClC,sFAAsF;gBACtF,yFAAyF;gBACzF,UAAU;gBACV,MAAM,KAAK,CAAC,MAAM,EAAE,CAAA;gBACpB,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE,CAAA;gBAC5C,QAAQ,CACN,OAAO,KAAK,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,OAAO;oBACvD,CAAC,CAAC,OAAO,KAAK,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,QAAQ;wBAC3D,CAAC,CAAC,cAAc,CAAC,MAAM,CAC5B,CAAA;gBACD,OAAM;YACR,CAAC;YAED,4FAA4F;YAC5F,2FAA2F;YAC3F,4FAA4F;YAC5F,2FAA2F;YAC3F,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;YACxC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;gBAChC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;gBAChC,OAAM;YACR,CAAC;YACD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;YAC5C,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE,CAAA;YACpC,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,KAAK,EAAE,EAAE,CAAC;gBACpC,MAAM,CAAC,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAA;YACxC,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAA;YAClC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAA;QACvF,CAAC,CAAA;QAED,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;YAC5B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YAChB,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;YACnB,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAA;QACjC,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAErB,OAAO,KAAC,kBAAkB,IACxB,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAC9D,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,GAC1D,CAAA;AACJ,CAAC,CAAA"}
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/login/screen.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/web-client",
3
- "version": "0.1.18-rc.26",
3
+ "version": "0.1.18-rc.27",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -21,22 +21,22 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@owlmeans/auth": "^0.1.18-rc.11",
25
- "@owlmeans/auth-common": "^0.1.18-rc.15",
26
- "@owlmeans/client": "^0.1.18-rc.18",
27
- "@owlmeans/client-auth": "^0.1.18-rc.22",
28
- "@owlmeans/client-context": "^0.1.18-rc.15",
29
- "@owlmeans/client-i18n": "^0.1.18-rc.17",
30
- "@owlmeans/client-entrypoint": "^0.1.18-rc.15",
31
- "@owlmeans/client-resource": "^0.1.18-rc.15",
32
- "@owlmeans/client-route": "^0.1.18-rc.15",
33
- "@owlmeans/config": "^0.1.18-rc.14",
34
- "@owlmeans/context": "^0.1.18-rc.10",
35
- "@owlmeans/error": "^0.1.18-rc.10",
36
- "@owlmeans/i18n": "^0.1.18-rc.10",
37
- "@owlmeans/route": "^0.1.18-rc.11",
38
- "@owlmeans/web-db": "^0.1.18-rc.16",
39
- "@owlmeans/web-router": "^0.1.18-rc.16",
24
+ "@owlmeans/auth": "^0.1.18-rc.12",
25
+ "@owlmeans/auth-common": "^0.1.18-rc.16",
26
+ "@owlmeans/client": "^0.1.18-rc.19",
27
+ "@owlmeans/client-auth": "^0.1.18-rc.23",
28
+ "@owlmeans/client-context": "^0.1.18-rc.16",
29
+ "@owlmeans/client-i18n": "^0.1.18-rc.18",
30
+ "@owlmeans/client-entrypoint": "^0.1.18-rc.16",
31
+ "@owlmeans/client-resource": "^0.1.18-rc.16",
32
+ "@owlmeans/client-route": "^0.1.18-rc.16",
33
+ "@owlmeans/config": "^0.1.18-rc.15",
34
+ "@owlmeans/context": "^0.1.18-rc.11",
35
+ "@owlmeans/error": "^0.1.18-rc.11",
36
+ "@owlmeans/i18n": "^0.1.18-rc.11",
37
+ "@owlmeans/route": "^0.1.18-rc.12",
38
+ "@owlmeans/web-db": "^0.1.18-rc.17",
39
+ "@owlmeans/web-router": "^0.1.18-rc.17",
40
40
  "react-dropzone": "^14.3.5"
41
41
  },
42
42
  "peerDependencies": {
@@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'
3
3
  import { useI18nLib } from '@owlmeans/client-i18n'
4
4
  import { AUTH_QUERY } from '@owlmeans/auth'
5
5
  import {
6
- FallbackLoginScreen, LoginIntent, LoginOutcome, ResumeAction, resumeAction, LOGIN_FRESH_QUERY,
6
+ FallbackLoginScreen, LoginIntent, LoginOutcome, ResumeAction, resumeAction,
7
7
  } from '@owlmeans/client-auth/login'
8
8
  import { LoginSurrogateView, SurrogateStage } from '../../login/view.js'
9
9
  import { useContext } from '../../context.js'
@@ -42,14 +42,7 @@ export const Dispatcher = DispatcherHOC(({ provideToken, navigate }) => {
42
42
  return
43
43
  }
44
44
 
45
- // `fresh` says this window was opened to PRODUCE a session, so one it merely finds on this
46
- // origin is not the answer — see LOGIN_FRESH_QUERY. Kept identical to the relying party's own
47
- // dispatcher: the last time these two held their own copy of a decision they drifted.
48
- const found = query.has(LOGIN_FRESH_QUERY)
49
- ? Promise.resolve(null)
50
- : context.auth().authenticated()
51
-
52
- void found.then(async authzToken => {
45
+ void context.auth().authenticated().then(async authzToken => {
53
46
  if (authzToken == null || authzToken === '') {
54
47
  setChoose(true)
55
48
 
@@ -1,20 +1,20 @@
1
- import { DISPATCHER, DISPATCHER_SURROGATE } from '@owlmeans/auth'
2
- import { entrypoints as list } from '@owlmeans/client-auth'
3
- import { elevate } from '@owlmeans/client-entrypoint'
1
+ import { authProtocols } from '@owlmeans/auth-common'
2
+ import { entrypoints as authBindings } from '@owlmeans/client-auth'
3
+ import { bindScreen } from '@owlmeans/client-entrypoint'
4
4
  import { handler } from '@owlmeans/client'
5
5
  import { Dispatcher } from './components/dispatcher/component.js'
6
6
  import { SurrogateScreen } from './login/screen.js'
7
7
 
8
- elevate(list, DISPATCHER, handler(Dispatcher))
9
-
10
8
  /**
11
- * Elevated here rather than in a relying-party package on purpose.
9
+ * Bound here rather than in a relying-party package on purpose.
12
10
  *
13
11
  * The surrogate mechanic is not OIDC-specific — it is "run the login route one window up and hand
14
12
  * the result back" — and every web application already spreads this list. Putting the screen here
15
13
  * means `web-panel`, `mui-panel` and every generated target gain a working login window with no
16
14
  * edit of their own, which is the only way an application that is already deployed can get it.
17
15
  */
18
- elevate(list, DISPATCHER_SURROGATE, handler(SurrogateScreen))
19
-
20
- export const entrypoints = list
16
+ export const entrypoints = [
17
+ ...authBindings,
18
+ bindScreen(authProtocols.dispatcher, handler(Dispatcher)),
19
+ bindScreen(authProtocols.surrogate, handler(SurrogateScreen)),
20
+ ]
package/src/exports.ts CHANGED
@@ -3,7 +3,7 @@ export { handler } from '@owlmeans/client'
3
3
  export { config } from '@owlmeans/client-context'
4
4
  export { service } from '@owlmeans/config'
5
5
  export { AppType, HOME, ROOT, BASE, GUEST } from '@owlmeans/context'
6
- export { entrypoint, elevate, provideRequest, stab } from '@owlmeans/client-entrypoint'
6
+ export { bind, bindAll, bindScreen, provideRequest, stab } from '@owlmeans/client-entrypoint'
7
7
  export { route, frontend } from '@owlmeans/route'
8
8
  export type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
9
9
  export type { ClientEntrypoint as Module } from '@owlmeans/client-entrypoint'
package/src/helper.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { useEffect, useState } from 'react'
2
- import { useContext } from '@owlmeans/client'
3
1
  import type { AppConfig, AppContext } from './types.js'
4
2
 
5
3
  export const extractPrimaryHost = <C extends AppConfig = AppConfig, T extends AppContext<C> = AppContext<C>>(context: T) => {
@@ -8,39 +6,3 @@ export const extractPrimaryHost = <C extends AppConfig = AppConfig, T extends Ap
8
6
  context.cfg.primaryPort = window.location.port != null && window.location.port != '' ? parseInt(window.location.port) : undefined
9
7
  }
10
8
  }
11
-
12
- /**
13
- * Whether this browsing context currently holds a session — the flag a screen renders against
14
- * when it offers "Log in" or "Log out", a profile menu, or an authenticated-only panel.
15
- *
16
- * It reads the one channel the rest of the package reads, `context.auth().authenticated()`, which
17
- * answers from the auth service's token or, in a cold document, rehydrates it from the auth
18
- * resource. Nothing here touches storage or decodes a token: a second way to ask the same question
19
- * is a second thing to keep in step with logout.
20
- *
21
- * The answer is `false` until that promise settles and is not re-checked afterwards, because both
22
- * transitions out of the current answer replace the document — signing in navigates through the
23
- * dispatcher, and `auth().update(undefined)` assigns `document.location.href`. There is no in-page
24
- * change to subscribe to.
25
- *
26
- * This reports; it does not guard. `useSelfAuth` from `@owlmeans/client-auth` is the guard — it
27
- * sends an anonymous visitor to the dispatcher, which is the wrong behaviour for a component that
28
- * only wants to know which control to draw.
29
- */
30
- export const useAuthenticated = (): boolean => {
31
- const context = useContext<AppConfig, AppContext>()
32
- const [authenticated, setAuthenticated] = useState(false)
33
-
34
- useEffect(() => {
35
- let mounted = true
36
- void context.auth().authenticated().then(token => {
37
- if (mounted) {
38
- setAuthenticated(token != null && token !== '')
39
- }
40
- })
41
-
42
- return () => { mounted = false }
43
- }, [])
44
-
45
- return authenticated
46
- }
@@ -3,8 +3,7 @@ import type { FC } from 'react'
3
3
  import { useContext } from '@owlmeans/client'
4
4
  import { useI18nLib } from '@owlmeans/client-i18n'
5
5
  import {
6
- LoginIntent, LoginOutcome, LOGIN_FRESH_QUERY, LOGIN_INTENT_QUERY, LOGIN_METHOD_QUERY,
7
- LOGIN_NEXT_QUERY,
6
+ LoginIntent, LoginOutcome, LOGIN_INTENT_QUERY, LOGIN_METHOD_QUERY, LOGIN_NEXT_QUERY,
8
7
  } from '@owlmeans/client-auth/login'
9
8
  import type { LoginService } from '@owlmeans/client-auth/login'
10
9
  import type { AppContext } from '../types.js'
@@ -18,22 +17,9 @@ import { LoginSurrogateView, SurrogateStage } from './view.js'
18
17
  * application, with its navigation, inside itself. This screen has no continuation at all — it
19
18
  * either hands something back and closes, or it says what it is waiting for.
20
19
  *
21
- * It does not run the authorization machine itself either: it forwards to the dispatcher (`next`),
22
- * which owns that flow.
23
- *
24
- * It used to short-circuit that when a session was already present on this origin — hand it back,
25
- * no provider round trip. That is wrong, and it was the whole of a reported defect. This window is
26
- * first-party on the application's origin, so what it finds there is whatever the person's own
27
- * tabs left behind, and a token being present says nothing about the record behind it still
28
- * existing: `authenticated()` reads storage and decodes an envelope, and no client asks the server.
29
- * A session that had been revoked, replaced or expired was therefore handed back to a window that
30
- * had asked for a LOGIN, adopted, and used to fail every call — and the next press of the same
31
- * button found the same dead token and did it again. Nothing recovered but clearing site data.
32
- *
33
- * So an explicit login PRODUCES a session. `fresh` says so to the dispatcher, which skips its own
34
- * resume for the same reason. The cost is one provider round trip that the provider's own session
35
- * normally answers without asking the person anything; the gain is that what comes back has just
36
- * been vouched for, and that signing in as somebody else is possible at all.
20
+ * It also never runs the authorization machine. When there is already a session here, that is the
21
+ * answer, and it goes back to the opener immediately — no provider round trip, no PKCE exchange.
22
+ * When there is not, it forwards to the dispatcher (`next`), which owns that flow.
37
23
  */
38
24
  export const SurrogateScreen: FC = () => {
39
25
  const context = useContext() as unknown as AppContext
@@ -76,6 +62,8 @@ export const SurrogateScreen: FC = () => {
76
62
  }
77
63
 
78
64
  const run = async (): Promise<void> => {
65
+ const token = await context.auth().authenticated()
66
+
79
67
  if (intent === LoginIntent.Logout) {
80
68
  // Revoked FIRST, before anything can be awaited on a channel that may never answer: a
81
69
  // window the user closes half a second later must still have ended the session it opened
@@ -90,22 +78,31 @@ export const SurrogateScreen: FC = () => {
90
78
  return
91
79
  }
92
80
 
93
- // The dispatcher owns the authorization round trip, and the provider's callback lands there
94
- // rather than on this route. Two things travel with it: the method the user already chose,
95
- // so the dispatcher does not ask a second time in a window with no one to ask, and `fresh`,
96
- // which tells it that a session it happens to find here is not the answer to this request.
81
+ if (token != null && token !== '') {
82
+ // Already signed in here. The framed application is the one that asked, so the session
83
+ // goes to it rather than being displayed to this window.
84
+ const outcome = await login.resume(token)
85
+ setStage(
86
+ outcome === LoginOutcome.Handled ? SurrogateStage.Handing
87
+ : outcome === LoginOutcome.Orphaned ? SurrogateStage.Orphaned
88
+ : SurrogateStage.Failed
89
+ )
90
+ return
91
+ }
92
+
93
+ // Nothing here yet — the dispatcher owns the authorization round trip, and the provider's
94
+ // callback lands there rather than on this route. The method the user already chose travels
95
+ // with it, so the dispatcher does not ask a second time in a window with no one to ask.
97
96
  const next = query.get(LOGIN_NEXT_QUERY)
98
97
  if (next == null || next === '') {
99
98
  setStage(SurrogateStage.Gesture)
100
99
  return
101
100
  }
102
101
  const method = query.get(LOGIN_METHOD_QUERY)
103
- const params = new URLSearchParams()
104
- if (method != null && method !== '') {
105
- params.set(LOGIN_METHOD_QUERY, method)
106
- }
107
- params.set(LOGIN_FRESH_QUERY, '1')
108
- window.location.href = `${next}${next.includes('?') ? '&' : '?'}${params.toString()}`
102
+ const target = method != null && method !== ''
103
+ ? `${next}${next.includes('?') ? '&' : '?'}${LOGIN_METHOD_QUERY}=${encodeURIComponent(method)}`
104
+ : next
105
+ window.location.href = target
109
106
  }
110
107
 
111
108
  void run().catch((e: Error) => {