@owlmeans/client-panel 0.1.18-rc.57 → 0.1.18-rc.59

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 (56) hide show
  1. package/README.md +5 -5
  2. package/agent-meta/manifest.json +2 -2
  3. package/agent-meta/skills/client-panel/SKILL.md +46 -19
  4. package/build/auth/i18n.js +9 -9
  5. package/build/auth/i18n.js.map +1 -1
  6. package/build/auth/login/index.d.ts +2 -0
  7. package/build/auth/login/index.d.ts.map +1 -1
  8. package/build/auth/login/index.js +2 -0
  9. package/build/auth/login/index.js.map +1 -1
  10. package/build/auth/login/model.d.ts +2 -2
  11. package/build/auth/login/model.d.ts.map +1 -1
  12. package/build/auth/login/model.js +11 -8
  13. package/build/auth/login/model.js.map +1 -1
  14. package/build/auth/login/provider/consts.local.d.ts +3 -0
  15. package/build/auth/login/provider/consts.local.d.ts.map +1 -0
  16. package/build/auth/login/provider/consts.local.js +3 -0
  17. package/build/auth/login/provider/consts.local.js.map +1 -0
  18. package/build/auth/login/provider-config.d.ts +37 -0
  19. package/build/auth/login/provider-config.d.ts.map +1 -0
  20. package/build/auth/login/provider-config.js +2 -0
  21. package/build/auth/login/provider-config.js.map +1 -0
  22. package/build/auth/login/provider.d.ts +5 -0
  23. package/build/auth/login/provider.d.ts.map +1 -0
  24. package/build/auth/login/provider.js +55 -0
  25. package/build/auth/login/provider.js.map +1 -0
  26. package/build/auth/login/types.d.ts +48 -1
  27. package/build/auth/login/types.d.ts.map +1 -1
  28. package/build/components/nav/helper.d.ts +1 -9
  29. package/build/components/nav/helper.d.ts.map +1 -1
  30. package/build/components/nav/helper.js +0 -12
  31. package/build/components/nav/helper.js.map +1 -1
  32. package/build/components/nav/index.d.ts +1 -0
  33. package/build/components/nav/index.d.ts.map +1 -1
  34. package/build/components/nav/index.js +1 -0
  35. package/build/components/nav/index.js.map +1 -1
  36. package/build/components/nav/label.d.ts +4 -0
  37. package/build/components/nav/label.d.ts.map +1 -0
  38. package/build/components/nav/label.js +12 -0
  39. package/build/components/nav/label.js.map +1 -0
  40. package/build/components/nav/types.d.ts +12 -0
  41. package/build/components/nav/types.d.ts.map +1 -1
  42. package/build/i18n.js +2 -2
  43. package/build/i18n.js.map +1 -1
  44. package/package.json +14 -14
  45. package/src/auth/i18n.ts +9 -9
  46. package/src/auth/login/index.ts +2 -0
  47. package/src/auth/login/model.ts +11 -11
  48. package/src/auth/login/provider/consts.local.ts +2 -0
  49. package/src/auth/login/provider-config.ts +38 -0
  50. package/src/auth/login/provider.ts +65 -0
  51. package/src/auth/login/types.ts +52 -1
  52. package/src/components/nav/helper.ts +1 -19
  53. package/src/components/nav/index.ts +1 -0
  54. package/src/components/nav/label.ts +20 -0
  55. package/src/components/nav/types.ts +13 -0
  56. package/src/i18n.ts +2 -2
package/README.md CHANGED
@@ -16,7 +16,7 @@ headless navigation model.
16
16
  ## Installation
17
17
 
18
18
  ```bash
19
- bun add @owlmeans/client-panel@^0.1.18-rc.57
19
+ bun add @owlmeans/client-panel@^0.1.18-rc.59
20
20
  ```
21
21
 
22
22
  ## Usage
@@ -130,12 +130,12 @@ Returns `sections` (with `hidden` filtered out), `current` (the active screen's
130
130
  keyboard-operable, openable in a new tab). It returns `undefined` for a path carrying route
131
131
  parameters.
132
132
 
133
- ### `resolveNavLabel(translate, label, key, alias)`
133
+ ### `navLabelHelper.resolveNavLabel(translate, label, key, alias)`
134
134
 
135
135
  Resolves a label as literal `label` → `translate(key, defaultNavLabel(alias))` → the humanized
136
- alias. `translate` always reaches a component as a **prop**, defaulting to `defaultNavTranslate`
136
+ alias. `translate` always reaches a component as a **prop**, defaulting to `navLabelHelper.defaultNavTranslate`
137
137
  (which returns the fallback) — a menu must never read an i18n context implicitly, because an app
138
- mounted without an i18n provider throws inside render and blanks the page. `defaultNavLabel`
138
+ mounted without an i18n provider throws inside render and blanks the page. `navLabelHelper.defaultNavLabel`
139
139
  humanizes the last alias segment
140
140
  (`my-app:web:user-list` → `User list`). Default key families are `nav.<section>` and
141
141
  `modules.<alias>`.
@@ -153,7 +153,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
153
153
  your project's skill store (`.agents/skills/`):
154
154
 
155
155
  ```sh
156
- npx @owlmeans/agent-skills@^0.1.18-rc.48
156
+ npx @owlmeans/agent-skills@^0.1.18-rc.51
157
157
  ```
158
158
 
159
159
  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/client-panel",
4
- "version": "0.1.18-rc.57",
5
- "generatedAt": "2026-10-05T08:32:19.132Z",
4
+ "version": "0.1.18-rc.59",
5
+ "generatedAt": "2026-10-06T11:45:57.680Z",
6
6
  "canonicalRepo": "https://github.com/owlmeans/common",
