@mintplayer/ng-spark-auth 22.2.1 → 22.6.0

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 (27) hide show
  1. package/fesm2022/mintplayer-ng-spark-auth-auth-bar.mjs +3 -3
  2. package/fesm2022/mintplayer-ng-spark-auth-core.mjs +6 -6
  3. package/fesm2022/mintplayer-ng-spark-auth-forgot-password.mjs +3 -3
  4. package/fesm2022/mintplayer-ng-spark-auth-login.mjs +4 -4
  5. package/fesm2022/mintplayer-ng-spark-auth-login.mjs.map +1 -1
  6. package/fesm2022/mintplayer-ng-spark-auth-models.mjs +2 -1
  7. package/fesm2022/mintplayer-ng-spark-auth-models.mjs.map +1 -1
  8. package/fesm2022/mintplayer-ng-spark-auth-pipes.mjs +3 -3
  9. package/fesm2022/mintplayer-ng-spark-auth-register.mjs +9 -5
  10. package/fesm2022/mintplayer-ng-spark-auth-register.mjs.map +1 -1
  11. package/fesm2022/mintplayer-ng-spark-auth-reset-password.mjs +3 -3
  12. package/fesm2022/mintplayer-ng-spark-auth-routes.mjs +122 -34
  13. package/fesm2022/mintplayer-ng-spark-auth-routes.mjs.map +1 -1
  14. package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs +82 -17
  15. package/fesm2022/mintplayer-ng-spark-auth-sign-in.mjs.map +1 -1
  16. package/fesm2022/mintplayer-ng-spark-auth-two-factor.mjs +3 -3
  17. package/fesm2022/mintplayer-ng-spark-auth.mjs +11 -3
  18. package/fesm2022/mintplayer-ng-spark-auth.mjs.map +1 -1
  19. package/package.json +2 -1
  20. package/types/mintplayer-ng-spark-auth-forgot-password.d.ts +1 -1
  21. package/types/mintplayer-ng-spark-auth-login.d.ts +1 -1
  22. package/types/mintplayer-ng-spark-auth-models.d.ts +32 -27
  23. package/types/mintplayer-ng-spark-auth-register.d.ts +1 -1
  24. package/types/mintplayer-ng-spark-auth-reset-password.d.ts +1 -1
  25. package/types/mintplayer-ng-spark-auth-routes.d.ts +82 -12
  26. package/types/mintplayer-ng-spark-auth-sign-in.d.ts +58 -7
  27. package/types/mintplayer-ng-spark-auth-two-factor.d.ts +1 -1
@@ -38,19 +38,9 @@ type SparkAuthRouteEntry = string | {
38
38
  path: string;
39
39
  component?: Type<unknown>;
40
40
  };
