@owlmeans/client-auth 0.1.18-rc.28 → 0.1.18-rc.29

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 (48) hide show
  1. package/README.md +278 -37
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/client-auth/SKILL.md +2 -2
  4. package/build/helper.d.ts +2 -1
  5. package/build/helper.d.ts.map +1 -1
  6. package/build/helper.js +23 -2
  7. package/build/helper.js.map +1 -1
  8. package/build/login/consts.d.ts +10 -0
  9. package/build/login/consts.d.ts.map +1 -1
  10. package/build/login/consts.js +11 -1
  11. package/build/login/consts.js.map +1 -1
  12. package/build/login/i18n/be.json +1 -1
  13. package/build/login/i18n/de.json +1 -1
  14. package/build/login/i18n/en.json +1 -1
  15. package/build/login/i18n/es.json +1 -1
  16. package/build/login/i18n/pl.json +1 -1
  17. package/build/login/i18n/ru.json +1 -1
  18. package/build/login/i18n/uk.json +1 -1
  19. package/build/login/resume.d.ts.map +1 -1
  20. package/build/login/resume.js +2 -0
  21. package/build/login/resume.js.map +1 -1
  22. package/build/login/service.d.ts.map +1 -1
  23. package/build/login/service.js +13 -2
  24. package/build/login/service.js.map +1 -1
  25. package/build/login/types.d.ts +22 -2
  26. package/build/login/types.d.ts.map +1 -1
  27. package/build/login/types.js +9 -1
  28. package/build/login/types.js.map +1 -1
  29. package/build/manager/entrypoints.d.ts +2 -2
  30. package/build/manager/entrypoints.d.ts.map +1 -1
  31. package/build/manager/plugins/tunnel-consumer.d.ts.map +1 -1
  32. package/build/manager/plugins/tunnel-consumer.js +4 -1
  33. package/build/manager/plugins/tunnel-consumer.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/helper.ts +25 -2
  36. package/src/login/consts.ts +14 -1
  37. package/src/login/i18n/be.json +1 -1
  38. package/src/login/i18n/de.json +1 -1
  39. package/src/login/i18n/en.json +1 -1
  40. package/src/login/i18n/es.json +1 -1
  41. package/src/login/i18n/pl.json +1 -1
  42. package/src/login/i18n/ru.json +1 -1
  43. package/src/login/i18n/uk.json +1 -1
  44. package/src/login/resume.ts +2 -0
  45. package/src/login/service.ts +18 -4
  46. package/src/login/types.ts +22 -1
  47. package/src/manager/plugins/tunnel-consumer.tsx +4 -1
  48. package/tests/login.spec.ts +19 -0
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # @owlmeans/client-auth
2
2
 
3
- Client-side authentication service providing user auth state and external auth flow setup.
4
-
5
- ## Overview
6
-
7
- - `useSelfAuth()` React hook that returns the current authenticated user's `Auth` object
8
- - `setupExternalAuthentication()` configure the client to authenticate against an external identity provider
9
- - `entrypoints` pre-built bindings for the auth protocols (login, dispatcher)
10
- - `DEFAULT_ALIAS` the auth service alias (`'auth'`)
3
+ The browser side of OwlMeans authentication: the client `AuthService` that holds the bearer token,
4
+ the dispatcher HOC that handles the authentication return leg, the authentication-plugin registry
5
+ and screen (`./manager`), and the login-plugin host with its sign-in method registry, terms
6
+ confirmation and `useLogin` / `useLogout` hooks (`./login`). A web app normally gets the auth
7
+ service and the login host from `@owlmeans/web-client`'s `makeContext`, and the styled sign-in
8
+ screen from `@owlmeans/web-panel`. It imports this package for the hooks, the dispatcher contract
9
+ and plugin authoring. The OIDC relying party is `@owlmeans/web-oidc-rp` (`@owlmeans/mui-oidc-rp` is
10
+ legacy). The server-side counterpart is `@owlmeans/server-auth`.
11
11
 
12
12
  ## Installation
13
13
 
@@ -15,60 +15,301 @@ Client-side authentication service providing user auth state and external auth f
15
15
  bun add @owlmeans/client-auth@^0.1.18-rc.19