7
7
  "entries": [
8
8
  {
@@ -8,7 +8,7 @@ user-invocable: false
8
8
  # @owlmeans/client-panel
9
9
 
10
10
  **Layer:** Client
11
- **Install:** `"@owlmeans/client-panel": "^0.1.18-rc.57"` in `dependencies`
11
+ **Install:** `"@owlmeans/client-panel": "^0.1.18-rc.59"` in `dependencies`
12
12
 
13
13
  ## Key Exports
14
14
 
@@ -34,15 +34,17 @@ controller; apps may override it through their own `buttons` resource.
34
34
  | `usePanelLayout()` / `useLayoutTitle(name?, alias?)` / `prepareLayoutTitle(title)` | The entrypoint the current layout is rendering, and its translated title |
35
35
  | `BlockScaling` | `Full` / `Half` / `Wide` — the sizing vocabulary both platform families render |
36
36
  | `usePanelNav(config)` | Headless navigation model behind a two-layer menu |
37
- | `resolveNavLabel`, `defaultNavLabel`, `defaultNavTranslate` | Label resolution helpers |
37
+ | `navLabelHelper` → `.resolveNavLabel`, `.defaultNavLabel`, `.defaultNavTranslate` | Label resolution helpers |
38
38
  | `PanelNavConfig`, `PanelNavSection`, `PanelNavItem`, `PanelNavLink`, `PanelNavModel`, `NavTranslate` | Navigation types |
39
39
  | `FormProps`, `FormRef`, `FormOnSubmit`, `TFormContext`, `FormFieldProps`, `FormActionProps`, `FormActionRenderArgs`, `InputControllerProps`, `TPanelContext`, `StatusOptions` | The model shapes a renderer is written against |
40
40
 
41
41
  ## Subpath Exports
42
42
 
43
- - `./auth` — `useLoginMethods` and the login model types (`LoginMethodsModel`, `LoginTermsModel`,
44
- `LoginCreditModel`, `UseLoginMethodsOptions`). Importing it also registers this package's own
45
- seven-language `client-panel-auth` bundle by side effect.
43
+ - `./auth` — `useLoginMethods`, `loginProviderHelper` and the login model types
44
+ (`LoginMethodsModel`, `LoginTermsModel`, `LoginCreditModel`, `LoginProviderConfig`,
45
+ `LoginProviderModel`, `LoginProviderPlacement`, `UseLoginMethodsOptions`). Importing it also
46
+ registers this package's own seven-language `client-panel-auth` bundle and the
47
+ `LoginScreenConfig.provider` augmentation of `@owlmeans/config` by side effect.
46
48
  - `./auth/plugins` — the shapes an auth UI plugin is written against: `Ed22519BasicAuthUIPluginForm`
47
49
  and its `Ed22519BasicAuthUIPluginFormSchema`.
48
50
 
@@ -55,13 +57,37 @@ same split the form and navigation models already use. See `login-methods`.
55
57
  `@owlmeans/client-auth/login`) rather than a flat `urls: { terms, privacy, cookies? }` — that field
56
58
  is gone; nothing in the repo read it outside this model and its one renderer, so it was dropped
57
59
  rather than kept alongside the replacement. It also carries `revisedAt?` and `version`. A renderer
58
- turns `documents`/`notices` into markup with `termsSentence` (`@owlmeans/client-auth/login`), never
59
- by re-deriving link/label pairs itself.
60
-
61
- `LoginTermsModel.deferred` mirrors `termsDeferred(ctx)`: true once a registered, bound `LoginStep`
62
- confirms the terms instead of this screen. `LoginMethodsModel.blocked` folds it in
63
- (`required && !deferred && !accepted`) — a renderer never blocks on `required`/`accepted` alone,
64
- or it would re-block a screen whose confirmation moved elsewhere.
60
+ turns `documents`/`notices` into markup with `loginTermsHelper.termsSentence`
61
+ (`@owlmeans/client-auth/login`), never by re-deriving link/label pairs itself.
62
+
63
+ `LoginTermsModel.deferred` mirrors `loginTermsHelper.termsDeferred(ctx)`: true once a registered,
64
+ bound `LoginStep` confirms the terms instead of this screen. `LoginMethodsModel.blocked` folds it in
65
+ (`required && !deferred && !accepted`) — a renderer never blocks on `required`/`accepted` alone, or
66
+ it would re-block a screen whose confirmation moved elsewhere.
67
+
68
+ ### The provider disclosure — `LoginMethodsModel.provider`
69
+
70
+ A sign-in screen that a third party runs for an application (a generated target signing people in
71
+ through the platform's IAM) names both parties: who signs the person in, and on behalf of which
72
+ product. The rules live here, headless, so every renderer discloses the same thing:
73
+
74
+ - **Config** — `cfg.security.auth.login.provider?: LoginProviderConfig`
75
+ (`{ name, operator?, info?, placement?: 'top' | 'inline' }`), declared onto `@owlmeans/config`'s
76
+ `LoginScreenConfig` by module augmentation in `auth/login/provider-config.ts` (the
77
+ `client-auth/login/terms-config.ts` pattern), never by editing `@owlmeans/config`. The `./auth`
78
+ barrel re-exports it, so any import of `@owlmeans/client-panel/auth` loads the field; a program
79
+ that builds the literal without one adds `import type {} from '@owlmeans/client-panel/auth'`.
80
+ - **Model** — `loginProviderHelper.resolve(cfg, brand)` → `LoginProviderModel { name, operator,
81
+ product, info: string | null, placement }` or `null`. Null unless the provider `name` AND the
82
+ product (`cfg.brand.name`) are set — a relationship with one party missing is never shown. Blank
83
+ strings are unset (build-time env arrives as `''`); `operator` defaults to `name`; `placement` to
84
+ `'inline'` (anything but `'top'` is inline); `info` survives only as an absolute `http(s)` URL or
85
+ a root-relative path (`//host` and `/\` are refused). `useLoginMethods().provider` carries it.
86
+ - **Copy** — `loginProviderHelper.fill(template, model)` puts `{{provider}}`, `{{operator}}` and
87
+ `{{product}}` into an ALREADY-TRANSLATED sentence in one pass; names never travel as i18next
88
+ params. The keys (`login.provider.*`) and the markup belong to `web-panel`.
89
+ - The disclosure is independent of the credit line: `credit.poweredBy: false` never hides who
90
+ signs a person in.
65
91
 
66
92
  ## Usage
67
93
 
@@ -122,13 +148,14 @@ alias, or null), `active` (its section), `showSide`, `isSectionActive` / `isItem
122
148
  - **`showSide` owns the one-screen rule.** It is false when the active section holds a single
123
149
  screen — a second level offering the page you are already on is noise. A renderer asks the model;
124
150
  it does not count items itself.
125
- - **Label resolution never touches i18n implicitly.** `NavTranslate` is a `(key, defaultValue) =>
126
- string` **prop**, defaulting to `defaultNavTranslate`, which returns the fallback. An app mounted
127
- without an i18n provider (`renderApp` from `@owlmeans/web-client` mounts none) crashes if a menu
128
- reaches for the panel i18n context: the hook dereferences `i18n.options` on the empty object
129
- `react-i18next` returns without an instance, and a throw inside render blanks the whole app.
130
- `resolveNavLabel(translate, label, key, alias)` applies the order — literal `label` →
131
- `translate(key, humanized)` → `defaultNavLabel(alias)`, which humanizes the last alias segment
151
+ - **Label resolution never touches i18n implicitly.** `NavTranslate` is a
152
+ `(key, defaultValue) => string` **prop**, defaulting to `navLabelHelper.defaultNavTranslate`,
153
+ which returns the fallback. An app mounted without an i18n provider (`renderApp` from
154
+ `@owlmeans/web-client` mounts none) crashes if a menu reaches for the panel i18n context: the hook
155
+ dereferences `i18n.options` on the empty object `react-i18next` returns without an instance, and a
156
+ throw inside render blanks the whole app.
157
+ `navLabelHelper.resolveNavLabel(translate, label, key, alias)` applies the order — literal `label`
158
+ → `translate(key, humanized)` → `.defaultNavLabel(alias)`, which humanizes the last alias segment
132
159
  (`my-app:web:user-list` → `User list`). Default key families: `nav.<name>` for sections,
133
160
  `modules.<alias>` for items and footer links.
134
161
  - **Resolving the current screen needs two sources.** The router's `location.state.alias` is
@@ -1,4 +1,4 @@
1
- import { addI18nLib } from '@owlmeans/i18n';
1
+ import { i18nHelper } from '@owlmeans/i18n';
2
2
  import en from './i18n/en.json' with { type: 'json' };
3
3
  import pl from './i18n/pl.json' with { type: 'json' };
4
4
  import ru from './i18n/ru.json' with { type: 'json' };
@@ -7,12 +7,12 @@ import uk from './i18n/uk.json' with { type: 'json' };
7
7
  import es from './i18n/es.json' with { type: 'json' };
8
8
  import de from './i18n/de.json' with { type: 'json' };
9
9
  import fr from './i18n/fr.json' with { type: 'json' };
10
- addI18nLib('en', 'client-panel-auth', en);
11
- addI18nLib('pl', 'client-panel-auth', pl);
12
- addI18nLib('ru', 'client-panel-auth', ru);
13
- addI18nLib('be', 'client-panel-auth', be);
14
- addI18nLib('uk', 'client-panel-auth', uk);
15
- addI18nLib('es', 'client-panel-auth', es);
16
- addI18nLib('de', 'client-panel-auth', de);
17
- addI18nLib('fr', 'client-panel-auth', fr);
10
+ i18nHelper.addI18nLib('en', 'client-panel-auth', en);
11
+ i18nHelper.addI18nLib('pl', 'client-panel-auth', pl);
12
+ i18nHelper.addI18nLib('ru', 'client-panel-auth', ru);
13
+ i18nHelper.addI18nLib('be', 'client-panel-auth', be);
14
+ i18nHelper.addI18nLib('uk', 'client-panel-auth', uk);
15
+ i18nHelper.addI18nLib('es', 'client-panel-auth', es);
16
+ i18nHelper.addI18nLib('de', 'client-panel-auth', de);
17
+ i18nHelper.addI18nLib('fr', 'client-panel-auth', fr);
18
18
  //# sourceMappingURL=i18n.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/auth/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE3C,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAErD,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACzC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../../src/auth/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAE3C,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AACrD,OAAO,EAAE,MAAM,gBAAgB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAA;AAErD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA;AACpD,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,mBAAmB,EAAE,EAAE,CAAC,CAAA"}
@@ -1,3 +1,5 @@
1
1
  export type * from './types.js';
2
2
  export * from './model.js';
3
+ export * from './provider.js';
4
+ export * from './provider-config.js';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/login/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/login/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA"}
@@ -1,2 +1,4 @@
1
1
  export * from './model.js';
2
+ export * from './provider.js';
3
+ export * from './provider-config.js';
2
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/login/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/login/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAA;AAC1B,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA"}
@@ -3,8 +3,8 @@ import type { LoginMethodsModel, UseLoginMethodsOptions } from './types.js';
3
3
  * Everything a sign-in screen needs, with no opinion about how it looks.
4
4
  *
5
5
  * Headless and cross-platform, like `usePanelNav`: the rules about what may be offered, what must
6
- * be confirmed first and what the credit line says are the same on every platform, and only the
7
- * rendering differs. A renderer that re-derives any of them will drift from the one that does not.
6
+ * be confirmed first, what the credit line says and who is disclosed as signing the person in are
7
+ * the same on every platform, and only the rendering differs. A renderer that re-derives any of them will drift from the one that does not.
8
8
  */
9
9
  export declare const useLoginMethods: (opts?: UseLoginMethodsOptions) => LoginMethodsModel;
10
10
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/auth/login/model.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAE3E;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,UAAW,sBAAsB,KAAG,iBAoF/D,CAAA"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/auth/login/model.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAA;AAG3E;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,UAAW,sBAAsB,KAAG,iBAsF/D,CAAA"}
@@ -1,12 +1,13 @@
1
1
  import { useCallback, useMemo, useState } from 'react';
2
2
  import { useContext, useNavigate } from '@owlmeans/client';
3
- import { acceptTerms, primaryLoginMethod, resolveCredit, resolveTerms, termsAccepted, termsDeferred, LoginOutcome, LOGIN_SERVICE, } from '@owlmeans/client-auth/login';
3
+ import { resolveCredit, LoginOutcome, LOGIN_SERVICE, loginMethodsHelper, loginTermsHelper } from '@owlmeans/client-auth/login';
4
+ import { loginProviderHelper } from './provider.js';
4
5
  /**
5
6
  * Everything a sign-in screen needs, with no opinion about how it looks.
6
7
  *
7
8
  * Headless and cross-platform, like `usePanelNav`: the rules about what may be offered, what must
8
- * be confirmed first and what the credit line says are the same on every platform, and only the
9
- * rendering differs. A renderer that re-derives any of them will drift from the one that does not.
9
+ * be confirmed first, what the credit line says and who is disclosed as signing the person in are
10
+ * the same on every platform, and only the rendering differs. A renderer that re-derives any of them will drift from the one that does not.
10
11
  */
11
12
  export const useLoginMethods = (opts) => {
12
13
  const context = useContext();
@@ -14,9 +15,10 @@ export const useLoginMethods = (opts) => {
14
15
  const login = context.service(LOGIN_SERVICE);
15
16
  const cfg = opts?.config ?? context.cfg.security?.auth?.login;
16
17
  const brand = context.cfg.brand;
17
- const resolved = useMemo(() => resolveTerms(opts?.terms ?? cfg?.terms), [opts?.terms, cfg]);
18
+ const resolved = useMemo(() => loginTermsHelper.resolveTerms(opts?.terms ?? cfg?.terms), [opts?.terms, cfg]);
18
19
  const credit = useMemo(() => resolveCredit(cfg?.credit, brand, context.cfg.service), [cfg, brand, context]);
19
- const [accepted, setAccepted] = useState(() => termsAccepted(resolved));
20
+ const provider = useMemo(() => loginProviderHelper.resolve(cfg?.provider, brand), [cfg, brand]);
21
+ const [accepted, setAccepted] = useState(() => loginTermsHelper.termsAccepted(resolved));
20
22
  const [attempted, setAttempted] = useState(false);
21
23
  const [busy, setBusy] = useState(null);
22
24
  const [outcome, setOutcome] = useState(null);
@@ -29,7 +31,7 @@ export const useLoginMethods = (opts) => {
29
31
  const methods = typeof opts?.methods === 'function'
30
32
  ? opts.methods(all)
31
33
  : opts?.methods ?? all;
32
- const deferred = termsDeferred(context);
34
+ const deferred = loginTermsHelper.termsDeferred(context);
33
35
  const blocked = resolved != null && resolved.required && !deferred && !accepted;
34
36
  const select = useCallback((method) => {
35
37
  if (blocked) {
@@ -58,11 +60,11 @@ export const useLoginMethods = (opts) => {
58
60
  const accept = useCallback((value) => {
59
61
  setAccepted(value);
60
62
  setAttempted(false);
61
- acceptTerms(resolved, value);
63
+ loginTermsHelper.acceptTerms(resolved, value);
62
64
  }, [resolved]);
63
65
  return {
64
66
  methods,
65
- primary: primaryLoginMethod(methods),
67
+ primary: loginMethodsHelper.primaryLoginMethod(methods),
66
68
  terms: {
67
69
  required: resolved?.required ?? false,
68
70
  accepted: resolved == null ? true : accepted,
@@ -75,6 +77,7 @@ export const useLoginMethods = (opts) => {
75
77
  accept,
76
78
  },
77
79
  credit,
80
+ provider,
78
81
  blocked,
79
82
  busy,
80
83
  outcome,
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/auth/login/model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE1D,OAAO,EACL,WAAW,EAAE,kBAAkB,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAC1F,YAAY,EAAE,aAAa,GAC5B,MAAM,6BAA6B,CAAA;AAIpC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAA6B,EAAqB,EAAE;IAClF,MAAM,OAAO,GAAG,UAAU,EAA6B,CAAA;IACvD,MAAM,GAAG,GAAG,WAAW,EAAE,CAAA;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAe,aAAa,CAAC,CAAA;IAE1D,MAAM,GAAG,GAAG,IAAI,EAAE,MAAM,IAAK,OAAO,CAAC,GAAoB,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAA;IAC/E,MAAM,KAAK,GAAI,OAAO,CAAC,GAAoB,CAAC,KAAK,CAAA;IAEjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,IAAI,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,CAAA;IAC3F,MAAM,MAAM,GAAG,OAAO,CACpB,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CACpF,CAAA;IAED,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAA;IACvE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACrD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAsB,IAAI,CAAC,CAAA;IACjE,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IAEvD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;IACvB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC;QACxB,OAAO,EAAE,GAAG;QACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA,CAAC,CAAC;KACxF,CAAC,CAAA;IACF,MAAM,OAAO,GAAG,OAAO,IAAI,EAAE,OAAO,KAAK,UAAU;QACjD,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;QACnB,CAAC,CAAC,IAAI,EAAE,OAAO,IAAI,GAAG,CAAA;IAExB,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,OAAO,GAAG,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAA;IAE/E,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,MAAmB,EAAE,EAAE;QACjD,IAAI,OAAO,EAAE,CAAC;YACZ,4FAA4F;YAC5F,8FAA8F;YAC9F,YAAY,CAAC,IAAI,CAAC,CAAA;YAElB,OAAM;QACR,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QAClB,QAAQ,CAAC,IAAI,CAAC,CAAA;QACd,KAAK,MAAM,CAAC,KAAK,CAAC;YAChB,OAAO,EAAE,GAAG;YACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA,CAAC,CAAC;SACxF,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE;YACf,UAAU,CAAC,MAAM,CAAC,CAAA;YAClB,uFAAuF;YACvF,IAAI,MAAM,KAAK,YAAY,CAAC,UAAU,EAAE,CAAC;gBACvC,OAAO,CAAC,IAAI,CAAC,CAAA;YACf,CAAC;QACH,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;YACpB,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;YACnB,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IAEhC,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,KAAc,EAAE,EAAE;QAC5C,WAAW,CAAC,KAAK,CAAC,CAAA;QAClB,YAAY,CAAC,KAAK,CAAC,CAAA;QACnB,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;IAC9B,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAA;IAEd,OAAO;QACL,OAAO;QACP,OAAO,EAAE,kBAAkB,CAAC,OAAO,CAAC;QACpC,KAAK,EAAE;YACL,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI,KAAK;YACrC,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ;YAC5C,QAAQ;YACR,SAAS;YACT,SAAS,EAAE,QAAQ,EAAE,SAAS,IAAI,EAAE;YACpC,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE;YAChC,GAAG,CAAC,QAAQ,EAAE,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACzE,OAAO,EAAE,QAAQ,EAAE,OAAO,IAAI,EAAE;YAChC,MAAM;SACP;QACD,MAAM;QACN,OAAO;QACP,IAAI;QACJ,OAAO;QACP,KAAK;QACL,MAAM;KACP,CAAA;AACH,CAAC,CAAA"}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/auth/login/model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** The names a provider sentence may carry, matched in one pass. */
2
+ export declare const PROVIDER_PLACEHOLDER: RegExp;
3
+ //# sourceMappingURL=consts.local.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.d.ts","sourceRoot":"","sources":["../../../../src/auth/login/provider/consts.local.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,QAAyC,CAAA"}
@@ -0,0 +1,3 @@
1
+ /** The names a provider sentence may carry, matched in one pass. */
2
+ export const PROVIDER_PLACEHOLDER = /\{\{(provider|operator|product)\}\}/g;
3
+ //# sourceMappingURL=consts.local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.local.js","sourceRoot":"","sources":["../../../../src/auth/login/provider/consts.local.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,sCAAsC,CAAA"}
@@ -0,0 +1,37 @@
1
+ import type { LoginProviderConfig } from './types.js';
2
+ /**
3
+ * `LoginScreenConfig.provider`, added by TypeScript module augmentation rather than by editing
4
+ * `@owlmeans/config` itself.
5
+ *
6
+ * `@owlmeans/config` has roughly 85 dependents, and every one of them sits in the same release
7
+ * closure — a config bump ripples through every package that pins a range against it, whether or
8
+ * not it touches sign-in. The field below is read by exactly one consumer family (the sign-in
9
+ * screen's headless model here and its renderers), so it is declared here instead, merged onto the
10
+ * base interface by TypeScript's own declaration merging — the pattern
11
+ * `@owlmeans/client-auth/login`'s `terms-config.ts` set.
12
+ *
13
+ * This file must be part of whatever a consumer's own compilation actually loads, or the merge
14
+ * never happens — an ambient augmentation applies only once the compiler has read the file that
15
+ * declares it. `@owlmeans/client-panel/auth`'s barrel re-exports this module for exactly that
16
+ * reason, so ANY import from `@owlmeans/client-panel/auth` pulls this augmentation into that
17
+ * program. An app that builds its `security.auth.login` literal in a file that imports nothing from
18
+ * it (a config file importing only `@owlmeans/config`) still benefits as long as some other file in
19
+ * the same `tsc` program does; if none does, add `import type {} from '@owlmeans/client-panel/auth'`
20
+ * to the file building the literal — an import with an empty type list, kept only to pull this
21
+ * file into that program's graph.
22
+ *
23
+ * `export {}` below is required, not decorative: without at least one top-level import/export this
24
+ * file is a SCRIPT to TypeScript, not a MODULE, and `declare module '@owlmeans/config'` inside a
25
+ * script augments the global scope instead of merging onto the named module's exports.
26
+ */
27
+ declare module '@owlmeans/config' {
28
+ interface LoginScreenConfig {
29
+ /**
30
+ * Who signs a person in on this application's behalf — an identity service the application
31
+ * does not itself run. Absent, the screen discloses nothing and renders exactly as before.
32
+ */
33
+ provider?: LoginProviderConfig;
34
+ }
35
+ }
36
+ export {};
37
+ //# sourceMappingURL=provider-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-config.d.ts","sourceRoot":"","sources":["../../../src/auth/login/provider-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,QAAQ,kBAAkB,CAAC;IAChC,UAAU,iBAAiB;QACzB;;;WAGG;QACH,QAAQ,CAAC,EAAE,mBAAmB,CAAA;KAC/B;CACF;AAED,OAAO,EAAG,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=provider-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-config.js","sourceRoot":"","sources":["../../../src/auth/login/provider-config.ts"],"names":[],"mappings":""}
@@ -0,0 +1,5 @@
1
+ import type { LoginProviderHelper } from './types.js';
2
+ import './provider-config.js';
3
+ export declare const createLoginProviderHelper: () => LoginProviderHelper;
4
+ export declare const loginProviderHelper: LoginProviderHelper;
5
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../src/auth/login/provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,mBAAmB,EAAsB,MAAM,YAAY,CAAA;AAE9F,OAAO,sBAAsB,CAAA;AAE7B,eAAO,MAAM,yBAAyB,QAAO,mBAyD5C,CAAA;AAED,eAAO,MAAM,mBAAmB,qBAA8B,CAAA"}
@@ -0,0 +1,55 @@
1
+ import { PROVIDER_PLACEHOLDER } from './provider/consts.local.js';
2
+ import './provider-config.js';
3
+ export const createLoginProviderHelper = () => {
4
+ /**
5
+ * A configured value that was actually SET — `''` is how a build-time default spells "unset"
6
+ * (see `resolveCredit` in `@owlmeans/client-auth/login`, which follows the same rule).
7
+ */
8
+ const set = (value) => typeof value === 'string' && value.trim() !== '' ? value.trim() : null;
9
+ /**
10
+ * A link a person may be sent to: an absolute http(s) URL, or a path on this origin.
11
+ *
12
+ * `//host` is protocol-relative — another origin wearing a path's clothes — and `/\` is read as
13
+ * the same by browsers, so both are refused along with every other scheme (`javascript:` above
14
+ * all, since this lands in an `href`).
15
+ */
16
+ const link = (value) => {
17
+ const href = set(value);
18
+ if (href == null) {
19
+ return null;
20
+ }
21
+ if (href.startsWith('/')) {
22
+ return /^\/[/\\]/.test(href) ? null : href;
23
+ }
24
+ try {
25
+ const url = new URL(href);
26
+ return url.protocol === 'https:' || url.protocol === 'http:' ? href : null;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ };
32
+ const resolve = (cfg, brand) => {
33
+ const name = set(cfg?.name);
34
+ const product = set(brand?.name);
35
+ if (name == null || product == null) {
36
+ return null;
37
+ }
38
+ return {
39
+ name,
40
+ operator: set(cfg?.operator) ?? name,
41
+ product,
42
+ info: link(cfg?.info),
43
+ placement: cfg?.placement === 'top' ? 'top' : 'inline',
44
+ };
45
+ };
46
+ const fill = (template, model) => {
47
+ const values = {
48
+ provider: model.name, operator: model.operator, product: model.product,
49
+ };
50
+ return template.replace(PROVIDER_PLACEHOLDER, (match, key) => values[key] ?? match);
51
+ };
52
+ return { resolve, fill };
53
+ };
54
+ export const loginProviderHelper = createLoginProviderHelper();
55
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../src/auth/login/provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AACjE,OAAO,sBAAsB,CAAA;AAE7B,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAwB,EAAE;IACjE;;;OAGG;IACH,MAAM,GAAG,GAAG,CAAC,KAAqB,EAAiB,EAAE,CACnD,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAExE;;;;;;OAMG;IACH,MAAM,IAAI,GAAG,CAAC,KAAqB,EAAiB,EAAE;QACpD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAA;QACvB,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YACjB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAC5C,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAA;YAEzB,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC,CAAA;IAED,MAAM,OAAO,GAAG,CAAC,GAAyB,EAAE,KAAqB,EAA6B,EAAE;QAC9F,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QAC3B,MAAM,OAAO,GAAG,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAChC,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpC,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO;YACL,IAAI;YACJ,QAAQ,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,IAAI;YACpC,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC;YACrB,SAAS,EAAE,GAAG,EAAE,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ;SACvD,CAAA;IACH,CAAC,CAAA;IAED,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAE,KAAyB,EAAU,EAAE;QACnE,MAAM,MAAM,GAA2B;YACrC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO;SACvE,CAAA;QAED,OAAO,QAAQ,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,KAAK,EAAE,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAA;IAC7F,CAAC,CAAA;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,yBAAyB,EAAE,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import type { LoginMethod, LoginOutcome, ResolvedTermsDocument } from '@owlmeans/client-auth/login';
2
- import type { LoginScreenConfig, LoginTermsConfig } from '@owlmeans/config';
2
+ import type { BrandSettings, LoginScreenConfig, LoginTermsConfig } from '@owlmeans/config';
3
3
  export interface UseLoginMethodsOptions {
4
4
  /** Overrides the configuration the context carries. */
5
5
  config?: LoginScreenConfig;
@@ -33,12 +33,59 @@ export interface LoginCreditModel {
33
33
  poweredBy: boolean;
34
34
  line: string | null;
35
35
  }
36
+ /** Where the provider disclosure sits: a strip above the card, or a line inside it. */
37
+ export type LoginProviderPlacement = 'top' | 'inline';
38
+ /**
39
+ * Who actually signs a person in, when that is not the application on whose screen they are.
40
+ *
41
+ * Read from `cfg.security.auth.login.provider` (declared onto `LoginScreenConfig` by
42
+ * `./provider-config.ts`). Blank strings are unset, exactly as they are for the credit line: this
43
+ * config is filled from build-time environment variables, and an undelivered one arrives as `''`.
44
+ */
45
+ export interface LoginProviderConfig {
46
+ /** The sign-in service as a person reads it — "OwlMeans IAM". */
47
+ name: string;
48
+ /** Who runs it. Defaults to `name`. */
49
+ operator?: string;
50
+ /** "More information" — an absolute http(s) URL or a root-relative path; anything else is dropped. */
51
+ info?: string;
52
+ /** Default `'inline'`. */
53
+ placement?: LoginProviderPlacement;
54
+ }
55
+ export interface LoginProviderModel {
56
+ name: string;
57
+ operator: string;
58
+ /** The application the person is signing in to — `cfg.brand.name`. */
59
+ product: string;
60
+ info: string | null;
61
+ placement: LoginProviderPlacement;
62
+ }
63
+ export interface LoginProviderHelper {
64
+ /**
65
+ * The disclosure a sign-in screen renders, or `null` when there is nothing to disclose.
66
+ *
67
+ * Null unless both the provider's `name` and the product (`brand.name`) are set — a sentence
68
+ * relating two parties cannot be written with one of them missing, and a screen that showed half
69
+ * of it would be worse than one that shows none.
70
+ */
71
+ resolve: (cfg?: LoginProviderConfig, brand?: BrandSettings) => LoginProviderModel | null;
72
+ /**
73
+ * Put the names into a sentence AFTER it was translated.
74
+ *
75
+ * `{{provider}}`, `{{operator}}` and `{{product}}`, replaced in one pass — a name that itself
76
+ * contains a placeholder is never expanded a second time. The names never travel as i18next
77
+ * interpolation parameters, so no translation backend gets the chance to escape or format them.
78
+ */
79
+ fill: (template: string, model: LoginProviderModel) => string;
80
+ }
36
81
  export interface LoginMethodsModel {
37
82
  methods: LoginMethod[];
38
83
  /** The one a screen highlights and focuses. It is never started automatically. */
39
84
  primary: LoginMethod | null;
40
85
  terms: LoginTermsModel;
41
86
  credit: LoginCreditModel;
87
+ /** Who signs the person in, on behalf of which product — `null` when the app configured nobody. */
88
+ provider: LoginProviderModel | null;
42
89
  /** True while the terms have not been confirmed and confirming them is required. */
43
90
  blocked: boolean;
44
91
  /** Id of the method currently starting. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/login/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AACnG,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAE3E,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,KAAK,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAA;IAChC,qDAAqD;IACrD,OAAO,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC,CAAA;CACtE;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAA;IAClB,8FAA8F;IAC9F,SAAS,EAAE,qBAAqB,EAAE,CAAA;IAClC,6FAA6F;IAC7F,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,kFAAkF;IAClF,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,gBAAgB,CAAA;IACxB,oFAAoF;IACpF,OAAO,EAAE,OAAO,CAAA;IAChB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;OAKG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;CACtC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/auth/login/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAA;AACnG,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAE1F,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,KAAK,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAA;IAChC,qDAAqD;IACrD,OAAO,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC,CAAA;CACtE;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB;;;;;OAKG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAA;IAClB,8FAA8F;IAC9F,SAAS,EAAE,qBAAqB,EAAE,CAAA;IAClC,6FAA6F;IAC7F,OAAO,EAAE,qBAAqB,EAAE,CAAA;IAChC,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CACpB;AAED,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,QAAQ,CAAA;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sGAAsG;IACtG,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0BAA0B;IAC1B,SAAS,CAAC,EAAE,sBAAsB,CAAA;CACnC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,SAAS,EAAE,sBAAsB,CAAA;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;;OAMG;IACH,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,mBAAmB,EAAE,KAAK,CAAC,EAAE,aAAa,KAAK,kBAAkB,GAAG,IAAI,CAAA;IACxF;;;;;;OAMG;IACH,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,KAAK,MAAM,CAAA;CAC9D;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,kFAAkF;IAClF,OAAO,EAAE,WAAW,GAAG,IAAI,CAAA;IAC3B,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,gBAAgB,CAAA;IACxB,mGAAmG;IACnG,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAA;IACnC,oFAAoF;IACpF,OAAO,EAAE,OAAO,CAAA;IAChB,2CAA2C;IAC3C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAA;IAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB;;;;;OAKG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAA;CACtC"}
@@ -1,12 +1,4 @@
1
- import type { NavTranslate, PanelNavConfig, PanelNavModel } from './types.js';
2
- /** Default resolver: no i18n, the caller's fallback wins. See {@link NavTranslate}. */
3
- export declare const defaultNavTranslate: NavTranslate;
4
- /**
5
- * Turn an alias into something readable — `my-app:web:user-list` becomes `User list`.
6
- * The last segment is the meaningful one; the prefixes address the app, not the screen.
7
- */
8
- export declare const defaultNavLabel: (alias: string) => string;
9
- export declare const resolveNavLabel: (translate: NavTranslate, label: string | undefined, key: string, alias?: string) => string;
1
+ import type { PanelNavConfig, PanelNavModel } from './types.js';
10
2
  /**
11
3
  * The navigation model behind both menus.
12
4
  *
@@ -1 +1 @@
1
- {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../../src/components/nav/helper.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAgB,aAAa,EAAmB,MAAM,YAAY,CAAA;AAE5G,uFAAuF;AACvF,eAAO,MAAM,mBAAmB,EAAE,YAAmD,CAAA;AAErF;;;GAGG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,KAAG,MAK/C,CAAA;AAED,eAAO,MAAM,eAAe,cACf,YAAY,SAAS,MAAM,GAAG,SAAS,OAAO,MAAM,UAAU,MAAM,KAC9E,MAAgE,CAAA;AAQnE;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,WAAY,cAAc,KAAG,aA6FpD,CAAA"}
1
+ {"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../../src/components/nav/helper.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAgB,aAAa,EAAmB,MAAM,YAAY,CAAA;AAQ9F;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,WAAY,cAAc,KAAG,aA6FpD,CAAA"}
@@ -1,17 +1,5 @@
1
1
  import { useMemo } from 'react';
2
2
  import { useContext, useNavigate } from '@owlmeans/client';
3
- /** Default resolver: no i18n, the caller's fallback wins. See {@link NavTranslate}. */
4
- export const defaultNavTranslate = (_key, defaultValue) => defaultValue;
5
- /**
6
- * Turn an alias into something readable — `my-app:web:user-list` becomes `User list`.
7
- * The last segment is the meaningful one; the prefixes address the app, not the screen.
8
- */
9
- export const defaultNavLabel = (alias) => {
10
- const segment = alias.split(/[:.]/).filter(part => part !== '').pop() ?? alias;
11
- const words = segment.replace(/[-_]+/g, ' ').trim();
12
- return words.charAt(0).toUpperCase() + words.slice(1);
13
- };
14
- export const resolveNavLabel = (translate, label, key, alias) => label ?? translate(key, defaultNavLabel(alias ?? key));
15
3
  const visibleItems = (section) => section.items.filter(item => item.hidden !== true);
16
4
  const normalizePath = (path) => path.length > 1 && path.endsWith('/') ? path.slice(0, -1) : path;
17
5
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"helper.js","sourceRoot":"","sources":["../../../src/components/nav/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAI/B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAI1D,uFAAuF;AACvF,MAAM,CAAC,MAAM,mBAAmB,GAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,YAAY,CAAA;AAErF;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAa,EAAU,EAAE;IACvD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,CAAA;IAC9E,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IAEnD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACvD,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,SAAuB,EAAE,KAAyB,EAAE,GAAW,EAAE,KAAc,EACvE,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,EAAE,eAAe,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAA;AAEnE,MAAM,YAAY,GAAG,CAAC,OAAwB,EAAkB,EAAE,CAChE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAA;AAEpD,MAAM,aAAa,GAAG,CAAC,IAAY,EAAU,EAAE,CAC7C,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAElE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAsB,EAAiB,EAAE;IACnE,MAAM,OAAO,GAAG,UAAU,EAAE,CAAA;IAC5B,MAAM,GAAG,GAAG,WAAW,EAAE,CAAA;IACzB,MAAM,QAAQ,GAA0B,OAAO,CAAC,MAAM,EAAE,CAAC,WAAW,EAAE,CAAA;IAEtE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAA2B,CAAA;IAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAA;IAElC,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ;aAC7B,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC;aAC1C,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;QAEjE,MAAM,MAAM,GAAG,CAAC,KAAa,EAAiB,EAAE;YAC9C,IAAI,CAAC;gBACH,OAAO,aAAa,CAAC,OAAO,CAAC,UAAU,CAA2B,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;YAClF,CAAC;YAAC,MAAM,CAAC;gBACP,sFAAsF;gBACtF,8CAA8C;gBAC9C,OAAO,IAAI,CAAA;YACb,CAAC;QACH,CAAC,CAAA;QAED,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAEtD,IAAI,OAAO,GAAkB,KAAK,EAAE,KAAK,IAAI,IAAI,CAAA;QACjD,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;YACpC,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAA;YAC3D,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBAClB,OAAO,GAAG,KAAK,CAAC,KAAK,CAAA;YACvB,CAAC;iBAAM,CAAC;gBACN,mFAAmF;gBACnF,MAAM,QAAQ,GAAG,GAAG;qBACjB,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;qBACjD,MAAM,CAAC,CAAC,KAAK,EAAiD,EAAE,CAC/D,KAAK,CAAC,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;qBAC/E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;gBACnD,OAAO,GAAG,QAAQ,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAA;YACxC,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,CAAC,KAAoB,EAA0B,EAAE,CACjE,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,IAAI,IAAI,CAAA;QAE3G,IAAI,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,CAAA;QAC/B,IAAI,MAAM,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACtC,oFAAoF;YACpF,uFAAuF;YACvF,IAAI,KAAK,GAAkB,OAAO,CAAA;YAClC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;YAC9B,OAAO,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;gBACf,IAAI,CAAC;oBACH,KAAK,GAAG,OAAO,CAAC,UAAU,CAA2B,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAA;gBACxF,CAAC;gBAAC,MAAM,CAAC;oBACP,KAAK,GAAG,IAAI,CAAA;gBACd,CAAC;gBACD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;gBAC9B,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,MAAM,GAAG,KAAK,CAAA;oBACd,MAAK;gBACP,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,YAAY,GAAG,CAAC,IAAkB,EAAW,EAAE,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAA;QAC5E,MAAM,eAAe,GAAG,CAAC,OAAwB,EAAW,EAAE,CAC5D,MAAM,IAAI,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAA;QAEhD,OAAO;YACL,QAAQ;YACR,OAAO;YACP,MAAM;YACN,QAAQ,EAAE,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;YACnD,eAAe;YACf,YAAY;YACZ,SAAS,EAAE,OAAO,CAAC,EAAE;gBACnB,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;gBAC9B,OAAO,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;YAC1D,CAAC;YACD,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;YACrC,MAAM,EAAE,MAAM,CAAC,EAAE;gBACf,MAAM,KAAK,GAAG,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAA;gBACvE,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,OAAO,SAAS,CAAA;gBAClB,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;gBAE1B,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;YAC9D,CAAC;SACF,CAAA;IACH,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;AACpD,CAAC,CAAA"}
1
+ {"version":3,"file":"helper.js","sourceRoot":"","sources":["../../../src/components/nav/helper.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export type * from './types.js';
2
+ export * from './label.js';
2
3
  export * from './helper.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/nav/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAE/B,cAAc,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/nav/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,YAAY,CAAA;AAE/B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA"}
@@ -1,2 +1,3 @@
1
+ export * from './label.js';
1
2
  export * from './helper.js';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/nav/index.ts"],"names":[],"mappings":"AAEA,cAAc,aAAa,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/nav/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { NavLabelHelper } from './types.js';
2
+ export declare const createNavLabelHelper: () => NavLabelHelper;
3
+ export declare const navLabelHelper: NavLabelHelper;
4
+ //# sourceMappingURL=label.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/components/nav/label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,YAAY,CAAA;AAE9D,eAAO,MAAM,oBAAoB,QAAO,cAevC,CAAA;AAED,eAAO,MAAM,cAAc,gBAAyB,CAAA"}
@@ -0,0 +1,12 @@
1
+ export const createNavLabelHelper = () => {
2
+ const defaultNavTranslate = (_key, defaultValue) => defaultValue;
3
+ const defaultNavLabel = (alias) => {
4
+ const segment = alias.split(/[:.]/).filter(part => part !== '').pop() ?? alias;
5
+ const words = segment.replace(/[-_]+/g, ' ').trim();
6
+ return words.charAt(0).toUpperCase() + words.slice(1);
7
+ };
8
+ const resolveNavLabel = (translate, label, key, alias) => label ?? translate(key, defaultNavLabel(alias ?? key));
9
+ return { defaultNavTranslate, defaultNavLabel, resolveNavLabel };
10
+ };
11
+ export const navLabelHelper = createNavLabelHelper();
12
+ //# sourceMappingURL=label.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"label.js","sourceRoot":"","sources":["../../../src/components/nav/label.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAmB,EAAE;IACvD,MAAM,mBAAmB,GAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,YAAY,CAAA;IAE9E,MAAM,eAAe,GAAG,CAAC,KAAa,EAAU,EAAE;QAChD,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,CAAA;QAC9E,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QAEnD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IACvD,CAAC,CAAA;IAED,MAAM,eAAe,GAAG,CACtB,SAAuB,EAAE,KAAyB,EAAE,GAAW,EAAE,KAAc,EACvE,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,EAAE,eAAe,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAA;IAEnE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,eAAe,EAAE,CAAA;AAClE,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,oBAAoB,EAAE,CAAA"}
@@ -73,4 +73,16 @@ export interface PanelNavModel {
73
73
  */
74
74
  hrefOf: (target: PanelNavItem | PanelNavSection) => string | undefined;
75
75
  }
76
+ /** How a navigation entry gets its label. */
77
+ export interface NavLabelHelper {
78
+ /** Default resolver: no i18n, the caller's fallback wins. See {@link NavTranslate}. */
79
+ defaultNavTranslate: NavTranslate;
80
+ /**
81
+ * Turn an alias into something readable — `my-app:web:user-list` becomes `User list`.
82
+ * The last segment is the meaningful one; the prefixes address the app, not the screen.
83
+ */
84
+ defaultNavLabel: (alias: string) => string;
85
+ /** The literal label when given, else the translation of `key` falling back to the humanized alias. */
86
+ resolveNavLabel: (translate: NavTranslate, label: string | undefined, key: string, alias?: string) => string;
87
+ }
76
88
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/nav/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,4GAA4G;IAC5G,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAED,uFAAuF;AACvF,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,QAAQ,EAAE,eAAe,EAAE,CAAA;IAC3B,yEAAyE;IACzE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IAC9B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAA;IACtD,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAA;IAC7C,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,IAAI,CAAA;IACnD,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,IAAI,CAAA;IAC1C;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,KAAK,MAAM,GAAG,SAAS,CAAA;CACvE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/nav/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,4GAA4G;IAC5G,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,aAAa,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5C,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,mEAAmE;IACnE,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,+EAA+E;IAC/E,KAAK,EAAE,YAAY,EAAE,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAED,uFAAuF;AACvF,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yBAAyB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAAA;CAC5C;AAED,MAAM,WAAW,aAAa;IAC5B,qDAAqD;IACrD,QAAQ,EAAE,eAAe,EAAE,CAAA;IAC3B,yEAAyE;IACzE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,MAAM,EAAE,eAAe,GAAG,IAAI,CAAA;IAC9B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,OAAO,CAAA;IACtD,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAA;IAC7C,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,MAAM,IAAI,CAAA;IACnD,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,IAAI,CAAA;IAC1C;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,YAAY,GAAG,eAAe,KAAK,MAAM,GAAG,SAAS,CAAA;CACvE;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,mBAAmB,EAAE,YAAY,CAAA;IACjC;;;OAGG;IACH,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1C,uGAAuG;IACvG,eAAe,EAAE,CAAC,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAC7G"}
package/build/i18n.js CHANGED
@@ -1,6 +1,6 @@
1
- import { addI18nLib } from '@owlmeans/i18n';
1
+ import { i18nHelper } from '@owlmeans/i18n';
2
2
  import { buttons } from './consts.local.js';
3
3
  for (const [language, values] of Object.entries(buttons)) {
4
- addI18nLib(language, 'client-panel', values);
4
+ i18nHelper.addI18nLib(language, 'client-panel', values);
5
5
  }
6
6
  //# sourceMappingURL=i18n.js.map
package/build/i18n.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3C,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IACzD,UAAU,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,CAAC,CAAA;AAC9C,CAAC"}
1
+ {"version":3,"file":"i18n.js","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAA;AAE3C,KAAK,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IACzD,UAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,CAAC,CAAA;AACzD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owlmeans/client-panel",
3
- "version": "0.1.18-rc.57",
3
+ "version": "0.1.18-rc.59",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -36,19 +36,19 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@hookform/resolvers": "^5.9.1",
39
- "@owlmeans/client": "^0.1.18-rc.50",
40
- "@owlmeans/client-i18n": "^0.1.18-rc.49",
41
- "@owlmeans/client-entrypoint": "^0.1.18-rc.46",
42
- "@owlmeans/client-route": "^0.1.18-rc.47",
43
- "@owlmeans/error": "^0.1.18-rc.37",
44
- "@owlmeans/entrypoint": "^0.1.18-rc.40"
39
+ "@owlmeans/client": "^0.1.18-rc.52",
40
+ "@owlmeans/client-i18n": "^0.1.18-rc.51",
41
+ "@owlmeans/client-entrypoint": "^0.1.18-rc.48",
42
+ "@owlmeans/client-route": "^0.1.18-rc.49",
43
+ "@owlmeans/error": "^0.1.18-rc.38",
44
+ "@owlmeans/entrypoint": "^0.1.18-rc.41"
45
45
  },
46
46
  "peerDependencies": {
47
- "@owlmeans/auth": "^0.1.18-rc.39",
48
- "@owlmeans/client-auth": "^0.1.18-rc.57",
49
- "@owlmeans/config": "^0.1.18-rc.43",
50
- "@owlmeans/i18n": "^0.1.18-rc.38",
51
- "@owlmeans/router": "^0.1.18-rc.32",
47
+ "@owlmeans/auth": "^0.1.18-rc.40",
48
+ "@owlmeans/client-auth": "^0.1.18-rc.59",
49
+ "@owlmeans/config": "^0.1.18-rc.44",
50
+ "@owlmeans/i18n": "^0.1.18-rc.39",
51
+ "@owlmeans/router": "^0.1.18-rc.33",
52
52
  "ajv": "*",
53
53
  "react": "*",
54
54
  "react-hook-form": "*"
@@ -63,8 +63,8 @@
63
63
  },
64
64
  "devDependencies": {
65
65
  "@owlmeans/dep-config": "workspace:*",
66
- "@owlmeans/auth": "^0.1.18-rc.39",
67
- "@owlmeans/client-auth": "^0.1.18-rc.57",
66
+ "@owlmeans/auth": "^0.1.18-rc.40",
67
+ "@owlmeans/client-auth": "^0.1.18-rc.59",
68
68
  "@types/react": "^19.3.0",
69
69
  "nodemon": "^3.1.14",
70
70
  "react-hook-form": "^7.89.0",
package/src/auth/i18n.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { addI18nLib } from '@owlmeans/i18n'
1
+ import { i18nHelper } from '@owlmeans/i18n'
2
2
 
3
3
  import en from './i18n/en.json' with { type: 'json' }
4
4
  import pl from './i18n/pl.json' with { type: 'json' }
@@ -9,11 +9,11 @@ import es from './i18n/es.json' with { type: 'json' }
9
9
  import de from './i18n/de.json' with { type: 'json' }
10
10
  import fr from './i18n/fr.json' with { type: 'json' }
11
11
 
12
- addI18nLib('en', 'client-panel-auth', en)
13
- addI18nLib('pl', 'client-panel-auth', pl)
14
- addI18nLib('ru', 'client-panel-auth', ru)
15
- addI18nLib('be', 'client-panel-auth', be)
16
- addI18nLib('uk', 'client-panel-auth', uk)
17
- addI18nLib('es', 'client-panel-auth', es)
18
- addI18nLib('de', 'client-panel-auth', de)
19
- addI18nLib('fr', 'client-panel-auth', fr)
12
+ i18nHelper.addI18nLib('en', 'client-panel-auth', en)
13
+ i18nHelper.addI18nLib('pl', 'client-panel-auth', pl)
14
+ i18nHelper.addI18nLib('ru', 'client-panel-auth', ru)
15
+ i18nHelper.addI18nLib('be', 'client-panel-auth', be)
16
+ i18nHelper.addI18nLib('uk', 'client-panel-auth', uk)
17
+ i18nHelper.addI18nLib('es', 'client-panel-auth', es)
18
+ i18nHelper.addI18nLib('de', 'client-panel-auth', de)
19
+ i18nHelper.addI18nLib('fr', 'client-panel-auth', fr)
@@ -1,2 +1,4 @@
1
1
  export type * from './types.js'
2
2
  export * from './model.js'
3
+ export * from './provider.js'
4
+ export * from './provider-config.js'
@@ -1,19 +1,17 @@
1
1
  import { useCallback, useMemo, useState } from 'react'
2
2
  import { useContext, useNavigate } from '@owlmeans/client'
3
3
  import type { CommonConfig } from '@owlmeans/config'
4
- import {
5
- acceptTerms, primaryLoginMethod, resolveCredit, resolveTerms, termsAccepted, termsDeferred,
6
- LoginOutcome, LOGIN_SERVICE,
7
- } from '@owlmeans/client-auth/login'
4
+ import { resolveCredit, LoginOutcome, LOGIN_SERVICE, loginMethodsHelper, loginTermsHelper } from '@owlmeans/client-auth/login'
8
5
  import type { LoginContext, LoginMethod, LoginService } from '@owlmeans/client-auth/login'
9
6
  import type { LoginMethodsModel, UseLoginMethodsOptions } from './types.js'
7
+ import { loginProviderHelper } from './provider.js'
10
8
 
11
9
  /**
12
10
  * Everything a sign-in screen needs, with no opinion about how it looks.
13
11
  *
14
12
  * Headless and cross-platform, like `usePanelNav`: the rules about what may be offered, what must
15
- * be confirmed first and what the credit line says are the same on every platform, and only the
16
- * rendering differs. A renderer that re-derives any of them will drift from the one that does not.
13
+ * be confirmed first, what the credit line says and who is disclosed as signing the person in are
14
+ * the same on every platform, and only the rendering differs. A renderer that re-derives any of them will drift from the one that does not.
17
15
  */
18
16
  export const useLoginMethods = (opts?: UseLoginMethodsOptions): LoginMethodsModel => {
19
17
  const context = useContext() as unknown as LoginContext
@@ -23,12 +21,13 @@ export const useLoginMethods = (opts?: UseLoginMethodsOptions): LoginMethodsMode
23
21
  const cfg = opts?.config ?? (context.cfg as CommonConfig).security?.auth?.login
24
22
  const brand = (context.cfg as CommonConfig).brand
25
23
 
26
- const resolved = useMemo(() => resolveTerms(opts?.terms ?? cfg?.terms), [opts?.terms, cfg])
24
+ const resolved = useMemo(() => loginTermsHelper.resolveTerms(opts?.terms ?? cfg?.terms), [opts?.terms, cfg])
27
25
  const credit = useMemo(
28
26
  () => resolveCredit(cfg?.credit, brand, context.cfg.service), [cfg, brand, context]
29
27
  )
28
+ const provider = useMemo(() => loginProviderHelper.resolve(cfg?.provider, brand), [cfg, brand])
30
29
 
31
- const [accepted, setAccepted] = useState(() => termsAccepted(resolved))
30
+ const [accepted, setAccepted] = useState(() => loginTermsHelper.termsAccepted(resolved))
32
31
  const [attempted, setAttempted] = useState(false)
33
32
  const [busy, setBusy] = useState<string | null>(null)
34
33
  const [outcome, setOutcome] = useState<LoginOutcome | null>(null)
@@ -43,7 +42,7 @@ export const useLoginMethods = (opts?: UseLoginMethodsOptions): LoginMethodsMode
43
42
  ? opts.methods(all)
44
43
  : opts?.methods ?? all
45
44
 
46
- const deferred = termsDeferred(context)
45
+ const deferred = loginTermsHelper.termsDeferred(context)
47
46
  const blocked = resolved != null && resolved.required && !deferred && !accepted
48
47
 
49
48
  const select = useCallback((method: LoginMethod) => {
@@ -75,12 +74,12 @@ export const useLoginMethods = (opts?: UseLoginMethodsOptions): LoginMethodsMode
75
74
  const accept = useCallback((value: boolean) => {
76
75
  setAccepted(value)
77
76
  setAttempted(false)
78
- acceptTerms(resolved, value)
77
+ loginTermsHelper.acceptTerms(resolved, value)
79
78
  }, [resolved])
80
79
 
81
80
  return {
82
81
  methods,
83
- primary: primaryLoginMethod(methods),
82
+ primary: loginMethodsHelper.primaryLoginMethod(methods),
84
83
  terms: {
85
84
  required: resolved?.required ?? false,
86
85
  accepted: resolved == null ? true : accepted,
@@ -93,6 +92,7 @@ export const useLoginMethods = (opts?: UseLoginMethodsOptions): LoginMethodsMode
93
92
  accept,
94
93
  },
95
94
  credit,
95
+ provider,
96
96
  blocked,
97
97
  busy,
98
98
  outcome,
@@ -0,0 +1,2 @@
1
+ /** The names a provider sentence may carry, matched in one pass. */
2
+ export const PROVIDER_PLACEHOLDER = /\{\{(provider|operator|product)\}\}/g
@@ -0,0 +1,38 @@
1
+ import type { LoginProviderConfig } from './types.js'
2
+
3
+ /**
4
+ * `LoginScreenConfig.provider`, added by TypeScript module augmentation rather than by editing
5
+ * `@owlmeans/config` itself.
6
+ *
7
+ * `@owlmeans/config` has roughly 85 dependents, and every one of them sits in the same release
8
+ * closure — a config bump ripples through every package that pins a range against it, whether or
9
+ * not it touches sign-in. The field below is read by exactly one consumer family (the sign-in
10
+ * screen's headless model here and its renderers), so it is declared here instead, merged onto the
11
+ * base interface by TypeScript's own declaration merging — the pattern
12
+ * `@owlmeans/client-auth/login`'s `terms-config.ts` set.
13
+ *
14
+ * This file must be part of whatever a consumer's own compilation actually loads, or the merge
15
+ * never happens — an ambient augmentation applies only once the compiler has read the file that
16
+ * declares it. `@owlmeans/client-panel/auth`'s barrel re-exports this module for exactly that
17
+ * reason, so ANY import from `@owlmeans/client-panel/auth` pulls this augmentation into that
18
+ * program. An app that builds its `security.auth.login` literal in a file that imports nothing from
19
+ * it (a config file importing only `@owlmeans/config`) still benefits as long as some other file in
20
+ * the same `tsc` program does; if none does, add `import type {} from '@owlmeans/client-panel/auth'`
21
+ * to the file building the literal — an import with an empty type list, kept only to pull this
22
+ * file into that program's graph.
23
+ *
24
+ * `export {}` below is required, not decorative: without at least one top-level import/export this
25
+ * file is a SCRIPT to TypeScript, not a MODULE, and `declare module '@owlmeans/config'` inside a
26
+ * script augments the global scope instead of merging onto the named module's exports.
27
+ */
28
+ declare module '@owlmeans/config' {
29
+ interface LoginScreenConfig {
30
+ /**
31
+ * Who signs a person in on this application's behalf — an identity service the application
32
+ * does not itself run. Absent, the screen discloses nothing and renders exactly as before.
33
+ */
34
+ provider?: LoginProviderConfig
35
+ }
36
+ }
37
+
38
+ export { }
@@ -0,0 +1,65 @@
1
+ import type { BrandSettings } from '@owlmeans/config'
2
+ import type { LoginProviderConfig, LoginProviderHelper, LoginProviderModel } from './types.js'
3
+ import { PROVIDER_PLACEHOLDER } from './provider/consts.local.js'
4
+ import './provider-config.js'
5
+
6
+ export const createLoginProviderHelper = (): LoginProviderHelper => {
7
+ /**
8
+ * A configured value that was actually SET — `''` is how a build-time default spells "unset"
9
+ * (see `resolveCredit` in `@owlmeans/client-auth/login`, which follows the same rule).
10
+ */
11
+ const set = (value?: string | null): string | null =>
12
+ typeof value === 'string' && value.trim() !== '' ? value.trim() : null
13
+
14
+ /**
15
+ * A link a person may be sent to: an absolute http(s) URL, or a path on this origin.
16
+ *
17
+ * `//host` is protocol-relative — another origin wearing a path's clothes — and `/\` is read as
18
+ * the same by browsers, so both are refused along with every other scheme (`javascript:` above
19
+ * all, since this lands in an `href`).
20
+ */
21
+ const link = (value?: string | null): string | null => {
22
+ const href = set(value)
23
+ if (href == null) {
24
+ return null
25
+ }
26
+ if (href.startsWith('/')) {
27
+ return /^\/[/\\]/.test(href) ? null : href
28
+ }
29
+ try {
30
+ const url = new URL(href)
31
+
32
+ return url.protocol === 'https:' || url.protocol === 'http:' ? href : null
33
+ } catch {
34
+ return null
35
+ }
36
+ }
37
+
38
+ const resolve = (cfg?: LoginProviderConfig, brand?: BrandSettings): LoginProviderModel | null => {
39
+ const name = set(cfg?.name)
40
+ const product = set(brand?.name)
41
+ if (name == null || product == null) {
42
+ return null
43
+ }
44
+
45
+ return {
46
+ name,
47
+ operator: set(cfg?.operator) ?? name,
48
+ product,
49
+ info: link(cfg?.info),
50
+ placement: cfg?.placement === 'top' ? 'top' : 'inline',
51
+ }
52
+ }
53
+
54
+ const fill = (template: string, model: LoginProviderModel): string => {
55
+ const values: Record<string, string> = {
56
+ provider: model.name, operator: model.operator, product: model.product,
57
+ }
58
+
59
+ return template.replace(PROVIDER_PLACEHOLDER, (match, key: string) => values[key] ?? match)
60
+ }
61
+
62
+ return { resolve, fill }
63
+ }
64
+
65
+ export const loginProviderHelper = createLoginProviderHelper()
@@ -1,5 +1,5 @@
1
1
  import type { LoginMethod, LoginOutcome, ResolvedTermsDocument } from '@owlmeans/client-auth/login'
2
- import type { LoginScreenConfig, LoginTermsConfig } from '@owlmeans/config'
2
+ import type { BrandSettings, LoginScreenConfig, LoginTermsConfig } from '@owlmeans/config'
3
3
 
4
4
  export interface UseLoginMethodsOptions {
5
5
  /** Overrides the configuration the context carries. */
@@ -37,12 +37,63 @@ export interface LoginCreditModel {
37
37
  line: string | null
38
38
  }
39
39
 
40
+ /** Where the provider disclosure sits: a strip above the card, or a line inside it. */
41
+ export type LoginProviderPlacement = 'top' | 'inline'
42
+
43
+ /**
44
+ * Who actually signs a person in, when that is not the application on whose screen they are.
45
+ *
46
+ * Read from `cfg.security.auth.login.provider` (declared onto `LoginScreenConfig` by
47
+ * `./provider-config.ts`). Blank strings are unset, exactly as they are for the credit line: this
48
+ * config is filled from build-time environment variables, and an undelivered one arrives as `''`.
49
+ */
50
+ export interface LoginProviderConfig {
51
+ /** The sign-in service as a person reads it — "OwlMeans IAM". */
52
+ name: string
53
+ /** Who runs it. Defaults to `name`. */
54
+ operator?: string
55
+ /** "More information" — an absolute http(s) URL or a root-relative path; anything else is dropped. */
56
+ info?: string
57
+ /** Default `'inline'`. */
58
+ placement?: LoginProviderPlacement
59
+ }
60
+
61
+ export interface LoginProviderModel {
62
+ name: string
63
+ operator: string
64
+ /** The application the person is signing in to — `cfg.brand.name`. */
65
+ product: string
66
+ info: string | null
67
+ placement: LoginProviderPlacement
68
+ }
69
+
70
+ export interface LoginProviderHelper {
71
+ /**
72
+ * The disclosure a sign-in screen renders, or `null` when there is nothing to disclose.
73
+ *
74
+ * Null unless both the provider's `name` and the product (`brand.name`) are set — a sentence
75
+ * relating two parties cannot be written with one of them missing, and a screen that showed half
76
+ * of it would be worse than one that shows none.
77
+ */
78
+ resolve: (cfg?: LoginProviderConfig, brand?: BrandSettings) => LoginProviderModel | null
79
+ /**
80
+ * Put the names into a sentence AFTER it was translated.
81
+ *
82
+ * `{{provider}}`, `{{operator}}` and `{{product}}`, replaced in one pass — a name that itself
83
+ * contains a placeholder is never expanded a second time. The names never travel as i18next
84
+ * interpolation parameters, so no translation backend gets the chance to escape or format them.
85
+ */
86
+ fill: (template: string, model: LoginProviderModel) => string
87
+ }
88
+
40
89
  export interface LoginMethodsModel {
41
90
  methods: LoginMethod[]
42
91
  /** The one a screen highlights and focuses. It is never started automatically. */
43
92
  primary: LoginMethod | null
44
93
  terms: LoginTermsModel
45
94
  credit: LoginCreditModel
95
+ /** Who signs the person in, on behalf of which product — `null` when the app configured nobody. */
96
+ provider: LoginProviderModel | null
46
97
  /** True while the terms have not been confirmed and confirming them is required. */
47
98
  blocked: boolean
48
99
  /** Id of the method currently starting. */
@@ -4,25 +4,7 @@ import type { ClientEntrypoint } from '@owlmeans/client-entrypoint'
4
4
  import type { Location } from '@owlmeans/router'
5
5
  import { useContext, useNavigate } from '@owlmeans/client'
6
6
 
7
- import type { NavTranslate, PanelNavConfig, PanelNavItem, PanelNavModel, PanelNavSection } from './types.js'
8
-
9
- /** Default resolver: no i18n, the caller's fallback wins. See {@link NavTranslate}. */
10
- export const defaultNavTranslate: NavTranslate = (_key, defaultValue) => defaultValue
11
-
12
- /**
13
- * Turn an alias into something readable — `my-app:web:user-list` becomes `User list`.
14
- * The last segment is the meaningful one; the prefixes address the app, not the screen.
15
- */
16
- export const defaultNavLabel = (alias: string): string => {
17
- const segment = alias.split(/[:.]/).filter(part => part !== '').pop() ?? alias
18
- const words = segment.replace(/[-_]+/g, ' ').trim()
19
-
20
- return words.charAt(0).toUpperCase() + words.slice(1)
21
- }
22
-
23
- export const resolveNavLabel = (
24
- translate: NavTranslate, label: string | undefined, key: string, alias?: string
25
- ): string => label ?? translate(key, defaultNavLabel(alias ?? key))
7
+ import type { PanelNavConfig, PanelNavItem, PanelNavModel, PanelNavSection } from './types.js'
26
8
 
27
9
  const visibleItems = (section: PanelNavSection): PanelNavItem[] =>
28
10
  section.items.filter(item => item.hidden !== true)
@@ -1,3 +1,4 @@
1
1
  export type * from './types.js'
2
2
 
3
+ export * from './label.js'
3
4
  export * from './helper.js'
@@ -0,0 +1,20 @@
1
+ import type { NavLabelHelper, NavTranslate } from './types.js'
2
+
3
+ export const createNavLabelHelper = (): NavLabelHelper => {
4
+ const defaultNavTranslate: NavTranslate = (_key, defaultValue) => defaultValue
5
+
6
+ const defaultNavLabel = (alias: string): string => {
7
+ const segment = alias.split(/[:.]/).filter(part => part !== '').pop() ?? alias
8
+ const words = segment.replace(/[-_]+/g, ' ').trim()
9
+
10
+ return words.charAt(0).toUpperCase() + words.slice(1)
11
+ }
12
+
13
+ const resolveNavLabel = (
14
+ translate: NavTranslate, label: string | undefined, key: string, alias?: string
15
+ ): string => label ?? translate(key, defaultNavLabel(alias ?? key))
16
+
17
+ return { defaultNavTranslate, defaultNavLabel, resolveNavLabel }
18
+ }
19
+
20
+ export const navLabelHelper = createNavLabelHelper()
@@ -77,3 +77,16 @@ export interface PanelNavModel {
77
77
  */
78
78
  hrefOf: (target: PanelNavItem | PanelNavSection) => string | undefined
79
79
  }
80
+
81
+ /** How a navigation entry gets its label. */
82
+ export interface NavLabelHelper {
83
+ /** Default resolver: no i18n, the caller's fallback wins. See {@link NavTranslate}. */
84
+ defaultNavTranslate: NavTranslate
85
+ /**
86
+ * Turn an alias into something readable — `my-app:web:user-list` becomes `User list`.
87
+ * The last segment is the meaningful one; the prefixes address the app, not the screen.
88
+ */
89
+ defaultNavLabel: (alias: string) => string
90
+ /** The literal label when given, else the translation of `key` falling back to the humanized alias. */
91
+ resolveNavLabel: (translate: NavTranslate, label: string | undefined, key: string, alias?: string) => string
92
+ }
package/src/i18n.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { addI18nLib } from '@owlmeans/i18n'
1
+ import { i18nHelper } from '@owlmeans/i18n'
2
2
  import { buttons } from './consts.local.js'
3
3
 
4
4
  for (const [language, values] of Object.entries(buttons)) {
5
- addI18nLib(language, 'client-panel', values)
5
+ i18nHelper.addI18nLib(language, 'client-panel', values)
6
6
  }