41
- /**
42
- * How much of the local-credential (email + password) page family to route.
43
- *
44
- * Mirrors the server's `SparkLocalCredentials`, and for the same reason it is a mode rather
45
- * than five independent switches: the pages form a star centred on the login page, and every
46
- * template dereferences its siblings' paths unconditionally, so removing any proper subset
47
- * leaves a dangling link. The family is the unit on both tiers.
48
- */
49
- type SparkLocalCredentialsMode = 'full' | 'sign-in-only' | 'disabled';
50
- /** The routable local-credential pages. Kept separate from {@link SparkAuthRouteConfig} so that
51
- * adding non-route options below cannot widen {@link SparkAuthRoutePaths}. */
41
+ /** The routable authentication pages. */
52
42
  interface SparkAuthRouteEntries {
53
- /** The provider-button landing page. Routed whenever local credentials are limited. */
43
+ /** The provider-button landing page, mounted by `withExternalLogin()`. */
54
44
  signIn?: SparkAuthRouteEntry;
55
45
  login?: SparkAuthRouteEntry;
56
46
  twoFactor?: SparkAuthRouteEntry;
@@ -58,21 +48,36 @@ interface SparkAuthRouteEntries {
58
48
  forgotPassword?: SparkAuthRouteEntry;
59
49
  resetPassword?: SparkAuthRouteEntry;
60
50
  }
61
- interface SparkAuthRouteConfig extends SparkAuthRouteEntries {
62
- /**
63
- * Defaults to `'full'`, which routes every page — the behaviour of every version before this
64
- * option existed. Set it to match the server's `LocalCredentials` mode; `GET /spark/auth/capabilities`
65
- * reports what the server is actually running.
66
- */
67
- localCredentials?: SparkLocalCredentialsMode;
68
- }
69
51
  /**
70
- * Every path is present regardless of mode. The pages that are dropped are dropped together, so no
71
- * surviving template can dereference a missing sibling — which is what lets this stay `Required`
72
- * and keeps the change additive for consumers.
52
+ * The paths of the pages that were actually mounted.
53
+ *
54
+ * Partial, and that is the change: pages are opted into individually now, so a template cannot
55
+ * assume its siblings exist. `login` links to `register` only when registration was opted into, and
56
+ * the sign-in landing page links to `login` only when local login was. A `[routerLink]` bound to
57
+ * `undefined` silently navigates to the current route, so every cross-feature link is guarded.
58
+ */
59
+ type SparkAuthRoutePaths = Partial<Record<keyof SparkAuthRouteEntries, string>>;
60
+ declare const SPARK_AUTH_ROUTE_PATHS: InjectionToken<Partial<Record<keyof SparkAuthRouteEntries, string>>>;
61
+ /**
62
+ * Presentation for one external provider's button — an icon, a label, an ordering.
63
+ *
64
+ * **It decorates; it does not declare.** The server stays authoritative over which providers exist
65
+ * (`GET /spark/auth/capabilities`), because letting the client declare them would reintroduce exactly
66
+ * the string-literal mismatch that endpoint exists to prevent. A scheme the server reports with no
67
+ * matching declaration falls back to the default button, so adding a provider server-side never
68
+ * yields a blank page; a declaration matching no reported scheme is simply unused.
73
69
  */
74
- type SparkAuthRoutePaths = Required<Record<keyof SparkAuthRouteEntries, string>>;
75
- declare const SPARK_AUTH_ROUTE_PATHS: InjectionToken<Required<Record<keyof SparkAuthRouteEntries, string>>>;
70
+ interface SparkExternalProviderPresentation {
71
+ /** The ASP.NET Core authentication scheme, as the server reports it. Matched case-insensitively. */
72
+ scheme: string;
73
+ /** Overrides the server's display name. */
74
+ displayName?: string;
75
+ /** A CSS class for an icon element rendered before the label. */
76
+ iconClass?: string;
77
+ /** Lower sorts first. Providers with no declared order keep the server's order, after declared ones. */
78
+ order?: number;
79
+ }
80
+ declare const SPARK_EXTERNAL_PROVIDERS: InjectionToken<SparkExternalProviderPresentation[]>;
76
81
 
77
82
  /**
78
83
  * Shared validator for `returnUrl` query parameters consumed by the auth
@@ -133,5 +138,5 @@ declare const SPARK_EXTERNAL_LOGIN_MESSAGE_TYPE = "spark:external-login";
133
138
  */
134
139
  declare function resolveSignInUrl(config: SparkAuthConfig, router: Router): string;
135
140
 
136
- export { SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, SPARK_EXTERNAL_LOGIN_MESSAGE_TYPE, defaultSparkAuthConfig, isSafeReturnUrl, resolveSignInUrl, sanitizeReturnUrl };
137
- export type { AuthUser, SparkAuthCapabilities, SparkAuthConfig, SparkAuthRouteConfig, SparkAuthRouteEntries, SparkAuthRouteEntry, SparkAuthRoutePaths, SparkExternalLoginError, SparkExternalLoginMessage, SparkExternalLoginMode, SparkExternalLoginOptions, SparkExternalLoginResult, SparkExternalProvider, SparkLocalCredentialsMode };
141
+ export { SPARK_AUTH_CONFIG, SPARK_AUTH_ROUTE_PATHS, SPARK_EXTERNAL_LOGIN_MESSAGE_TYPE, SPARK_EXTERNAL_PROVIDERS, defaultSparkAuthConfig, isSafeReturnUrl, resolveSignInUrl, sanitizeReturnUrl };
142
+ export type { AuthUser, SparkAuthCapabilities, SparkAuthConfig, SparkAuthRouteEntries, SparkAuthRouteEntry, SparkAuthRoutePaths, SparkExternalLoginError, SparkExternalLoginMessage, SparkExternalLoginMode, SparkExternalLoginOptions, SparkExternalLoginResult, SparkExternalProvider, SparkExternalProviderPresentation };
@@ -8,7 +8,7 @@ declare class SparkRegisterComponent {
8
8
  private readonly authService;
9
9
  private readonly router;
10
10
  private readonly translation;
11
- readonly routePaths: Required<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
11
+ readonly routePaths: Partial<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
12
12
  colors: typeof Color;
13
13
  readonly loading: _angular_core.WritableSignal<boolean>;
14
14
  readonly errorMessage: _angular_core.WritableSignal<string>;
@@ -10,7 +10,7 @@ declare class SparkResetPasswordComponent implements OnInit {
10
10
  private readonly router;
11
11
  private readonly route;
12
12
  private readonly translation;
13
- readonly routePaths: Required<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
13
+ readonly routePaths: Partial<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
14
14
  colors: typeof Color;
15
15
  readonly loading: _angular_core.WritableSignal<boolean>;
16
16
  readonly errorMessage: _angular_core.WritableSignal<string>;
@@ -1,20 +1,90 @@
1
- import { SparkAuthRouteConfig } from '@mintplayer/ng-spark-auth/models';
1
+ import { SparkAuthRoutePaths, SparkExternalProviderPresentation, SparkAuthRouteEntries, SparkAuthRouteEntry } from '@mintplayer/ng-spark-auth/models';
2
2
 
3
+ type Loader = () => Promise<any>;
4
+ interface Child {
5
+ path: string;
6
+ loadComponent: Loader;
7
+ }
8
+ /**
9
+ * One opt-in group of authentication pages. Produced by `withLocalLogin()`, `withRegistration()` and
10
+ * `withExternalLogin()`; not constructible by consumers, which is what keeps the set of mountable
11
+ * pages a decision this library makes rather than a shape an application can invent.
12
+ */
13
+ interface SparkAuthRoutesFeature {
14
+ readonly children: Child[];
15
+ readonly paths: SparkAuthRoutePaths;
16
+ readonly providers?: SparkExternalProviderPresentation[];
17
+ }
18
+ /** Path override for the sign-in landing page. Named to stay clear of the core package's
19
+ * `SparkExternalLoginOptions`, which is about the sign-in *call* rather than the route. */
20
+ type SparkExternalLoginRouteOptions = Pick<SparkAuthRouteEntries, 'signIn'>;
3
21
  /**
4
22
  * The routes for Spark's authentication pages.
5
23
  *
6
- * `config.localCredentials` chooses how much of the email/password family to route, mirroring the
7
- * server's `SparkLocalCredentials`. `GET /spark/auth/capabilities` reports what the server is
8
- * actually running, so the two can be checked against each other.
24
+ * **Nothing is mounted unless a feature asks for it.** Passing no features emits no pages at all —
25
+ * opt-in enforced by construction rather than by a flag, matching `provideHttpClient(withFetch())`
26
+ * and `provideRouter(withComponentInputBinding())`. Before this the pages mounted by default and an
27
+ * application had to opt *out*, so every app shipped a registration form whether or not it wanted
28
+ * one.
29
+ *
30
+ * ```ts
31
+ * sparkAuthRoutes(
32
+ * withLocalLogin(),
33
+ * withRegistration(),
34
+ * withExternalLogin(githubProvider(), facebookProvider()),
35
+ * )
36
+ * ```
37
+ *
38
+ * The `import()` expressions live *inside* each feature. That placement is the point: a bundler
39
+ * decides whether to emit a lazy chunk from whether the `import()` call site is reachable, not from
40
+ * whether the route object referencing it survives — so filtering a children array after the fact
41
+ * would still ship every page. A page nobody opted into has no reachable `import()` at all.
42
+ */
43
+ declare function sparkAuthRoutes(...features: SparkAuthRoutesFeature[]): any[];
44
+ /**
45
+ * Mounts the email/password family: login, two-factor, forgot-password, reset-password.
46
+ *
47
+ * These four are one feature rather than four because they form a star centred on the login page and
48
+ * every template dereferences its siblings unconditionally — removing any proper subset leaves a
49
+ * dangling link. Registration is genuinely separable, and is its own feature.
50
+ *
51
+ * Two-factor belongs here because it is reachable only from the login page's `RequiresTwoFactor`
52
+ * branch and posts to the same `/login` endpoint: it is part of password sign-in, not of
53
+ * authentication in general.
54
+ */
55
+ declare function withLocalLogin(entries?: Pick<SparkAuthRouteEntries, 'login' | 'twoFactor' | 'forgotPassword' | 'resetPassword'>): SparkAuthRoutesFeature;
56
+ /**
57
+ * Mounts the self-service registration page.
58
+ *
59
+ * Separate from {@link withLocalLogin} because the two decisions genuinely are separate: an
60
+ * application whose accounts are provisioned by an administrator still needs password sign-in and
61
+ * password reset. Mount it only alongside a server whose `SparkLocalCredentials` is `Full` — with
62
+ * `SignInOnly` the endpoint it posts to is not mapped.
63
+ */
64
+ declare function withRegistration(entry?: SparkAuthRouteEntry): SparkAuthRoutesFeature;
65
+ /**
66
+ * Mounts the sign-in landing page — a button per external provider the *server* reports.
67
+ *
68
+ * Accepts provider declarations and, in any position, one options object for the page's own path;
69
+ * the two shapes are disjoint, so `withExternalLogin(githubProvider(), facebookProvider())` and
70
+ * `withExternalLogin({ signIn: 'landing' }, githubProvider())` both read naturally.
9
71
  *
10
- * The `import()` expressions live *inside* the branches that need them. That placement is the point:
11
- * a bundler decides whether to emit a lazy chunk from whether the `import()` call site is reachable,
12
- * not from whether the route object referencing it survives — so filtering the children array after
13
- * the fact would still ship every page. Excluded pages must have no reachable `import()` at all.
72
+ * Declaring no providers is valid and useful: the page still renders whatever
73
+ * `GET /spark/auth/capabilities` reports, using default buttons.
74
+ */
75
+ declare function withExternalLogin(...providersOrOptions: (SparkExternalProviderPresentation | SparkExternalLoginRouteOptions)[]): SparkAuthRoutesFeature;
76
+ /**
77
+ * Presentation for one provider's button, keyed by the scheme the server reports.
14
78
  *
15
- * `SPARK_AUTH_ROUTE_PATHS` is still provided in full. The excluded pages are excluded together, so
16
- * nothing that survives can link to something that does not, and the token stays `Required`.
79
+ * The generic form. `githubProvider()` and friends are this with a scheme and an icon filled in —
80
+ * they exist so the common case does not require knowing the scheme string, not because the library
81
+ * has an opinion about which providers exist.
17
82
  */
18
- declare function sparkAuthRoutes(config?: SparkAuthRouteConfig): any[];
83
+ declare function externalProvider(scheme: string, presentation?: Omit<SparkExternalProviderPresentation, 'scheme'>): SparkExternalProviderPresentation;
84
+ declare function githubProvider(presentation?: Omit<SparkExternalProviderPresentation, 'scheme'>): SparkExternalProviderPresentation;
85
+ declare function googleProvider(presentation?: Omit<SparkExternalProviderPresentation, 'scheme'>): SparkExternalProviderPresentation;
86
+ declare function facebookProvider(presentation?: Omit<SparkExternalProviderPresentation, 'scheme'>): SparkExternalProviderPresentation;
87
+ declare function microsoftProvider(presentation?: Omit<SparkExternalProviderPresentation, 'scheme'>): SparkExternalProviderPresentation;
19
88
 
20
- export { sparkAuthRoutes };
89
+ export { externalProvider, facebookProvider, githubProvider, googleProvider, microsoftProvider, sparkAuthRoutes, withExternalLogin, withLocalLogin, withRegistration };
90
+ export type { SparkAuthRoutesFeature, SparkExternalLoginRouteOptions };
@@ -1,25 +1,73 @@
1
1
  import * as _angular_core from '@angular/core';
2
+ import { TemplateRef } from '@angular/core';
2
3
  import * as _mintplayer_ng_spark_auth_models from '@mintplayer/ng-spark-auth/models';
3
4
  import { SparkExternalProvider } from '@mintplayer/ng-spark-auth/models';
4
5
  import { Color } from '@mintplayer/ng-bootstrap';
5
6
 
6
7
  /**
7
- * The sign-in landing page for an application whose local credentials are turned off a button per
8
- * external provider, and a link to the password form when there still is one.
8
+ * One provider's button, as the template sees it: the provider itself, and the call that signs in
9
+ * with it.
10
+ *
11
+ * **Passing the closure is the point.** A consumer never touches `provider.scheme`, so the failure
12
+ * this component exists to prevent — a hard-coded scheme string that silently stops matching when
13
+ * the server's registration changes — is unreachable by construction. It also means busy state,
14
+ * `returnUrl` handling and popup-versus-redirect can move behind `signIn` later without a
15
+ * consumer-facing change.
16
+ */
17
+ interface SparkProviderButtonContext {
18
+ $implicit: SparkExternalProviderView;
19
+ signIn: () => void;
20
+ }
21
+ /** A provider the server reported, merged with whatever presentation the app declared for it. */
22
+ interface SparkExternalProviderView extends SparkExternalProvider {
23
+ iconClass?: string;
24
+ }
25
+ /**
26
+ * The sign-in landing page: a button per external provider, and a link to the password form when the
27
+ * application mounted one.
9
28
  *
10
29
  * The providers come from `GET /spark/auth/capabilities` rather than from a list the application
11
30
  * hard-codes. That is the point of the component: every consumer that hand-rolled this before wrote
12
31
  * the scheme name as a string literal, which is a silent mismatch waiting to happen the moment the
13
- * server's provider registration changes.
32
+ * server's provider registration changes. A `withExternalLogin(githubProvider())` declaration only
33
+ * *decorates* what the server reports — it cannot conjure a provider the server does not have.
14
34
  */
15
35
  declare class SparkSignInComponent {
16
36
  private readonly authService;
17
- readonly routePaths: Required<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
37
+ private readonly declaredProviders;
38
+ private readonly route;
39
+ readonly routePaths: Partial<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
18
40
  readonly colors: typeof Color;
19
- readonly providers: _angular_core.WritableSignal<SparkExternalProvider[]>;
41
+ /**
42
+ * Where to land after a successful external sign-in.
43
+ *
44
+ * Falls back to a `?returnUrl=` query parameter, matching what the login page already does — so a
45
+ * plain `<a routerLink="/sign-in" [queryParams]="{ returnUrl: '/somewhere' }">` works with no
46
+ * wiring, which is what a routed page needs since the router passes it no inputs. The query value
47
+ * is validated as a local path before use; an off-site one is dropped rather than followed.
48
+ */
49
+ readonly returnUrl: _angular_core.InputSignal<string | undefined>;
50
+ private effectiveReturnUrl;
51
+ /**
52
+ * Replaces the default provider button. Rendered once per provider with a
53
+ * {@link SparkProviderButtonContext}.
54
+ *
55
+ * Reachable only when the consumer *hosts* this component — the router instantiates it with no
56
+ * projected content, so on a default `withExternalLogin()` route there is nothing to project into.
57
+ * Host it via `withExternalLogin({ signIn: { path: 'sign-in', component: MySignIn } })` and pass
58
+ * the template from there.
59
+ */
60
+ readonly providerTemplate: _angular_core.InputSignal<TemplateRef<SparkProviderButtonContext> | null>;
61
+ private readonly reported;
20
62
  readonly localCredentialsAvailable: _angular_core.WritableSignal<boolean>;
21
63
  readonly loading: _angular_core.WritableSignal<boolean>;
22
64
  readonly failed: _angular_core.WritableSignal<boolean>;
65
+ /**
66
+ * The server's list, decorated and ordered by whatever the application declared. Declared-but-not-
67
+ * reported schemes are dropped and reported-but-not-declared ones keep a default button, so
68
+ * neither side can produce a provider the other does not have.
69
+ */
70
+ readonly providers: _angular_core.Signal<SparkExternalProviderView[]>;
23
71
  constructor();
24
72
  private load;
25
73
  /**
@@ -28,9 +76,12 @@ declare class SparkSignInComponent {
28
76
  * which it only does when local credentials are meant to be limited.
29
77
  */
30
78
  private warnOnMismatch;
31
- signInWith(provider: SparkExternalProvider): void;
79
+ /** The closure handed to a projected template, so a consumer never names a scheme itself. */
80
+ contextFor(provider: SparkExternalProviderView): SparkProviderButtonContext;
81
+ signInWith(provider: SparkExternalProviderView): void;
32
82
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<SparkSignInComponent, never>;
33
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkSignInComponent, "spark-sign-in", never, {}, {}, never, never, true, never>;
83
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SparkSignInComponent, "spark-sign-in", never, { "returnUrl": { "alias": "returnUrl"; "required": false; "isSignal": true; }; "providerTemplate": { "alias": "providerTemplate"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
34
84
  }
35
85
 
36
86
  export { SparkSignInComponent };
87
+ export type { SparkExternalProviderView, SparkProviderButtonContext };
@@ -10,7 +10,7 @@ declare class SparkTwoFactorComponent {
10
10
  private readonly route;
11
11
  private readonly config;
12
12
  private readonly translation;
13
- readonly routePaths: Required<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
13
+ readonly routePaths: Partial<Record<keyof _mintplayer_ng_spark_auth_models.SparkAuthRouteEntries, string>>;
14
14
  colors: typeof Color;
15
15
  readonly loading: _angular_core.WritableSignal<boolean>;
16
16
  readonly errorMessage: _angular_core.WritableSignal<string>;