16
16
  ```
17
17
 
18
+ ## Concepts
19
+
20
+ - **Auth service** — `context.auth()`. The token lives in the `AUTH_RESOURCE` resource under the
21
+ single id `USER_ID`. `authenticated()` resolves to the token or `null`, `user()` returns the
22
+ decoded `Auth` (throwing `AuthorizationError` when there is none), and `update(token | undefined)`
23
+ adopts or drops a session.
24
+ - **Dispatcher** — `DispatcherHOC` wraps a renderer that reads the return-leg query. It hands the
25
+ renderer `provideToken(token, query)` and `navigate()`, adopts the token, and strips `AUTH_QUERY`
26
+ before navigating on.
27
+ - **Authentication plugin** (`./manager/plugins`) — *how* a person proves identity: `type`,
28
+ `Implementation`, an optional `Renderer` a UI package supplies, and `method` metadata when it is
29
+ offered on the sign-in screen.
30
+ - **Login plugin** (`./login`) — *where* the round trip runs. Plugins are selected by `LoginEnv`
31
+ (embedded, surrogate) and priority. `@owlmeans/web-client` registers the redirect and surrogate
32
+ plugins.
33
+ - **Login method** — one offerable button. `LoginMethodSource`s produce candidates;
34
+ `resolveLoginMethods` drops restricted ones the config did not name and applies the configured
35
+ order.
36
+ - **Login outcome** — `LoginOutcome` (`Handled`, `Passed`, `Redirected`, `Gesture`, `Orphaned`,
37
+ `Failed`) tells the caller what to do next. `resumeAction` and `loginAttemptError` are the only
38
+ readings of it.
39
+
18
40
  ## Usage
19
41
 
20
- Access current auth state in a component:
42
+ ### 1. A context built by hand
43
+
44
+ `@owlmeans/web-client`'s `makeContext` already does this. Only a context composed without it
45
+ registers the pieces itself.
46
+
47
+ ```ts
48
+ import { makeClientContext } from '@owlmeans/client'
49
+ import { appendAuthService, bindExternalAuthentication, entrypoints as authEntrypoints } from '@owlmeans/client-auth'
50
+ import { appendLogin } from '@owlmeans/client-auth/login'
51
+ import { MY_APP_WEB } from 'my-app-common'
52
+ import type { Config, Context } from './types.js'
53
+
54
+ export const makeContext = <C extends Config, T extends Context<C>>(cfg: C): T => {
55
+ const context = makeClientContext(cfg) as T
56
+ appendAuthService<C, T>(context) // registers under DEFAULT_ALIAS ('auth'), exposes context.auth()
57
+ appendLogin<C, T>(context) // registers the login host, exposes context.login()
58
+
59
+ return context
60
+ }
61
+
62
+ export const clientBindings = [
63
+ ...authEntrypoints,
64
+ // The screen an external provider redirects into, pinned to this app's service.
65
+ bindExternalAuthentication(MY_APP_WEB),
66
+ ]
67
+ ```
68
+
69
+ ### 2. Guarding a layout and reading the identity
21
70
 
22
- ```typescript
71
+ ```tsx
72
+ import { entitySlugOf } from '@owlmeans/auth'
23
73
  import { useSelfAuth } from '@owlmeans/client-auth'
74
+ import type { FC, PropsWithChildren } from 'react'
75
+ import { useContext } from '../context.js'
24
76
 
25
- function UserMenu() {
26
- const auth = useSelfAuth()
27
- return <span>{auth?.userId}</span>
77
+ export const UserLayout: FC<PropsWithChildren> = ({ children }) => {
78
+ // `true` navigates to DISPATCHER when there is no session.
79
+ const authenticated = useSelfAuth(true)
80
+ const context = useContext()
81
+
82
+ if (!authenticated) {
83
+ return null
84
+ }
85
+
86
+ const auth = context.auth().user()
87
+ // The organization is its renameable entitySlug; the stable entityId never reaches the browser.
88
+ const organization = entitySlugOf(auth)
89
+
90
+ return <main data-organization={organization}>{children}</main>
28
91
  }
29
92
  ```
30
93
 
31
- Set up external authentication (e.g. OIDC redirect):
94
+ ### 3. Sign-in and sign-out controls
32
95
 
33
- ```typescript
34
- import { setupExternalAuthentication } from '@owlmeans/client-auth'
96
+ ```tsx
97
+ import type { FC } from 'react'
98
+ import { useLogin, useLogout } from '@owlmeans/client-auth/login'
35
99
 
