@owlmeans/client-auth 0.1.18 → 0.1.19
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 +2 -2
- package/agent-meta/manifest.json +4 -2
- package/agent-meta/skills/client-auth/SKILL.md +36 -3
- package/agent-meta/skills/client-auth/parts/login.md +2 -1
- package/build/components/dispatcher/component.d.ts.map +1 -1
- package/build/components/dispatcher/component.js +44 -5
- package/build/components/dispatcher/component.js.map +1 -1
- package/build/entrypoints.d.ts +2 -4
- package/build/entrypoints.d.ts.map +1 -1
- package/build/login/consts.local.d.ts +4 -0
- package/build/login/consts.local.d.ts.map +1 -1
- package/build/login/consts.local.js +8 -0
- package/build/login/consts.local.js.map +1 -1
- package/build/login/failure/consts.d.ts +17 -0
- package/build/login/failure/consts.d.ts.map +1 -0
- package/build/login/failure/consts.js +18 -0
- package/build/login/failure/consts.js.map +1 -0
- package/build/login/failure/consts.local.d.ts +17 -0
- package/build/login/failure/consts.local.d.ts.map +1 -0
- package/build/login/failure/consts.local.js +30 -0
- package/build/login/failure/consts.local.js.map +1 -0
- package/build/login/failure/types.d.ts +57 -0
- package/build/login/failure/types.d.ts.map +1 -0
- package/build/login/failure/types.js +2 -0
- package/build/login/failure/types.js.map +1 -0
- package/build/login/failure-view.d.ts +14 -0
- package/build/login/failure-view.d.ts.map +1 -0
- package/build/login/failure-view.js +19 -0
- package/build/login/failure-view.js.map +1 -0
- package/build/login/failure.d.ts +4 -0
- package/build/login/failure.d.ts.map +1 -0
- package/build/login/failure.js +50 -0
- package/build/login/failure.js.map +1 -0
- package/build/login/i18n/be.json +7 -1
- package/build/login/i18n/de.json +7 -1
- package/build/login/i18n/en.json +7 -1
- package/build/login/i18n/es.json +7 -1
- package/build/login/i18n/fr.json +7 -1
- package/build/login/i18n/pl.json +7 -1
- package/build/login/i18n/ru.json +7 -1
- package/build/login/i18n/uk.json +7 -1
- package/build/login/index.d.ts +5 -0
- package/build/login/index.d.ts.map +1 -1
- package/build/login/index.js +4 -0
- package/build/login/index.js.map +1 -1
- package/build/login/screen.d.ts.map +1 -1
- package/build/login/screen.js +9 -2
- package/build/login/screen.js.map +1 -1
- package/build/login/translate.d.ts +15 -0
- package/build/login/translate.d.ts.map +1 -0
- package/build/login/translate.js +26 -0
- package/build/login/translate.js.map +1 -0
- package/build/login/types.d.ts +7 -0
- package/build/login/types.d.ts.map +1 -1
- package/build/manager/entrypoints.d.ts +1 -9
- package/build/manager/entrypoints.d.ts.map +1 -1
- package/package.json +28 -25
- package/src/components/dispatcher/component.tsx +48 -5
- package/src/login/consts.local.ts +10 -0
- package/src/login/failure/consts.local.ts +35 -0
- package/src/login/failure/consts.ts +16 -0
- package/src/login/failure/types.ts +60 -0
- package/src/login/failure-view.tsx +35 -0
- package/src/login/failure.ts +67 -0
- package/src/login/i18n/be.json +7 -1
- package/src/login/i18n/de.json +7 -1
- package/src/login/i18n/en.json +7 -1
- package/src/login/i18n/es.json +7 -1
- package/src/login/i18n/fr.json +7 -1
- package/src/login/i18n/pl.json +7 -1
- package/src/login/i18n/ru.json +7 -1
- package/src/login/i18n/uk.json +7 -1
- package/src/login/index.ts +5 -0
- package/src/login/screen.tsx +13 -1
- package/src/login/translate.ts +32 -0
- package/src/login/types.ts +8 -0
- package/src/manager/README.md +1 -1
- package/tests/failure.spec.tsx +176 -0
- package/build/manager/modules.d.ts +0 -2
- package/build/manager/modules.d.ts.map +0 -1
- package/build/manager/modules.js +0 -16
- package/build/manager/modules.js.map +0 -1
- package/build/modules.d.ts +0 -4
- package/build/modules.d.ts.map +0 -1
- package/build/modules.js +0 -9
- package/build/modules.js.map +0 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { CSSProperties } from 'react'
|
|
2
|
+
import type { LoginFailureKind } from './consts.js'
|
|
3
|
+
import type { LoginTranslate } from '../types.js'
|
|
4
|
+
|
|
5
|
+
/** A failed sign-in, read for the person who has to act on it. */
|
|
6
|
+
export interface LoginFailure {
|
|
7
|
+
kind: LoginFailureKind
|
|
8
|
+
/** A refusal of this account — retrying with it changes nothing. */
|
|
9
|
+
refused: boolean
|
|
10
|
+
/** The `auth` library key that phrases it (`login.error.<kind>`); an app overrides it there. */
|
|
11
|
+
key: string
|
|
12
|
+
/** The English sentence used when no translation resolves the key. */
|
|
13
|
+
fallback: string
|
|
14
|
+
/** The server's incident id, when it sent one — what a person reports for a failure. */
|
|
15
|
+
incidentId: string | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The three lines a failure view renders, already translated. */
|
|
19
|
+
export interface LoginFailurePhrase {
|
|
20
|
+
message: string
|
|
21
|
+
/** `Reference: <id>` for a failure that is not a refusal and carries an incident id. */
|
|
22
|
+
incident: string | null
|
|
23
|
+
/** The action's label: "Back to sign-in" for a refusal, "Try again" otherwise. */
|
|
24
|
+
action: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* How every OwlMeans sign-in surface reads a failed attempt — the Google callback, the supervisor
|
|
29
|
+
* form, the dispatcher's exchange and the sign-in screens — so they phrase it the same way.
|
|
30
|
+
*/
|
|
31
|
+
export interface LoginFailureHelper {
|
|
32
|
+
/**
|
|
33
|
+
* What a caught sign-in error means.
|
|
34
|
+
*
|
|
35
|
+
* A visible refusal code comes first (`account:disabled`, `profile:disabled` — a development body
|
|
36
|
+
* rebuilt into its class, or a message that names it); then a refusal without one: an
|
|
37
|
+
* `AuthRefused` of any module copy, or the production answer `apiStatusHelper.isAccessDenied`
|
|
38
|
+
* recognises (403 with `X-OwlMeans-Denial: access-denied`). Anything else — a 403 without the
|
|
39
|
+
* marker included, since plan and entitlement refusals use that status too — is `Failed`.
|
|
40
|
+
*/
|
|
41
|
+
failureOf: (error: unknown) => LoginFailure
|
|
42
|
+
/** `failureOf(error).refused`. */
|
|
43
|
+
isRefusal: (error: unknown) => boolean
|
|
44
|
+
/** The failure's sentences through `translate` (the `auth` library keys), English without one. */
|
|
45
|
+
phrase: (failure: LoginFailure, translate?: LoginTranslate) => LoginFailurePhrase
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface LoginFailureViewProps {
|
|
49
|
+
failure: LoginFailure
|
|
50
|
+
/** `(key, defaultValue) => string` over the `auth` library — a prop, never an implicit i18n read. */
|
|
51
|
+
translate?: LoginTranslate
|
|
52
|
+
/**
|
|
53
|
+
* What the action button does — the way back to the sign-in choice for a refusal, the same
|
|
54
|
+
* attempt again otherwise. Omitted, no button is rendered.
|
|
55
|
+
*/
|
|
56
|
+
onAction?: () => void
|
|
57
|
+
/** Wrap the notice in the centred full-viewport page of the plain sign-in screen. */
|
|
58
|
+
page?: boolean
|
|
59
|
+
style?: CSSProperties
|
|
60
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { FC } from 'react'
|
|
2
|
+
import { loginFailureHelper } from './failure.js'
|
|
3
|
+
import { box, failureAction, page } from './consts.local.js'
|
|
4
|
+
import type { LoginFailureViewProps } from './failure/types.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The end state of a sign-in that did not complete: one phrased sentence, the incident reference of
|
|
8
|
+
* a failure, and the way on — back to the sign-in choice for a refusal, the same attempt again
|
|
9
|
+
* otherwise.
|
|
10
|
+
*
|
|
11
|
+
* Plain like `FallbackLoginScreen` — raw elements, inline styles, no class a consumer's stylesheet
|
|
12
|
+
* must scan for — so any OwlMeans surface can end on it, whatever UI family it belongs to. Hooks for
|
|
13
|
+
* tests and styling: `[data-login-failure="<kind>"]`, `[data-login-failure-message]`,
|
|
14
|
+
* `[data-login-failure-incident]`, `[data-login-failure-action]`.
|
|
15
|
+
*/
|
|
16
|
+
export const LoginFailureView: FC<LoginFailureViewProps> = ({ failure, translate, onAction, page: full, style }) => {
|
|
17
|
+
const phrase = loginFailureHelper.phrase(failure, translate)
|
|
18
|
+
|
|
19
|
+
const notice = <div
|
|
20
|
+
role="alert"
|
|
21
|
+
data-login-failure={failure.kind}
|
|
22
|
+
data-login-refused={failure.refused ? 'true' : undefined}
|
|
23
|
+
style={{ ...box, ...style }}
|
|
24
|
+
>
|
|
25
|
+
<p data-login-failure-message style={{ margin: 0 }}>{phrase.message}</p>
|
|
26
|
+
{phrase.incident != null && <p data-login-failure-incident style={{ marginTop: '.5rem', fontSize: '.75rem', opacity: .7 }}>
|
|
27
|
+
{phrase.incident}
|
|
28
|
+
</p>}
|
|
29
|
+
{onAction != null && <button type="button" data-login-failure-action style={failureAction} onClick={onAction}>
|
|
30
|
+
{phrase.action}
|
|
31
|
+
</button>}
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
return full === true ? <div data-login-failure-page style={page}>{notice}</div> : notice
|
|
35
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { AuthRefused } from '@owlmeans/auth'
|
|
2
|
+
import { apiStatusHelper } from '@owlmeans/api/status'
|
|
3
|
+
import { LoginFailureKind } from './failure/consts.js'
|
|
4
|
+
import {
|
|
5
|
+
BACK_COPY, FAILURE_COPY, INCIDENT_COPY, INCIDENT_PLACEHOLDER, REFUSAL_CODES, RETRY_COPY,
|
|
6
|
+
} from './failure/consts.local.js'
|
|
7
|
+
import type { LoginFailure, LoginFailureHelper, LoginFailurePhrase } from './failure/types.js'
|
|
8
|
+
import type { LoginTranslate } from './types.js'
|
|
9
|
+
|
|
10
|
+
export const createLoginFailureHelper = (): LoginFailureHelper => {
|
|
11
|
+
const english: LoginTranslate = (_key, defaultValue) => defaultValue
|
|
12
|
+
|
|
13
|
+
/** The message and type a caught value carries — a non-object carries none. */
|
|
14
|
+
const textOf = (error: unknown): string => {
|
|
15
|
+
if (error == null || typeof error !== 'object') {
|
|
16
|
+
return typeof error === 'string' ? error : ''
|
|
17
|
+
}
|
|
18
|
+
const { message, type } = error as { message?: unknown, type?: unknown }
|
|
19
|
+
|
|
20
|
+
return [message, type].filter((part): part is string => typeof part === 'string').join(' ')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const codeOf = (error: unknown): LoginFailureKind | null => {
|
|
24
|
+
const text = textOf(error)
|
|
25
|
+
|
|
26
|
+
return REFUSAL_CODES.find(([marker]) => marker.test(text))?.[1] ?? null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** `AuthRefused` of this or another module copy: `instanceof` answers across copies by type name. */
|
|
30
|
+
const isRefusedClass = (error: unknown): boolean =>
|
|
31
|
+
error instanceof AuthRefused
|
|
32
|
+
|| (error != null && typeof error === 'object' && (error as { type?: unknown }).type === AuthRefused.typeName)
|
|
33
|
+
|
|
34
|
+
const failureOf = (error: unknown): LoginFailure => {
|
|
35
|
+
const kind = codeOf(error)
|
|
36
|
+
?? (isRefusedClass(error) || apiStatusHelper.isAccessDenied(error) ? LoginFailureKind.Refused : LoginFailureKind.Failed)
|
|
37
|
+
const [key, fallback] = FAILURE_COPY[kind]
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
kind,
|
|
41
|
+
refused: kind !== LoginFailureKind.Failed,
|
|
42
|
+
key,
|
|
43
|
+
fallback,
|
|
44
|
+
incidentId: apiStatusHelper.incidentIdOf(error),
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const isRefusal = (error: unknown): boolean => failureOf(error).refused
|
|
49
|
+
|
|
50
|
+
const phrase = (failure: LoginFailure, translate: LoginTranslate = english): LoginFailurePhrase => {
|
|
51
|
+
const [actionKey, actionFallback] = failure.refused ? BACK_COPY : RETRY_COPY
|
|
52
|
+
// A refusal is the person's condition, not an incident to report: no reference line.
|
|
53
|
+
const incident = !failure.refused && failure.incidentId != null
|
|
54
|
+
? translate(INCIDENT_COPY[0], INCIDENT_COPY[1]).split(INCIDENT_PLACEHOLDER).join(failure.incidentId)
|
|
55
|
+
: null
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
message: translate(failure.key, failure.fallback),
|
|
59
|
+
incident,
|
|
60
|
+
action: translate(actionKey, actionFallback),
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { failureOf, isRefusal, phrase }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export const loginFailureHelper = createLoginFailureHelper()
|
package/src/login/i18n/be.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "Уваход не завершаны. Паспрабуйце яшчэ раз.",
|
|
37
|
-
"blocked": "Акно ўваходу заблакавана. Націсніце значок заблакаванага ўсплывальнага акна ў адрасным радку браўзера, каб адкрыць яго."
|
|
37
|
+
"blocked": "Акно ўваходу заблакавана. Націсніце значок заблакаванага ўсплывальнага акна ў адрасным радку браўзера, каб адкрыць яго.",
|
|
38
|
+
"refused": "З гэтым акаўнтам тут увайсці нельга.",
|
|
39
|
+
"account-disabled": "Гэты акаўнт адключаны, таму ўвайсці з ім тут нельга.",
|
|
40
|
+
"profile-disabled": "Доступ гэтага акаўнта да праграмы заблакаваны, таму ўвайсці з ім тут нельга.",
|
|
41
|
+
"retry": "Паспрабаваць зноў",
|
|
42
|
+
"back": "Вярнуцца да ўваходу",
|
|
43
|
+
"incident": "Код звароту: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Уваход выкананы. Можаце закрыць гэтае акно і вярнуцца ў праграму."
|
|
40
46
|
}
|
package/src/login/i18n/de.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "Die Anmeldung wurde nicht abgeschlossen. Bitte versuchen Sie es erneut.",
|
|
37
|
-
"blocked": "Das Anmeldefenster wurde blockiert. Klicken Sie auf das Symbol für blockierte Pop-ups in der Adressleiste Ihres Browsers, um es zu öffnen."
|
|
37
|
+
"blocked": "Das Anmeldefenster wurde blockiert. Klicken Sie auf das Symbol für blockierte Pop-ups in der Adressleiste Ihres Browsers, um es zu öffnen.",
|
|
38
|
+
"refused": "Mit diesem Konto ist hier keine Anmeldung möglich.",
|
|
39
|
+
"account-disabled": "Dieses Konto wurde deaktiviert; eine Anmeldung ist hier nicht möglich.",
|
|
40
|
+
"profile-disabled": "Der Zugang dieses Kontos zu dieser Anwendung wurde gesperrt; eine Anmeldung ist hier nicht möglich.",
|
|
41
|
+
"retry": "Erneut versuchen",
|
|
42
|
+
"back": "Zurück zur Anmeldung",
|
|
43
|
+
"incident": "Referenz: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Angemeldet. Sie können dieses Fenster schließen und in der Anwendung fortfahren."
|
|
40
46
|
}
|
package/src/login/i18n/en.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "Sign-in did not complete. Please try again.",
|
|
37
|
-
"blocked": "The sign-in window was blocked. Click the blocked pop-up icon in your browser's address bar to open it."
|
|
37
|
+
"blocked": "The sign-in window was blocked. Click the blocked pop-up icon in your browser's address bar to open it.",
|
|
38
|
+
"refused": "This account cannot sign in here.",
|
|
39
|
+
"account-disabled": "This account has been disabled and cannot sign in here.",
|
|
40
|
+
"profile-disabled": "This account’s access to this application has been blocked, so it cannot sign in here.",
|
|
41
|
+
"retry": "Try again",
|
|
42
|
+
"back": "Back to sign-in",
|
|
43
|
+
"incident": "Reference: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Signed in. You can close this window and continue in the application."
|
|
40
46
|
}
|
package/src/login/i18n/es.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "El inicio de sesión no se completó. Inténtalo de nuevo.",
|
|
37
|
-
"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."
|
|
37
|
+
"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.",
|
|
38
|
+
"refused": "Esta cuenta no puede iniciar sesión aquí.",
|
|
39
|
+
"account-disabled": "Esta cuenta ha sido desactivada y no puede iniciar sesión aquí.",
|
|
40
|
+
"profile-disabled": "El acceso de esta cuenta a esta aplicación ha sido bloqueado, por lo que no puede iniciar sesión aquí.",
|
|
41
|
+
"retry": "Intentar de nuevo",
|
|
42
|
+
"back": "Volver al inicio de sesión",
|
|
43
|
+
"incident": "Referencia: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Sesión iniciada. Puedes cerrar esta ventana y continuar en la aplicación."
|
|
40
46
|
}
|
package/src/login/i18n/fr.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "La connexion n’a pas abouti. Réessayez.",
|
|
37
|
-
"blocked": "La fenêtre de connexion a été bloquée. Cliquez sur l’icône de fenêtre contextuelle bloquée dans la barre d’adresse pour l’ouvrir."
|
|
37
|
+
"blocked": "La fenêtre de connexion a été bloquée. Cliquez sur l’icône de fenêtre contextuelle bloquée dans la barre d’adresse pour l’ouvrir.",
|
|
38
|
+
"refused": "Ce compte ne peut pas se connecter ici.",
|
|
39
|
+
"account-disabled": "Ce compte a été désactivé et ne peut pas se connecter ici.",
|
|
40
|
+
"profile-disabled": "L’accès de ce compte à cette application a été bloqué ; il ne peut donc pas se connecter ici.",
|
|
41
|
+
"retry": "Réessayer",
|
|
42
|
+
"back": "Retour à la connexion",
|
|
43
|
+
"incident": "Référence : {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Vous êtes connecté. Vous pouvez fermer cette fenêtre et continuer dans l’application."
|
|
40
46
|
}
|
package/src/login/i18n/pl.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "Logowanie nie zostało ukończone. Spróbuj ponownie.",
|
|
37
|
-
"blocked": "Okno logowania zostało zablokowane. Kliknij ikonę zablokowanego okienka w pasku adresu przeglądarki, aby je otworzyć."
|
|
37
|
+
"blocked": "Okno logowania zostało zablokowane. Kliknij ikonę zablokowanego okienka w pasku adresu przeglądarki, aby je otworzyć.",
|
|
38
|
+
"refused": "To konto nie może się tutaj zalogować.",
|
|
39
|
+
"account-disabled": "To konto zostało wyłączone i nie może się tutaj zalogować.",
|
|
40
|
+
"profile-disabled": "Dostęp tego konta do tej aplikacji został zablokowany, więc nie może się ono tutaj zalogować.",
|
|
41
|
+
"retry": "Spróbuj ponownie",
|
|
42
|
+
"back": "Wróć do logowania",
|
|
43
|
+
"incident": "Kod zgłoszenia: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Zalogowano. Możesz zamknąć to okno i kontynuować w aplikacji."
|
|
40
46
|
}
|
package/src/login/i18n/ru.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "Вход не завершён. Попробуйте ещё раз.",
|
|
37
|
-
"blocked": "Окно входа заблокировано. Нажмите на значок заблокированного всплывающего окна в адресной строке браузера, чтобы открыть его."
|
|
37
|
+
"blocked": "Окно входа заблокировано. Нажмите на значок заблокированного всплывающего окна в адресной строке браузера, чтобы открыть его.",
|
|
38
|
+
"refused": "С этим аккаунтом здесь войти нельзя.",
|
|
39
|
+
"account-disabled": "Этот аккаунт отключён, поэтому войти с ним здесь нельзя.",
|
|
40
|
+
"profile-disabled": "Доступ этого аккаунта к приложению заблокирован, поэтому войти с ним здесь нельзя.",
|
|
41
|
+
"retry": "Попробовать снова",
|
|
42
|
+
"back": "Вернуться ко входу",
|
|
43
|
+
"incident": "Код обращения: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Вход выполнен. Можете закрыть это окно и вернуться в приложение."
|
|
40
46
|
}
|
package/src/login/i18n/uk.json
CHANGED
|
@@ -34,7 +34,13 @@
|
|
|
34
34
|
},
|
|
35
35
|
"error": {
|
|
36
36
|
"failed": "Вхід не завершено. Спробуйте ще раз.",
|
|
37
|
-
"blocked": "Вікно входу заблоковано. Натисніть значок заблокованого спливаючого вікна в адресному рядку браузера, щоб відкрити його."
|
|
37
|
+
"blocked": "Вікно входу заблоковано. Натисніть значок заблокованого спливаючого вікна в адресному рядку браузера, щоб відкрити його.",
|
|
38
|
+
"refused": "З цим обліковим записом тут увійти не можна.",
|
|
39
|
+
"account-disabled": "Цей обліковий запис вимкнено, тому увійти з ним тут не можна.",
|
|
40
|
+
"profile-disabled": "Доступ цього облікового запису до застосунку заблоковано, тому увійти з ним тут не можна.",
|
|
41
|
+
"retry": "Спробувати ще раз",
|
|
42
|
+
"back": "Повернутися до входу",
|
|
43
|
+
"incident": "Код звернення: {{incident}}"
|
|
38
44
|
},
|
|
39
45
|
"orphaned": "Вхід виконано. Можете закрити це вікно й повернутися до застосунку."
|
|
40
46
|
}
|
package/src/login/index.ts
CHANGED
|
@@ -11,6 +11,11 @@ export type * from './credit/types.js'
|
|
|
11
11
|
export type * from './surrogate/types.js'
|
|
12
12
|
export type * from './land/types.js'
|
|
13
13
|
export type * from './start/types.js'
|
|
14
|
+
export type * from './failure/types.js'
|
|
15
|
+
export * from './failure/consts.js'
|
|
16
|
+
export * from './failure.js'
|
|
17
|
+
export * from './failure-view.js'
|
|
18
|
+
export * from './translate.js'
|
|
14
19
|
export * from './env.js'
|
|
15
20
|
export * from './adopt.js'
|
|
16
21
|
export * from './methods.js'
|
package/src/login/screen.tsx
CHANGED
|
@@ -8,6 +8,9 @@ import { loginMethodsHelper } from './methods.js'
|
|
|
8
8
|
import { loginTermsHelper } from './terms.js'
|
|
9
9
|
import { resolveCredit } from './credit.js'
|
|
10
10
|
import { box, page } from './consts.local.js'
|
|
11
|
+
import { loginFailureHelper } from './failure.js'
|
|
12
|
+
import { LoginFailureView } from './failure-view.js'
|
|
13
|
+
import type { LoginFailure } from './failure/types.js'
|
|
11
14
|
|
|
12
15
|
const renderParts = (parts: TermsSentencePart[]): ReactNode =>
|
|
13
16
|
parts.map((part, index) => part.href != null
|
|
@@ -49,6 +52,8 @@ export const FallbackLoginScreen: FC<LoginScreenProps> = props => {
|
|
|
49
52
|
|
|
50
53
|
const [accepted, setAccepted] = useState(() => loginTermsHelper.termsAccepted(resolved))
|
|
51
54
|
const [attempted, setAttempted] = useState(false)
|
|
55
|
+
// A start that rejected — phrased, never the raw message; the method buttons are the retry.
|
|
56
|
+
const [failure, setFailure] = useState<LoginFailure | null>(null)
|
|
52
57
|
|
|
53
58
|
const all = login.methods({ context, env })
|
|
54
59
|
const methods = typeof props.methods === 'function'
|
|
@@ -63,7 +68,10 @@ export const FallbackLoginScreen: FC<LoginScreenProps> = props => {
|
|
|
63
68
|
setAttempted(true)
|
|
64
69
|
return
|
|
65
70
|
}
|
|
66
|
-
|
|
71
|
+
setFailure(null)
|
|
72
|
+
void method.start({ context, env }).catch((error: unknown) => {
|
|
73
|
+
setFailure(loginFailureHelper.failureOf(error))
|
|
74
|
+
})
|
|
67
75
|
}, [blocked, context, env])
|
|
68
76
|
|
|
69
77
|
const onAccept = useCallback((value: boolean) => {
|
|
@@ -131,6 +139,10 @@ export const FallbackLoginScreen: FC<LoginScreenProps> = props => {
|
|
|
131
139
|
))}
|
|
132
140
|
</p>}
|
|
133
141
|
|
|
142
|
+
{failure != null && <LoginFailureView
|
|
143
|
+
failure={failure} translate={t} style={{ padding: 0, marginTop: '1rem', color: '#b00', fontSize: '.875rem' }}
|
|
144
|
+
/>}
|
|
145
|
+
|
|
134
146
|
{props.footer ?? <p style={{ marginTop: '2rem', fontSize: '.75rem', opacity: .7 }}>
|
|
135
147
|
{credit.poweredBy && <span>{t('login.credit.powered', 'Powered by OwlMeans')}</span>}
|
|
136
148
|
{credit.poweredBy && credit.line != null && ' · '}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ClientConfig } from '@owlmeans/client-context'
|
|
2
|
+
import { DEFAULT_LNG, LIB_NAMESPACE, i18nHelper } from '@owlmeans/i18n'
|
|
3
|
+
import { i18nInstanceHelper } from '@owlmeans/client-i18n/utils'
|
|
4
|
+
import { LOGIN_I18N_RESOURCE } from './consts.local.js'
|
|
5
|
+
import type { LoginTranslate } from './types.js'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A translate over the `auth` library resource that reads no React context.
|
|
9
|
+
*
|
|
10
|
+
* For a sign-in surface that renders outside any screen binding a `translate` — a dispatcher's
|
|
11
|
+
* failed exchange, a plugin's own form — where a hook that reaches for an i18n provider would throw
|
|
12
|
+
* inside render in an app mounted without one. It reads the app's one i18next instance
|
|
13
|
+
* (`i18nInstanceHelper.getI18nInstance`, the same instance `useI18nLib` drives) and drains the
|
|
14
|
+
* `auth` bundle into it when no component has yet: `initI18nResource` is one-shot per slot, so
|
|
15
|
+
* whichever of the two runs first loads it and the other no-ops. App-tier overrides of the `auth`
|
|
16
|
+
* keys (`addI18nApp(lng, 'auth', …, { ns: LIB_NAMESPACE })`) resolve here as everywhere else.
|
|
17
|
+
*/
|
|
18
|
+
export const makeAuthTranslate = (cfg: ClientConfig): LoginTranslate => {
|
|
19
|
+
const i18n = i18nInstanceHelper.getI18nInstance(cfg)
|
|
20
|
+
const fallback = typeof i18n.options?.fallbackLng === 'string' ? i18n.options.fallbackLng : DEFAULT_LNG
|
|
21
|
+
for (const lng of new Set([i18n.language, fallback])) {
|
|
22
|
+
if (lng == null) {
|
|
23
|
+
continue
|
|
24
|
+
}
|
|
25
|
+
i18nHelper.initI18nResource(lng, LOGIN_I18N_RESOURCE, LIB_NAMESPACE)?.forEach(resource => i18n.addResourceBundle(
|
|
26
|
+
lng, LIB_NAMESPACE, { [LOGIN_I18N_RESOURCE]: resource.data }, true, true
|
|
27
|
+
))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (key, defaultValue) =>
|
|
31
|
+
i18n.t(`${LOGIN_I18N_RESOURCE}.${key}`, { ns: LIB_NAMESPACE, defaultValue })
|
|
32
|
+
}
|
package/src/login/types.ts
CHANGED
|
@@ -177,6 +177,14 @@ export interface LoginMethodSource {
|
|
|
177
177
|
list: (ctx: LoginMethodContext) => LoginMethod[]
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/**
|
|
181
|
+
* `(key, defaultValue) => string` over the `auth` library resource — the one translate contract
|
|
182
|
+
* every sign-in renderer shares. Placeholders (`{{incident}}`) are filled after it answers.
|
|
183
|
+
*/
|
|
184
|
+
export interface LoginTranslate {
|
|
185
|
+
(key: string, defaultValue: string): string
|
|
186
|
+
}
|
|
187
|
+
|
|
180
188
|
/** What every rendering of the sign-in screen accepts, whatever its UI family. */
|
|
181
189
|
export interface LoginScreenProps {
|
|
182
190
|
/** The one thing a consuming application is expected to supply. */
|
package/src/manager/README.md
CHANGED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { randomUUID } from 'node:crypto'
|
|
3
|
+
import { renderToStaticMarkup } from 'react-dom/server'
|
|
4
|
+
import { ACCESS_DENIED_KIND, ApiClientError, ServerCrashedError } from '@owlmeans/api'
|
|
5
|
+
import type { ResponseStatusCarrier } from '@owlmeans/api'
|
|
6
|
+
import { AuthenFailed, AuthForbidden, AuthRefused, AuthenticationStage } from '@owlmeans/auth'
|
|
7
|
+
import { AppType } from '@owlmeans/context'
|
|
8
|
+
import { ResilientError } from '@owlmeans/error'
|
|
9
|
+
import { LIB_NAMESPACE, i18nHelper } from '@owlmeans/i18n'
|
|
10
|
+
import type { ClientConfig } from '@owlmeans/client-context'
|
|
11
|
+
import type { ClientContext } from '@owlmeans/client'
|
|
12
|
+
import {
|
|
13
|
+
LoginFailureKind, LoginFailureView, loginFailureHelper, makeAuthTranslate,
|
|
14
|
+
} from '../src/login/index.js'
|
|
15
|
+
import type { LoginTranslate } from '../src/login/index.js'
|
|
16
|
+
import { makeControl } from '../src/manager/components/authentication/control.js'
|
|
17
|
+
import { makeTestContext } from './context.js'
|
|
18
|
+
|
|
19
|
+
/** A failed call as the API client rejects it: the error, stamped with the status and denial kind. */
|
|
20
|
+
const answered = <T extends Error>(error: T, status: number, denialKind?: string): T =>
|
|
21
|
+
Object.assign(error, { responseStatus: status, denialKind } satisfies ResponseStatusCarrier)
|
|
22
|
+
|
|
23
|
+
/** A development body rebuilt into its class on the far side, as `@owlmeans/api` rebuilds it. */
|
|
24
|
+
const rebuilt = (error: ResilientError, status: number, denialKind?: string): ResilientError =>
|
|
25
|
+
answered(ResilientError.ensure(ResilientError.marshal(error)), status, denialKind)
|
|
26
|
+
|
|
27
|
+
/** The registered `auth` bundle of a language, resolved the way i18next resolves a dotted key. */
|
|
28
|
+
const translateOf = (lng: string): LoginTranslate => {
|
|
29
|
+
const bundle = i18nHelper.resolveI18nResource(lng, 'auth', LIB_NAMESPACE) ?? {}
|
|
30
|
+
|
|
31
|
+
return (key, defaultValue) => {
|
|
32
|
+
const found = key.split('.').reduce<unknown>(
|
|
33
|
+
(node, part) => (node != null && typeof node === 'object' ? (node as Record<string, unknown>)[part] : undefined),
|
|
34
|
+
bundle,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return typeof found === 'string' ? found : defaultValue
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe('loginFailureHelper — a refused sign-in', () => {
|
|
42
|
+
// Production exposure: the body is the incident id alone, the status and the marker are the refusal.
|
|
43
|
+
test('the labelled 403 is a refusal, phrased "This account cannot sign in here."', () => {
|
|
44
|
+
const incident = randomUUID()
|
|
45
|
+
const failure = loginFailureHelper.failureOf(answered(new ApiClientError(`forbidden:${incident}`), 403, ACCESS_DENIED_KIND))
|
|
46
|
+
|
|
47
|
+
expect(failure).toMatchObject({ kind: LoginFailureKind.Refused, refused: true, key: 'login.error.refused' })
|
|
48
|
+
expect(loginFailureHelper.phrase(failure)).toEqual({
|
|
49
|
+
message: 'This account cannot sign in here.', incident: null, action: 'Back to sign-in',
|
|
50
|
+
})
|
|
51
|
+
// Development exposure rebuilds the class itself; a deployment's own refusal reads the same.
|
|
52
|
+
expect(loginFailureHelper.failureOf(rebuilt(new AuthRefused('operator:refused'), 403, ACCESS_DENIED_KIND)).kind)
|
|
53
|
+
.toBe(LoginFailureKind.Refused)
|
|
54
|
+
expect(loginFailureHelper.isRefusal(new AuthRefused('operator:unknown-account'))).toBe(true)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('a visible refusal code gets its precise sentence', () => {
|
|
58
|
+
const account = loginFailureHelper.failureOf(rebuilt(new AuthRefused('account:disabled'), 403, ACCESS_DENIED_KIND))
|
|
59
|
+
const profile = loginFailureHelper.failureOf(rebuilt(new AuthRefused('profile:disabled'), 403, ACCESS_DENIED_KIND))
|
|
60
|
+
|
|
61
|
+
expect(account).toMatchObject({ kind: LoginFailureKind.AccountDisabled, refused: true })
|
|
62
|
+
expect(loginFailureHelper.phrase(account).message).toBe('This account has been disabled and cannot sign in here.')
|
|
63
|
+
expect(profile).toMatchObject({ kind: LoginFailureKind.ProfileDisabled, refused: true })
|
|
64
|
+
expect(loginFailureHelper.phrase(profile).message).toContain('access to this application has been blocked')
|
|
65
|
+
// A server still on `AuthenFailed`, and the integrated IAM finalizer's ban, name the same codes.
|
|
66
|
+
expect(loginFailureHelper.failureOf(rebuilt(new AuthenFailed('account:disabled'), 500)).kind)
|
|
67
|
+
.toBe(LoginFailureKind.AccountDisabled)
|
|
68
|
+
expect(loginFailureHelper.failureOf(rebuilt(new AuthForbidden('account:disabled'), 403, ACCESS_DENIED_KIND)).kind)
|
|
69
|
+
.toBe(LoginFailureKind.AccountDisabled)
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
describe('loginFailureHelper — any other failure', () => {
|
|
74
|
+
test('is worth a retry and carries the incident a person reports', () => {
|
|
75
|
+
const incident = randomUUID()
|
|
76
|
+
const crashed = loginFailureHelper.failureOf(answered(new ServerCrashedError(incident), 500))
|
|
77
|
+
|
|
78
|
+
expect(crashed).toMatchObject({ kind: LoginFailureKind.Failed, refused: false, key: 'login.error.failed', incidentId: incident })
|
|
79
|
+
expect(loginFailureHelper.phrase(crashed)).toEqual({
|
|
80
|
+
message: 'Sign-in did not complete. Please try again.', incident: `Reference: ${incident}`, action: 'Try again',
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// Plan and entitlement refusals use 403 too, and a proxy's 403 carries no marker at all.
|
|
85
|
+
test('a 403 without the marker, a failed challenge, a network error or nothing are no refusals', () => {
|
|
86
|
+
for (const error of [
|
|
87
|
+
answered(new ApiClientError('forbidden'), 403),
|
|
88
|
+
rebuilt(new AuthenFailed('challenge'), 500),
|
|
89
|
+
new AuthenFailed('account:disabled-later'),
|
|
90
|
+
new Error('Network Error'),
|
|
91
|
+
null,
|
|
92
|
+
'forbidden',
|
|
93
|
+
]) {
|
|
94
|
+
expect(loginFailureHelper.failureOf(error)).toMatchObject({ kind: LoginFailureKind.Failed, refused: false })
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('phrases through the translate it is given — every shipped language has the keys', () => {
|
|
99
|
+
const incident = randomUUID()
|
|
100
|
+
const refused = loginFailureHelper.failureOf(new AuthRefused())
|
|
101
|
+
const failed = loginFailureHelper.failureOf(answered(new ServerCrashedError(incident), 500))
|
|
102
|
+
|
|
103
|
+
expect(loginFailureHelper.phrase(refused, translateOf('fr'))).toEqual({
|
|
104
|
+
message: 'Ce compte ne peut pas se connecter ici.', incident: null, action: 'Retour à la connexion',
|
|
105
|
+
})
|
|
106
|
+
expect(loginFailureHelper.phrase(failed, translateOf('de')).incident).toBe(`Referenz: ${incident}`)
|
|
107
|
+
for (const lng of ['en', 'pl', 'ru', 'be', 'uk', 'es', 'de', 'fr']) {
|
|
108
|
+
const translate = translateOf(lng)
|
|
109
|
+
for (const key of ['refused', 'account-disabled', 'profile-disabled', 'failed', 'retry', 'back', 'incident']) {
|
|
110
|
+
expect({ lng, key, found: translate(`login.error.${key}`, '') !== '' }).toEqual({ lng, key, found: true })
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
describe('makeAuthTranslate — the `auth` keys with no React context', () => {
|
|
117
|
+
test('reads the app\'s i18next instance, and an app override of a key wins', () => {
|
|
118
|
+
// Registered before the slot is first drained — exactly how an application overrides it.
|
|
119
|
+
i18nHelper.addI18nApp('en', 'auth', { login: { error: { refused: 'Not with this account.' } } }, { ns: LIB_NAMESPACE })
|
|
120
|
+
const cfg = { ready: false, service: 'client-auth-tests', type: AppType.Frontend, services: {} } as unknown as ClientConfig
|
|
121
|
+
const translate = makeAuthTranslate(cfg)
|
|
122
|
+
|
|
123
|
+
expect(loginFailureHelper.phrase(loginFailureHelper.failureOf(new AuthRefused()), translate))
|
|
124
|
+
.toEqual({ message: 'Not with this account.', incident: null, action: 'Back to sign-in' })
|
|
125
|
+
expect(translate('login.error.failed', 'missing')).toBe('Sign-in did not complete. Please try again.')
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
describe('LoginFailureView — the end state of a failed sign-in', () => {
|
|
130
|
+
const html = (node: unknown): string => renderToStaticMarkup(<>{node as never}</>)
|
|
131
|
+
|
|
132
|
+
test('a refusal: one phrased sentence and the way back, no reference', () => {
|
|
133
|
+
const out = html(<LoginFailureView
|
|
134
|
+
failure={loginFailureHelper.failureOf(rebuilt(new AuthRefused('account:disabled'), 403, ACCESS_DENIED_KIND))}
|
|
135
|
+
onAction={() => {}}
|
|
136
|
+
/>)
|
|
137
|
+
|
|
138
|
+
expect(out).toContain('role="alert"')
|
|
139
|
+
expect(out).toContain('data-login-failure="account-disabled"')
|
|
140
|
+
expect(out).toContain('data-login-refused="true"')
|
|
141
|
+
expect(out).toContain('This account has been disabled and cannot sign in here.')
|
|
142
|
+
expect(out).toContain('>Back to sign-in</button>')
|
|
143
|
+
expect(out).not.toContain('data-login-failure-incident')
|
|
144
|
+
expect(out).not.toContain('auth:manager')
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
test('a failure: the generic sentence, its reference and a retry — a button only with an action', () => {
|
|
148
|
+
const incident = randomUUID()
|
|
149
|
+
const failure = loginFailureHelper.failureOf(answered(new ServerCrashedError(incident), 500))
|
|
150
|
+
|
|
151
|
+
const out = html(<LoginFailureView failure={failure} onAction={() => {}} page />)
|
|
152
|
+
expect(out).toContain('data-login-failure-page')
|
|
153
|
+
expect(out).toContain('data-login-failure="failed"')
|
|
154
|
+
expect(out).toContain('Sign-in did not complete. Please try again.')
|
|
155
|
+
expect(out).toContain(`Reference: ${incident}`)
|
|
156
|
+
expect(out).toContain('>Try again</button>')
|
|
157
|
+
|
|
158
|
+
expect(html(<LoginFailureView failure={failure} />)).not.toContain('<button')
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('the authentication control keeps what a failure view reads', () => {
|
|
163
|
+
// The Google callback and the supervisor form end in `setError`: the stage moves to Error, and
|
|
164
|
+
// the stamped status and marker of the API client's rejection survive `ResilientError.ensure`.
|
|
165
|
+
test('setError moves to the Error stage with the refusal intact', async () => {
|
|
166
|
+
const stages: AuthenticationStage[] = []
|
|
167
|
+
const control = makeControl(makeTestContext() as unknown as ClientContext<ClientConfig>)
|
|
168
|
+
control.setStage = stage => { stages.push(stage) }
|
|
169
|
+
|
|
170
|
+
await control.setError(answered(new ApiClientError(`forbidden:${randomUUID()}`), 403, ACCESS_DENIED_KIND))
|
|
171
|
+
|
|
172
|
+
expect(control.stage).toBe(AuthenticationStage.Error)
|
|
173
|
+
expect(stages).toEqual([AuthenticationStage.Error])
|
|
174
|
+
expect(loginFailureHelper.failureOf(control.error).kind).toBe(LoginFailureKind.Refused)
|
|
175
|
+
})
|
|
176
|
+
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../src/manager/modules.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,OAAO,mDAAO,CAAA"}
|
package/build/manager/modules.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { AUTHEN, AUTHEN_AUTHEN, AUTHEN_INIT, AUTHEN_RELY, CAUTHEN, CAUTHEN_AUTHEN, CAUTHEN_AUTHEN_DEFAULT, CAUTHEN_AUTHEN_TYPED, DISPATCHER } from '@owlmeans/auth';
|
|
2
|
-
import { modules as list } from '@owlmeans/auth-common';
|
|
3
|
-
import { handler } from '@owlmeans/client';
|
|
4
|
-
import { elevate, stab } from '@owlmeans/client-entrypoint';
|
|
5
|
-
import { AuthenticationHOC } from './components/authentication/component.js';
|
|
6
|
-
elevate(list, AUTHEN);
|
|
7
|
-
elevate(list, AUTHEN_INIT, true);
|
|
8
|
-
elevate(list, AUTHEN_AUTHEN, true);
|
|
9
|
-
elevate(list, AUTHEN_RELY);
|
|
10
|
-
elevate(list, CAUTHEN);
|
|
11
|
-
elevate(list, CAUTHEN_AUTHEN);
|
|
12
|
-
elevate(list, CAUTHEN_AUTHEN_DEFAULT, handler(AuthenticationHOC()));
|
|
13
|
-
elevate(list, CAUTHEN_AUTHEN_TYPED, handler(AuthenticationHOC()));
|
|
14
|
-
elevate(list, DISPATCHER, stab, { force: true });
|
|
15
|
-
export const modules = list;
|
|
16
|
-
//# sourceMappingURL=modules.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modules.js","sourceRoot":"","sources":["../../src/manager/modules.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AACnK,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAE5E,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACrB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;AAChC,OAAO,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,CAAC,CAAA;AAClC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAA;AAC1B,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AACtB,OAAO,CAAC,IAAI,EAAE,cAAc,CAAC,CAAA;AAC7B,OAAO,CAAC,IAAI,EAAE,sBAAsB,EAAE,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAA;AACnE,OAAO,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAA;AACjE,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAA"}
|
package/build/modules.d.ts
DELETED
package/build/modules.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAInE,eAAO,MAAM,OAAO,EAAE,gBAAgB,EAA+B,CAAA;AAErE,eAAO,MAAM,2BAA2B,GAAI,SAAS,MAAM,SAE1D,CAAA"}
|
package/build/modules.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { elevate, stab } from '@owlmeans/client-entrypoint';
|
|
2
|
-
import { modules as list } from '@owlmeans/auth-common';
|
|
3
|
-
import { CAUTHEN_FLOW_ENTER, DISPATCHER_AUTHEN } from '@owlmeans/auth';
|
|
4
|
-
elevate(list, DISPATCHER_AUTHEN);
|
|
5
|
-
export const modules = list;
|
|
6
|
-
export const setupExternalAuthentication = (service) => {
|
|
7
|
-
elevate(list, CAUTHEN_FLOW_ENTER, stab, { routeOptions: { overrides: { service } } });
|
|
8
|
-
};
|
|
9
|
-
//# sourceMappingURL=modules.js.map
|
package/build/modules.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"modules.js","sourceRoot":"","sources":["../src/modules.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,6BAA6B,CAAA;AAC3D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAGtE,OAAO,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAA;AAEhC,MAAM,CAAC,MAAM,OAAO,GAAuB,IAA0B,CAAA;AAErE,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,OAAe,EAAE,EAAE;IAC7D,OAAO,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,EAAE,YAAY,EAAE,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAA;AACvF,CAAC,CAAA"}
|