36
- // In context setup
37
- setupExternalAuthentication(context, { serviceUrl: process.env.AUTH_URL })
100
+ export const HeaderActions: FC<{ authenticated: boolean | null }> = ({ authenticated }) => {
101
+ const [loginPath, onLogIn] = useLogin()
102
+ const onLogOut = useLogout()
103
+
104
+ if (authenticated == null) {
105
+ return null
106
+ }
107
+
108
+ return authenticated
109
+ ? <button type="button" onClick={onLogOut}>Log out</button>
110
+ : <a href={loginPath} onClick={onLogIn}>Log in</a>
111
+ }
38
112
  ```
39
113
 
114
+ One control and one handler, with no conditions around them. The login service decides whether the
115
+ flow redirects this tab or runs one window up, because the app is framed.
116
+
117
+ ### 4. Offering a sign-in method and gating the flow
118
+
119
+ ```ts
120
+ import { ensureLoginService, LoginOutcome } from '@owlmeans/client-auth/login'
121
+ import type { LoginMethodSource, LoginPrecondition } from '@owlmeans/client-auth/login'
122
+
123
+ const partnerMethods: LoginMethodSource = {
124
+ alias: 'my-app-partner-methods',
125
+ list: () => [{
126
+ id: 'partner-sso',
127
+ label: 'Partner SSO',
128
+ i18nKey: 'partner',
129
+ icon: 'building',
130
+ order: 20,
131
+ // Callable synchronously from the click: leave before the first await.
132
+ start: () => {
133
+ window.location.href = partnerAuthorizeUrl()
134
+
135
+ return Promise.resolve(LoginOutcome.Redirected)
136
+ },
137
+ }],
138
+ }
139
+
140
+ const maintenanceWindow: LoginPrecondition = {
141
+ alias: 'my-app-maintenance',
142
+ // Synchronous by contract — a precondition that asks a server belongs elsewhere.
143
+ check: () => !isMaintenanceBannerOpen(),
144
+ }
145
+
146
+ export const appendPartnerLogin = <C extends Config, T extends Context<C>>(context: T): T => {
147
+ const login = ensureLoginService(context)
148
+ login.registerMethodSource(partnerMethods)
149
+ login.registerPrecondition(maintenanceWindow)
150
+
151
+ return context
152
+ }
153
+ ```
154
+
155
+ ### 5. Authoring an authentication plugin
156
+
157
+ ```tsx
158
+ import { AuthenticationStage } from '@owlmeans/auth'
159
+ import type { AuthenticationRendererProps } from '@owlmeans/client-auth/manager'
160
+ import { registerAuthPlugin } from '@owlmeans/client-auth/manager/plugins'
161
+ import type { AuthenticationPlugin } from '@owlmeans/client-auth/manager/plugins'
162
+ import { useEffect } from 'react'
163
+
164
+ const MY_APP_PASSKEY = 'my-app-passkey'
165
+
166
+ export const passkeyPlugin: AuthenticationPlugin = {
167
+ type: MY_APP_PASSKEY,
168
+ method: { label: 'Passkey', icon: 'key', order: 50 },
169
+ // The form comes from a UI package; without one the screen must not offer the method.
170
+ requiresRenderer: true,
171
+ Implementation: Renderer => ({ type, stage, control, params }: AuthenticationRendererProps) => {
172
+ useEffect(() => {
173
+ if (control.stage === AuthenticationStage.Init) {
174
+ void control.requestAllowence()
175
+ }
176
+ }, [type])
177
+
178
+ if (Renderer == null) {
179
+ throw new SyntaxError(`Renderer is not defined for ${MY_APP_PASSKEY}`)
180
+ }
181
+
182
+ return <Renderer type={type} stage={stage} control={control} params={params} />
183
+ },
184
+ }
185
+
186
+ registerAuthPlugin(passkeyPlugin)
187
+ ```
188
+
189
+ A UI package then assigns `plugins[MY_APP_PASSKEY].Renderer`, and the renderer calls
190
+ `control.authenticate({ userId, credential })` once the person has answered the challenge.
191
+
40
192
  ## API
41
193
 
42
- ### `useSelfAuth(): Auth | null`
194
+ ### `@owlmeans/client-auth`
195
+
196
+ | Symbol | Kind | Purpose |
197
+ |---|---|---|
198
+ | `makeAuthService(alias?)` | function | The client `AuthService` — `authenticate`, `update`, `authenticated`, `user`, `store` |
199
+ | `appendAuthService(ctx, alias?)` | function | Register it and `authMiddleware`; expose `context.auth()` |
200
+ | `entrypoints` | const | `[bind(authProtocols.dispatcherAuthenticate)]` |
201
+ | `bindExternalAuthentication(service)` | function | Bind `authProtocols.flowEnter` as a URL-only screen on the given service |
202
+ | `useSelfAuth(force = true)` | hook | Resolves to `boolean`; navigates to `DISPATCHER` when unauthenticated and `force` is set |
203
+ | `useWs(entrypoint, request?, options?)` | hook | `@owlmeans/client-socket`'s `useWs` with the token in `AUTH_QUERY`, refreshed before every reconnect unless the caller supplied its own |
204
+ | `DispatcherHOC` | HOC | The return-leg wrapper — see *Concepts* |
205
+ | `DispatcherProps`, `TDispatcherHOC`, `DispatcherRenderer`, `DispatcherRendererProps` | type | Dispatcher contract |
206
+ | `DEFAULT_ALIAS` | const | `'auth'` — the service alias and the client guard alias |
207
+ | `AUTH_RESOURCE`, `USER_ID` | const | `'auth'` resource and `'user'` record id holding the token |
208
+ | `DEFAULT_ENTITY` | const | `'owlmeans'` |
209
+ | `AuthServiceAppend`, `ClientAuthRecord`, `ClientAuthResource` | type | `context.auth()` and the stored record |
210
+
211
+ ### `@owlmeans/client-auth/manager`
212
+
213
+ Importing it registers `basic-ed25519`, `re-captcha` and `wallet-consumer`, plus
214
+ `pluginMethodSource`, by side effect.
215
+
216
+ | Symbol | Kind | Purpose |
217
+ |---|---|---|
218
+ | `plugins`, `registerAuthPlugin`, `getAuthPlugin`, `listAuthPlugins` | registry | The module-global authentication-plugin registry |
219
+ | `AuthenticationHOC(Renderer?, type?)` | HOC | The authentication screen hosting a plugin |
220
+ | `AuthenticationProps`, `TAuthenticationHOC` | type | Screen props (`type?`, `callback?`, `source?`) |
221
+ | `makeControl(context, callback?)` | function | The control a plugin drives: `requestAllowence`, `authenticate`, `persist` / `restore` / `hasPersistentState` / `cleanUpState`, `setError`, `flow` |
222
+ | `AuthenticationControl`, `AuthenticationControlState` | type | Control shape and the state persisted across a provider redirect |
223
+ | `AuthenticationRenderer`, `AuthenticationRendererProps`, `ClientAuthType`, `ClientAuthenticationMethod`, `AuthenticationCallback` | type | Rendering contract |
224
+ | `TunnelConsumer`, `TunnelAuthenticationProps`, `TunnelAuthCallback` | component, type | Wallet-tunnel consumer screen |
225
+ | `AuthenCredError` | class | The entered credential cannot be used |
226
+ | `CONTROL_STATE_ID` | const | Resource id of the persisted control state |
227
+
228
+ ### `@owlmeans/client-auth/manager/entrypoints`
43
229
 
44
- Returns the current `Auth` object from the context, or `null` if not authenticated.
230
+ | Symbol | Kind | Purpose |
231
+ |---|---|---|
232
+ | `entrypoints` | const | The authentication manager app's bindings: `authen`, `init`, `authenticate`, `rely`, `client`, `login`, the `loginDefault` / `loginTyped` screens and the dispatcher |
45
233
 
46
- ### `setupExternalAuthentication(ctx, opts?)`
234
+ ### `@owlmeans/client-auth/manager/plugins`
47
235
 
48
- Configures the context to redirect to an external identity provider for authentication.
236
+ The plugin-authoring surface, with no registration side effect.
49
237
 
50
- ### `entrypoints`
238
+ | Symbol | Kind | Purpose |
239
+ |---|---|---|
240
+ | `AuthenticationPlugin` | type | `type`, `Implementation`, `Renderer?`, `requiresRenderer?`, `method?`, `authenticate` / `beforeAuthenticate` / `afterAuthenticate` |
241
+ | `PluginImplemnetation` (sic) | type | `(Renderer?) => FC<AuthenticationRendererProps>` |
242
+ | `AuthMethodMeta` | type | `id`, `label`, `i18nKey`, `icon`, `order`, `emphasis`, `restricted`, `hidden`, `available(ctx)` |
243
+ | `plugins`, `registerAuthPlugin`, `getAuthPlugin`, `listAuthPlugins` | registry | Same registry as `./manager` |
244
+ | `pluginMethodSource` | const | The `LoginMethodSource` that offers registered plugins |
245
+ | `createWalletFacade`, `PinSchema`, `PinForm`, `TunnelAuthenticationRenderer`, `TunnelAuthenticationRendererProps` | function, const, type | Wallet-tunnel helpers |
246
+ | `ed25519BasicUIPlugin`, `reCaptchaPlugin`, `tunnelConsumerUIPlugin` | const | Shipped plugin objects |
51
247
 
52
- Pre-built protocol bindings for the auth flow (mirrors `@owlmeans/auth-common`'s declarations with
53
- client route models). New application code should resolve its shared protocol with
54
- `context.entrypoint(protocol)` rather than supplying a caller-side type.
248
+ ### `@owlmeans/client-auth/login`
55
249
 
56
- ### `DEFAULT_ALIAS`
250
+ | Symbol | Kind | Purpose |
251
+ |---|---|---|
252
+ | `appendLogin(ctx)` | function | Register the host; expose `context.login()` |
253
+ | `makeLoginService(alias?)`, `ensureLoginService(ctx)` | function | The lazy login service, and the idempotent getter a plugin package calls first |
254
+ | `LoginService`, `LoginServiceAppend`, `LoginContext` | type | `registerPlugin`, `registerPrecondition`, `registerMethodSource`, `registerScreen`, `screen`, `env`, and the `enter` / `begin` / `authorize` / `complete` / `resume` / `logout` / `logoutComplete` / `adopt` / `revoke` facade |
255
+ | `LoginPlugin`, `LoginEnv`, `LoginRequest`, `LogoutRequest`, `LoginPrecondition` | type | Plugin contract |
256
+ | `LoginOutcome`, `LoginIntent` | enum | Stage results; login or logout surrogate |
257
+ | `useLogin(target?)` | hook | `[dispatcherPath, onLogIn]` |
258
+ | `useLogout(target?)` | hook | `onLogOut` |
259
+ | `registerMethodSource`, `listMethodSources`, `resolveLoginMethods(ctx, cfg?, extra?)`, `primaryLoginMethod(methods)` | function | Global method sources and resolution |
260
+ | `LoginMethod`, `LoginMethodSource`, `LoginMethodContext` | type | Method contract |
261
+ | `resolveTerms(cfg?)`, `termsAccepted(resolved)`, `acceptTerms(resolved, accepted)`, `ResolvedTerms` | function, type | Terms confirmation, stored in `localStorage` against a version derived from the URLs |
262
+ | `resolveCredit(cfg?, brand?, service?)`, `ResolvedCredit` | function, type | The credit and copyright line |
263
+ | `FallbackLoginScreen`, `LoginScreenProps`, `LoginScreenComponent` | component, type | The plain screen used when no UI family registered one |
264
+ | `surrogatePath(ctx, target)`, `SurrogateTarget` | function, type | Where a surrogate window opens; `null` on an entrypoint list without the surrogate route |
265
+ | `resumeAction(outcome)`, `ResumeAction`, `loginAttemptError(outcome)` | function, enum | The shared readings of a `resume` outcome and of a finished attempt |
266
+ | `enterOidcAuthorization(model)` | function | Move a flow to the step that can authorize; idempotent |
267
+ | `adoptToken(ctx, token)`, `revokeToken(ctx)` | function | The single adoption and de-adoption paths |
268
+ | `isEmbedded`, `isSurrogate`, `markSurrogate`, `clearSurrogate`, `defaultLoginEnv` | function | Environment probes behind `LoginEnv` |
269
+ | `LOGIN_SERVICE`, `DEFAULT_ALIAS`, `DEFAULT_LOGIN_PRIORITY`, `DEFAULT_METHOD_ORDER`, `LOGIN_SURROGATE_NAME`, `LOGIN_TOKEN_MESSAGE`, `LOGIN_LOGOUT_MESSAGE`, `LOGIN_SURROGATE_MARKER`, `LOGIN_SURROGATE_FEATURES`, `LOGIN_WATCH_INTERVAL`, `LOGIN_INTENT_QUERY`, `LOGIN_NEXT_QUERY`, `LOGIN_METHOD_QUERY`, `LOGIN_TERMS_STORAGE` | const | Service alias, ordering defaults and cross-document wire values |
57
270
 
58
- Auth service alias: `'auth'`.
271
+ Importing `./login` also registers the `login` strings of the `auth` library namespace in all
272
+ seven supported languages.
59
273
 
60
- ## Product-Viable Integration Notes
274
+ ## Common pitfalls
61
275
 
62
- - The manager web app imports `DEFAULT_ALIAS` from this package as the client-side guard alias.
63
- - `@owlmeans/web-oidc-rp/auth/plugins` is imported for side effects to register the `OIDC_CLIENT_AUTH` and `GOOGLE_CLIENT_AUTH` plugins.
64
- - Redirect plugins persist auth control state before leaving the app and restore it before submitting provider query params as `AuthCredentials`.
65
- - After login, the browser stores a normal OwlMeans bearer token; product authorization is enforced by server gates and handler checks.
276
+ - **Keep sign-in handlers synchronous.** `useLogin` and `useLogout` handlers await nothing before
277
+ delegating. Wrapping them in an `async` handler that awaits first makes the popup blocker eat the
278
+ surrogate window. The same rule binds a plugin's `begin` / `logout`, a method's `start` and every
279
+ precondition.
280
+ - **Never start login from an effect.** Without a user gesture the window is blocked. Render a
281
+ control and let the person click.
282
+ - **Adopt and drop tokens only through the auth service or `adoptToken` / `revokeToken`.**
283
+ Hand-written access to `AUTH_RESOURCE` drifts from the envelope decoding beside it.
284
+ - **Import names from the right subpath.** The plugin contract (`AuthenticationPlugin`,
285
+ `AuthMethodMeta`, `pluginMethodSource`, tunnel helpers) resolves only through
286
+ `./manager/plugins`. Rendering types and the registry resolve through `./manager`. Importing
287
+ `./login` registers no authentication plugin.
288
+ - **Gate operator methods with `method.restricted`,** so the configuration has to name them. Gate
289
+ dev-only methods on `cfg.debug.supervisor`, never `cfg.debug.all`.
290
+ - **Declare `requiresRenderer`** on a plugin whose `Implementation` cannot render without a UI
291
+ package's `Renderer`. Otherwise the screen offers a button that crashes the page it opens.
292
+ - **Call `enterOidcAuthorization(model)` before every `authenticate`** in an OIDC flow, rather than
293
+ re-deriving the transition.
294
+ - **Authorization stays server-side.** The browser ends up holding an ordinary OwlMeans bearer token
295
+ whichever provider issued it. Product checks live in entrypoint gates and handlers, never in
296
+ client-only state.
297
+ - **The organization on the wire is its `entitySlug`.** Read it with `entitySlugOf` from
298
+ `@owlmeans/auth`; the stable `entityId` never reaches the browser.
299
+ - **Overrides of the `login` strings cover all seven languages** (`en`, `pl`, `ru`, `be`, `uk`,
300
+ `es`, `de`).
66
301
 
67
- ## Related Packages
302
+ ## Related packages
68
303
 
69
- - [`@owlmeans/auth`](../auth) — `Auth` type returned by `useSelfAuth`
70
- - [`@owlmeans/auth-common`](../auth-common) — auth entrypoint route definitions
71
- - [`@owlmeans/server-auth`](../server-auth) — server-side counterpart
304
+ - [`@owlmeans/auth`](../auth) — `Auth`, aliases, `entitySlugOf`, auth errors
305
+ - [`@owlmeans/auth-common`](../auth-common) — `authProtocols`, `authMiddleware`, guard aliases
306
+ - [`@owlmeans/web-client`](../web-client) — appends the auth service and login host; ships the dispatcher and login plugins
307
+ - [`@owlmeans/web-panel`](../web-panel) — the shadcn sign-in screen (`appendLoginScreen`)
308
+ - [`@owlmeans/client-panel`](../client-panel) — headless login-method and terms models
309
+ - [`@owlmeans/web-oidc-rp`](../web-oidc-rp) — OIDC relying party and its method source
310
+ - [`@owlmeans/web-auth`](../web-auth) — supervisor (PK) login plugin
311
+ - [`@owlmeans/client-socket`](../client-socket) — the socket hook `useWs` wraps
312
+ - [`@owlmeans/server-auth`](../server-auth) — the server-side counterpart
72
313
 
73
314
  <!-- owlmeans:agent-guidance:start -->
74
315
  ## Agent guidance
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@owlmeans/client-auth",
4
- "version": "0.1.18-rc.28",
5
- "generatedAt": "2026-09-12T14:18:54.779Z",
4
+ "version": "0.1.18-rc.29",
5
+ "generatedAt": "2026-09-14T19:17:35.187Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/client-auth
9
9
 
10
10
  **Layer:** Client
11
- **Install:** `"@owlmeans/client-auth": "^0.1.18-rc.28"` in `dependencies`
11
+ **Install:** `"@owlmeans/client-auth": "^0.1.18-rc.29"` in `dependencies`
12
12
 
13
13
  Five subpaths, five jobs:
14
14
 
@@ -44,7 +44,7 @@ conflate them.
44
44
  | `DEFAULT_ENTITY` | `'owlmeans'` |
45
45
  | `DispatcherHOC` | The return-leg HOC. It wraps a `DispatcherRenderer`, hands it `provideToken(token, query)` and `navigate()`, adopts the supplied token through the auth service, and strips `AUTH_QUERY` before navigating on. Reading the return-leg query is the renderer's job — `@owlmeans/web-client` reads `AUTH_QUERY`, `@owlmeans/web-oidc-rp` also reads `OIDC_ERROR_QUERY` and forwards the remaining params |
46
46
  | `DispatcherProps`, `TDispatcherHOC`, `DispatcherRenderer`, `DispatcherRendererProps` | Dispatcher types |
47
- | `useWs(entrypoint, request?)` | A socket hook that attaches the current token as the `AUTH_QUERY` param |
47
+ | `useWs(entrypoint, request?, options?)` | A socket hook that attaches the current token as the `AUTH_QUERY` param and refreshes it on every reconnect attempt (via `WsOptions.beforeConnect`), unless the request already carried its own token — in which case that stays untouched across reconnects too. `options` passes straight through to `@owlmeans/client-socket`'s `useWs`, so `{ reconnect: false }` still opts a stateful one-shot handshake out of retries (see `manager/plugins/tunnel-consumer.tsx`) |
48
48
  | `useSelfAuth(force?)` | Whether this context is authenticated; navigates to `DISPATCHER` when it is not and `force` |
49
49
  | `AuthServiceAppend`, `ClientAuthRecord`, `ClientAuthResource` | Types |
50
50
 
package/build/helper.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { ClientEntrypoint } from '@owlmeans/client-entrypoint';
2
+ import type { WsOptions } from '@owlmeans/client-socket';
2
3
  import type { AbstractRequest } from '@owlmeans/entrypoint';
3
- export declare const useWs: (module: string | ClientEntrypoint<any>, _request?: Partial<AbstractRequest<any>>) => import("@owlmeans/socket").Connection | null;
4
+ export declare const useWs: (module: string | ClientEntrypoint<any>, _request?: Partial<AbstractRequest<any>>, options?: WsOptions) => import("@owlmeans/socket").Connection | null;
4
5
  export declare const useSelfAuth: (force?: boolean) => boolean;
5
6
  //# sourceMappingURL=helper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAGnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAS3D,eAAO,MAAM,KAAK,WACR,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,iDA2BjF,CAAA;AAED,eAAO,MAAM,WAAW,WAAW,OAAO,YAoBzC,CAAA"}
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAGnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAS3D,eAAO,MAAM,KAAK,WACR,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,YAAY,SAAS,iDAiDtG,CAAA;AAED,eAAO,MAAM,WAAW,WAAW,OAAO,YAoBzC,CAAA"}
package/build/helper.js CHANGED
@@ -6,9 +6,12 @@ import { AUTH_QUERY, DISPATCHER } from '@owlmeans/auth';
6
6
  // import { useFlow } from '@owlmeans/web-flow'
7
7
  // import { DEFAULT_ENTITY } from './consts.js'
8
8
  // import { OidcAuthStep } from '@owlmeans/flow'
9
- export const useWs = (module, _request) => {
9
+ export const useWs = (module, _request, options) => {
10
10
  const ctx = useContext();
11
11
  const mod = useMemo(() => typeof module === 'string' ? ctx.entrypoint(module) : module, [module]);
12
+ // Captured before the token is filled in below, so a caller who supplied their own token
13
+ // keeps full control of it across a reconnect too — `beforeConnect` only refreshes ours.
14
+ const callerSuppliedToken = _request?.query?.[AUTH_QUERY] != null;
12
15
  const request = useMemo(() => {
13
16
  if (_request == null) {
14
17
  _request = provideRequest(mod.alias, mod.path());
@@ -26,7 +29,25 @@ export const useWs = (module, _request) => {
26
29
  }
27
30
  return _request;
28
31
  }, [_request]);
29
- return useWebSocket(module, request);
32
+ const wsOptions = useMemo(() => ({
33
+ ...options,
34
+ beforeConnect: async (req) => {
35
+ // A reconnect can land minutes after the socket first opened — refresh the bearer token
36
+ // on every attempt rather than trust the one `request` was built with, or a token rotated
37
+ // in between reopens the socket with a stale one the guard then rejects.
38
+ if (!callerSuppliedToken) {
39
+ try {
40
+ req.query ??= {};
41
+ req.query[AUTH_QUERY] = ctx.auth().token;
42
+ }
43
+ catch (e) {
44
+ console.error(e);
45
+ }
46
+ }
47
+ await options?.beforeConnect?.(req);
48
+ }
49
+ }), [options, callerSuppliedToken]);
50
+ return useWebSocket(module, request, wsOptions);
30
51
  };
31
52
  export const useSelfAuth = (force = true /*, entity: string = DEFAULT_ENTITY*/) => {
32
53
  const context = useContext();
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAG/D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACvD,+CAA+C;AAC/C,+CAA+C;AAC/C,gDAAgD;AAEhD,MAAM,CAAC,MAAM,KAAK,GAAG,CACnB,MAAsC,EAAE,QAAwC,EAChF,EAAE;IACF,MAAM,GAAG,GAAG,UAAU,EAAkD,CAAA;IAExE,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAmB,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAC/F,CAAA;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE;QAC3B,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;QAClD,CAAC;QACD,IAAI,CAAC;YACH,IAAI,QAAQ,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC1C,IAAI,QAAQ,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;oBAC3B,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAA;gBACrB,CAAC;gBACD,QAAQ,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAA;YAC/C,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAClB,CAAC;QAED,OAAO,QAAQ,CAAA;IACjB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,OAAO,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AACtC,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,GAAY,IAAI,CAAA,qCAAqC,EAAE,EAAE;IACxF,MAAM,OAAO,GAAG,UAAU,EAAkD,CAAA;IAC5E,sEAAsE;IACtE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACzD,MAAM,GAAG,GAAG,WAAW,EAAE,CAAA;IAEzB,SAAS,CAAC,GAAG,EAAE;QACb,2BAA2B;QAC3B,OAAO,CAAC,IAAI,EAAE,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,KAAK,EAAC,IAAI,EAAC,EAAE;YAC/C,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;gBACnB,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,CAAA;gBAClB,6BAA6B;gBAC7B,qEAAqE;YACvE,CAAC;YAED,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC1B,CAAC,CAAC,CAAA;IACJ,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":"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"}
@@ -17,6 +17,16 @@ export declare const LOGIN_SURROGATE_NAME = "owlmeans-oidc-login";
17
17
  export declare const LOGIN_TOKEN_MESSAGE = "owlmeans:oidc:popup-token";
18
18
  export declare const LOGIN_LOGOUT_MESSAGE = "owlmeans:oidc:popup-logout";
19
19
  export declare const LOGIN_SURROGATE_MARKER = "_owlmeans-oidc-popup";
20
+ export declare const LOGIN_SURROGATE_WIDTH = 520;
21
+ export declare const LOGIN_SURROGATE_HEIGHT = 760;
22
+ /**
23
+ * @deprecated Never centered the window — it carried no `left`/`top`, so the surrogate always
24
+ * opened wherever the browser's own default popup placement put it. Superseded by
25
+ * `@owlmeans/web-client`'s `centeredPopupFeatures(LOGIN_SURROGATE_WIDTH, LOGIN_SURROGATE_HEIGHT)`,
26
+ * computed fresh per call since centering depends on where the browser window currently sits.
27
+ * Kept, unchanged, for the same reason as the rest of this block: an already-generated app may
28
+ * carry a copy of code that still imports it.
29
+ */
20
30
  export declare const LOGIN_SURROGATE_FEATURES = "popup=yes,width=520,height=760";
21
31
  /** How often a surrogate window is checked for having been closed by the user. */
22
32
  export declare const LOGIN_WATCH_INTERVAL = 500;
@@ -1 +1 @@
1
- {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/login/consts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C,eAAO,MAAM,aAAa,kBAAgB,CAAA;AAE1C,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC,kDAAkD;AAClD,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAA;AAEzD,eAAO,MAAM,mBAAmB,8BAA8B,CAAA;AAE9D,eAAO,MAAM,oBAAoB,+BAA+B,CAAA;AAEhE,eAAO,MAAM,sBAAsB,yBAAyB,CAAA;AAE5D,eAAO,MAAM,wBAAwB,mCAAmC,CAAA;AAExE,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,0BAA0B,CAAA"}
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../../src/login/consts.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C,eAAO,MAAM,aAAa,kBAAgB,CAAA;AAE1C,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,IAAI,CAAA;AAEvC,kDAAkD;AAClD,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,wBAAwB,CAAA;AAEzD,eAAO,MAAM,mBAAmB,8BAA8B,CAAA;AAE9D,eAAO,MAAM,oBAAoB,+BAA+B,CAAA;AAEhE,eAAO,MAAM,sBAAsB,yBAAyB,CAAA;AAE5D,eAAO,MAAM,qBAAqB,MAAM,CAAA;AAExC,eAAO,MAAM,sBAAsB,MAAM,CAAA;AAEzC;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,mCACwC,CAAA;AAE7E,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,MAAM,CAAA;AAEvC,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,SAAS,CAAA;AAEtC;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,WAAW,CAAA;AAE1C,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,0BAA0B,CAAA"}
@@ -17,7 +17,17 @@ export const LOGIN_SURROGATE_NAME = 'owlmeans-oidc-login';
17
17
  export const LOGIN_TOKEN_MESSAGE = 'owlmeans:oidc:popup-token';
18
18
  export const LOGIN_LOGOUT_MESSAGE = 'owlmeans:oidc:popup-logout';
19
19
  export const LOGIN_SURROGATE_MARKER = '_owlmeans-oidc-popup';
20
- export const LOGIN_SURROGATE_FEATURES = 'popup=yes,width=520,height=760';
20
+ export const LOGIN_SURROGATE_WIDTH = 520;
21
+ export const LOGIN_SURROGATE_HEIGHT = 760;
22
+ /**
23
+ * @deprecated Never centered the window — it carried no `left`/`top`, so the surrogate always
24
+ * opened wherever the browser's own default popup placement put it. Superseded by
25
+ * `@owlmeans/web-client`'s `centeredPopupFeatures(LOGIN_SURROGATE_WIDTH, LOGIN_SURROGATE_HEIGHT)`,
26
+ * computed fresh per call since centering depends on where the browser window currently sits.
27
+ * Kept, unchanged, for the same reason as the rest of this block: an already-generated app may
28
+ * carry a copy of code that still imports it.
29
+ */
30
+ export const LOGIN_SURROGATE_FEATURES = `popup=yes,width=${LOGIN_SURROGATE_WIDTH},height=${LOGIN_SURROGATE_HEIGHT}`;
21
31
  /** How often a surrogate window is checked for having been closed by the user. */
22
32
  export const LOGIN_WATCH_INTERVAL = 500;
23
33
  /** Carries WHY the surrogate window was opened across the window boundary. */
@@ -1 +1 @@
1
- {"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/login/consts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAA;AAE1C,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEvC,kDAAkD;AAClD,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAA;AAEvC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAA;AAEzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAA;AAE9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,4BAA4B,CAAA;AAEhE,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,gCAAgC,CAAA;AAExE,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAA;AAEvC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAA;AAE1C;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAA;AAE1C,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAA"}
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../../src/login/consts.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAE5C,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAA;AAE1C,sEAAsE;AACtE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAA;AAEvC,kDAAkD;AAClD,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAA;AAEvC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,qBAAqB,CAAA;AAEzD,MAAM,CAAC,MAAM,mBAAmB,GAAG,2BAA2B,CAAA;AAE9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,4BAA4B,CAAA;AAEhE,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAA;AAE5D,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAA;AAExC,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAA;AAEzC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,mBAAmB,qBAAqB,WAAW,sBAAsB,EAAE,CAAA;AAE7E,kFAAkF;AAClF,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,CAAA;AAEvC,8EAA8E;AAC9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAA;AAE1C;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAA;AAE1C,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAA"}
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "Уваход не завершаны. Паспрабуйце яшчэ раз.",
33
- "blocked": "Акно ўваходу заблакавана. Дазвольце ўсплывальныя вокны для гэтага сайта і паспрабуйце зноў."
33
+ "blocked": "Акно ўваходу заблакавана. Націсніце значок заблакаванага ўсплывальнага акна ў адрасным радку браўзера, каб адкрыць яго."
34
34
  },
35
35
  "orphaned": "Уваход выкананы. Можаце закрыць гэтае акно і вярнуцца ў праграму."
36
36
  }
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "Die Anmeldung wurde nicht abgeschlossen. Bitte versuchen Sie es erneut.",
33
- "blocked": "Das Anmeldefenster wurde blockiert. Erlauben Sie Pop-ups für diese Website und versuchen Sie es erneut."
33
+ "blocked": "Das Anmeldefenster wurde blockiert. Klicken Sie auf das Symbol für blockierte Pop-ups in der Adressleiste Ihres Browsers, um es zu öffnen."
34
34
  },
35
35
  "orphaned": "Angemeldet. Sie können dieses Fenster schließen und in der Anwendung fortfahren."
36
36
  }
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "Sign-in did not complete. Please try again.",
33
- "blocked": "The sign-in window was blocked. Allow pop-ups for this site and try again."
33
+ "blocked": "The sign-in window was blocked. Click the blocked pop-up icon in your browser's address bar to open it."
34
34
  },
35
35
  "orphaned": "Signed in. You can close this window and continue in the application."
36
36
  }
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "El inicio de sesión no se completó. Inténtalo de nuevo.",
33
- "blocked": "Se bloqueó la ventana de inicio de sesión. Permite las ventanas emergentes para este sitio e inténtalo de nuevo."
33
+ "blocked": "Se bloqueó la ventana de inicio de sesión. Haz clic en el icono de ventana emergente bloqueada en la barra de direcciones del navegador para abrirla."
34
34
  },
35
35
  "orphaned": "Sesión iniciada. Puedes cerrar esta ventana y continuar en la aplicación."
36
36
  }
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "Logowanie nie zostało ukończone. Spróbuj ponownie.",
33
- "blocked": "Okno logowania zostało zablokowane. Zezwól na wyskakujące okienka dla tej witryny i spróbuj ponownie."
33
+ "blocked": "Okno logowania zostało zablokowane. Kliknij ikonę zablokowanego okienka w pasku adresu przeglądarki, aby je otworzyć."
34
34
  },
35
35
  "orphaned": "Zalogowano. Możesz zamknąć to okno i kontynuować w aplikacji."
36
36
  }
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "Вход не завершён. Попробуйте ещё раз.",
33
- "blocked": "Окно входа заблокировано. Разрешите всплывающие окна для этого сайта и попробуйте снова."
33
+ "blocked": "Окно входа заблокировано. Нажмите на значок заблокированного всплывающего окна в адресной строке браузера, чтобы открыть его."
34
34
  },
35
35
  "orphaned": "Вход выполнен. Можете закрыть это окно и вернуться в приложение."
36
36
  }
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "error": {
32
32
  "failed": "Вхід не завершено. Спробуйте ще раз.",
33
- "blocked": "Вікно входу заблоковано. Дозвольте спливаючі вікна для цього сайту та спробуйте знову."
33
+ "blocked": "Вікно входу заблоковано. Натисніть значок заблокованого спливаючого вікна в адресному рядку браузера, щоб відкрити його."
34
34
  },
35
35
  "orphaned": "Вхід виконано. Можете закрити це вікно й повернутися до застосунку."
36
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,YAAa,YAAY,GAAG,IAAI,KAAG,MAAM,GAAG,IAYzE,CAAA;AAED,sEAAsE;AACtE,oBAAY,YAAY;IACtB,kFAAkF;IAClF,IAAI,SAAS;IACb,oFAAoF;IACpF,MAAM,WAAW;IACjB,sEAAsE;IACtE,QAAQ,aAAa;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,YAAa,YAAY,KAAG,YAYpD,CAAA"}
1
+ {"version":3,"file":"resume.d.ts","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,YAAa,YAAY,GAAG,IAAI,KAAG,MAAM,GAAG,IAazE,CAAA;AAED,sEAAsE;AACtE,oBAAY,YAAY;IACtB,kFAAkF;IAClF,IAAI,SAAS;IACb,oFAAoF;IACpF,MAAM,WAAW;IACjB,sEAAsE;IACtE,QAAQ,aAAa;CACtB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,YAAa,YAAY,KAAG,YAapD,CAAA"}
@@ -11,6 +11,7 @@ import { LoginOutcome } from './types.js';
11
11
  export const loginAttemptError = (outcome) => {
12
12
  switch (outcome) {
13
13
  case LoginOutcome.Gesture:
14
+ case LoginOutcome.Blocked:
14
15
  // The window never opened. That is the popup blocker, and it has its own copy.
15
16
  return 'login.error.blocked';
16
17
  case LoginOutcome.Failed:
@@ -47,6 +48,7 @@ export const resumeAction = (outcome) => {
47
48
  case LoginOutcome.Orphaned:
48
49
  case LoginOutcome.Failed:
49
50
  case LoginOutcome.Gesture:
51
+ case LoginOutcome.Blocked:
50
52
  return ResumeAction.Render;
51
53
  default:
52
54
  return ResumeAction.Navigate;
@@ -1 +1 @@
1
- {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAA4B,EAAiB,EAAE;IAC/E,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO;YACvB,+EAA+E;YAC/E,OAAO,qBAAqB,CAAA;QAC9B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,MAAM;YACtB,OAAO,oBAAoB,CAAA;QAC7B;YACE,yFAAyF;YACzF,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC,CAAA;AAED,sEAAsE;AACtE,MAAM,CAAN,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,kFAAkF;IAClF,6BAAa,CAAA;IACb,oFAAoF;IACpF,iCAAiB,CAAA;IACjB,sEAAsE;IACtE,qCAAqB,CAAA;AACvB,CAAC,EAPW,YAAY,KAAZ,YAAY,QAOvB;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAgB,EAAE;IAClE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO,CAAC;QAC1B,KAAK,YAAY,CAAC,UAAU;YAC1B,OAAO,YAAY,CAAC,IAAI,CAAA;QAC1B,KAAK,YAAY,CAAC,QAAQ,CAAC;QAC3B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,OAAO;YACvB,OAAO,YAAY,CAAC,MAAM,CAAA;QAC5B;YACE,OAAO,YAAY,CAAC,QAAQ,CAAA;IAChC,CAAC;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"resume.js","sourceRoot":"","sources":["../../src/login/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEzC;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,OAA4B,EAAiB,EAAE;IAC/E,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO,CAAC;QAC1B,KAAK,YAAY,CAAC,OAAO;YACvB,+EAA+E;YAC/E,OAAO,qBAAqB,CAAA;QAC9B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,MAAM;YACtB,OAAO,oBAAoB,CAAA;QAC7B;YACE,yFAAyF;YACzF,OAAO,IAAI,CAAA;IACf,CAAC;AACH,CAAC,CAAA;AAED,sEAAsE;AACtE,MAAM,CAAN,IAAY,YAOX;AAPD,WAAY,YAAY;IACtB,kFAAkF;IAClF,6BAAa,CAAA;IACb,oFAAoF;IACpF,iCAAiB,CAAA;IACjB,sEAAsE;IACtE,qCAAqB,CAAA;AACvB,CAAC,EAPW,YAAY,KAAZ,YAAY,QAOvB;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAqB,EAAgB,EAAE;IAClE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,YAAY,CAAC,OAAO,CAAC;QAC1B,KAAK,YAAY,CAAC,UAAU;YAC1B,OAAO,YAAY,CAAC,IAAI,CAAA;QAC1B,KAAK,YAAY,CAAC,QAAQ,CAAC;QAC3B,KAAK,YAAY,CAAC,MAAM,CAAC;QACzB,KAAK,YAAY,CAAC,OAAO,CAAC;QAC1B,KAAK,YAAY,CAAC,OAAO;YACvB,OAAO,YAAY,CAAC,MAAM,CAAA;QAC5B;YACE,OAAO,YAAY,CAAC,QAAQ,CAAA;IAChC,CAAC;AACH,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/login/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAMlE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,KAAK,EAEV,YAAY,EAAE,kBAAkB,EACjC,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,WAAW,MAAM,KAAmB,YA0HhE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAS,YAAY,CAAC,GAAG,CAAC,KAAG,YAQ3D,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,OACrE,CAAC,KACL,CAAC,GAAG,kBAMN,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/login/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAMlE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,KAAK,EAEY,YAAY,EAAE,kBAAkB,EACvD,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gBAAgB,WAAW,MAAM,KAAmB,YAwIhE,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAS,YAAY,CAAC,GAAG,CAAC,KAAG,YAQ3D,CAAA;AAED,4DAA4D;AAC5D,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,WAAW,EAAE,CAAC,SAAS,YAAY,CAAC,CAAC,CAAC,OACrE,CAAC,KACL,CAAC,GAAG,kBAMN,CAAA;AAED,OAAO,EAAE,YAAY,EAAE,CAAA"}