@memberjunction/ng-auth-services 6.1.4 → 6.2.0-edge.1

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 (45) hide show
  1. package/dist/lib/AngularAuthProviderFactory.d.ts +12 -0
  2. package/dist/lib/AngularAuthProviderFactory.d.ts.map +1 -1
  3. package/dist/lib/AngularAuthProviderFactory.js +31 -7
  4. package/dist/lib/AngularAuthProviderFactory.js.map +1 -1
  5. package/dist/lib/IAuthProvider.js.map +1 -1
  6. package/dist/lib/auth-services.module.d.ts +2 -0
  7. package/dist/lib/auth-services.module.d.ts.map +1 -1
  8. package/dist/lib/auth-services.module.js +7 -3
  9. package/dist/lib/auth-services.module.js.map +1 -1
  10. package/dist/lib/catalog-environment.d.ts +4 -0
  11. package/dist/lib/catalog-environment.d.ts.map +1 -1
  12. package/dist/lib/catalog-environment.js +11 -3
  13. package/dist/lib/catalog-environment.js.map +1 -1
  14. package/dist/lib/login-picker.component.d.ts.map +1 -1
  15. package/dist/lib/login-picker.component.js +3 -3
  16. package/dist/lib/login-picker.component.js.map +1 -1
  17. package/dist/lib/providers/mjexplorer-auth0-provider.service.d.ts +11 -3
  18. package/dist/lib/providers/mjexplorer-auth0-provider.service.d.ts.map +1 -1
  19. package/dist/lib/providers/mjexplorer-auth0-provider.service.js +32 -16
  20. package/dist/lib/providers/mjexplorer-auth0-provider.service.js.map +1 -1
  21. package/dist/lib/providers/mjexplorer-cognito-provider.service.d.ts +11 -1
  22. package/dist/lib/providers/mjexplorer-cognito-provider.service.d.ts.map +1 -1
  23. package/dist/lib/providers/mjexplorer-cognito-provider.service.js +9 -1
  24. package/dist/lib/providers/mjexplorer-cognito-provider.service.js.map +1 -1
  25. package/dist/lib/providers/mjexplorer-magic-link-provider.service.d.ts +2 -0
  26. package/dist/lib/providers/mjexplorer-magic-link-provider.service.d.ts.map +1 -1
  27. package/dist/lib/providers/mjexplorer-magic-link-provider.service.js +5 -1
  28. package/dist/lib/providers/mjexplorer-magic-link-provider.service.js.map +1 -1
  29. package/dist/lib/providers/mjexplorer-msal-provider.service.d.ts +49 -3
  30. package/dist/lib/providers/mjexplorer-msal-provider.service.d.ts.map +1 -1
  31. package/dist/lib/providers/mjexplorer-msal-provider.service.js +41 -25
  32. package/dist/lib/providers/mjexplorer-msal-provider.service.js.map +1 -1
  33. package/dist/lib/providers/mjexplorer-okta-provider.service.d.ts +23 -1
  34. package/dist/lib/providers/mjexplorer-okta-provider.service.d.ts.map +1 -1
  35. package/dist/lib/providers/mjexplorer-okta-provider.service.js +9 -1
  36. package/dist/lib/providers/mjexplorer-okta-provider.service.js.map +1 -1
  37. package/dist/lib/providers/mjexplorer-workos-provider.service.d.ts +21 -1
  38. package/dist/lib/providers/mjexplorer-workos-provider.service.d.ts.map +1 -1
  39. package/dist/lib/providers/mjexplorer-workos-provider.service.js +9 -1
  40. package/dist/lib/providers/mjexplorer-workos-provider.service.js.map +1 -1
  41. package/dist/lib/redirect.component.d.ts +5 -1
  42. package/dist/lib/redirect.component.d.ts.map +1 -1
  43. package/dist/lib/redirect.component.js +11 -3
  44. package/dist/lib/redirect.component.js.map +1 -1
  45. package/package.json +4 -4
@@ -18,27 +18,39 @@ export declare class AngularAuthProviderFactory {
18
18
  /**
19
19
  * Create a provider based on configuration
20
20
  */
21
+ CreateProvider(config: AngularAuthProviderConfig): IAngularAuthProvider;
22
+ /** @deprecated Use {@link CreateProvider}. */
21
23
  createProvider(config: AngularAuthProviderConfig): IAngularAuthProvider;
22
24
  /**
23
25
  * Get a provider by type
24
26
  */
27
+ GetProvider(type: string): IAngularAuthProvider | undefined;
28
+ /** @deprecated Use {@link GetProvider}. */
25
29
  getProvider(type: string): IAngularAuthProvider | undefined;
26
30
  /**
27
31
  * Get all registered provider types
28
32
  */
33
+ GetRegisteredTypes(): string[];
34
+ /** @deprecated Use {@link GetRegisteredTypes}. */
29
35
  getRegisteredTypes(): string[];
30
36
  /**
31
37
  * Check if a provider type is registered
32
38
  */
39
+ IsTypeRegistered(type: string): boolean;
40
+ /** @deprecated Use {@link IsTypeRegistered}. */
33
41
  isTypeRegistered(type: string): boolean;
34
42
  /**
35
43
  * Clear all providers (useful for testing)
36
44
  */
45
+ ClearProviders(): void;
46
+ /** @deprecated Use {@link ClearProviders}. */
37
47
  clearProviders(): void;
38
48
  /**
39
49
  * Get provider-specific Angular services that need to be injected
40
50
  * This uses the static angularProviderFactory property on each provider class for extensibility
41
51
  */
52
+ static GetProviderAngularServices(type: string, environment: any): any[];
53
+ /** @deprecated Use {@link GetProviderAngularServices}. */
42
54
  static getProviderAngularServices(type: string, environment: any): any[];
43
55
  static ɵfac: i0.ɵɵFactoryDeclaration<AngularAuthProviderFactory, never>;
44
56
  static ɵprov: i0.ɵɵInjectableDeclaration<AngularAuthProviderFactory>;
@@ -1 +1 @@
1
- {"version":3,"file":"AngularAuthProviderFactory.d.ts","sourceRoot":"","sources":["../../src/lib/AngularAuthProviderFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGrD,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;;AAElF;;;GAGG;AACH,qBAGa,0BAA0B;IAKzB,OAAO,CAAC,QAAQ;IAJ5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAA8C;IACrF,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,eAAe,CAA+B;gBAElC,QAAQ,EAAE,QAAQ;IAQtC;;OAEG;IACH,WAAkB,QAAQ,IAAI,0BAA0B,CAMvD;IAED;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,yBAAyB,GAAG,oBAAoB;IAoCvE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAI3D;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAO9B;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIvC;;OAEG;IACH,cAAc,IAAI,IAAI;IAKtB;;;OAGG;IACH,MAAM,CAAC,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,GAAG,EAAE;yCAnG7D,0BAA0B;6CAA1B,0BAA0B;CAoItC"}
1
+ {"version":3,"file":"AngularAuthProviderFactory.d.ts","sourceRoot":"","sources":["../../src/lib/AngularAuthProviderFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGrD,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;;AAElF;;;GAGG;AACH,qBAGa,0BAA0B;IAKzB,OAAO,CAAC,QAAQ;IAJ5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAA8C;IACrF,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,eAAe,CAA+B;gBAElC,QAAQ,EAAE,QAAQ;IAQtC;;OAEG;IACH,WAAkB,QAAQ,IAAI,0BAA0B,CAMvD;IAED;;OAEG;IACH,cAAc,CAAC,MAAM,EAAE,yBAAyB,GAAG,oBAAoB;IAoCvE,8CAA8C;IAC9C,cAAc,CAAC,MAAM,EAAE,yBAAyB,GAAG,oBAAoB;IAIvE;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAI3D,2CAA2C;IAC3C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAI3D;;OAEG;IACH,kBAAkB,IAAI,MAAM,EAAE;IAO9B,kDAAkD;IAClD,kBAAkB,IAAI,MAAM,EAAE;IAI9B;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIvC,gDAAgD;IAChD,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIvC;;OAEG;IACH,cAAc,IAAI,IAAI;IAKtB,8CAA8C;IAC9C,cAAc,IAAI,IAAI;IAItB;;;OAGG;IACH,MAAM,CAAC,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,GAAG,EAAE;IAiCxE,0DAA0D;IAC1D,MAAM,CAAC,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,GAAG,EAAE;yCA9J7D,0BAA0B;6CAA1B,0BAA0B;CAkKtC"}
@@ -32,7 +32,7 @@ export class AngularAuthProviderFactory {
32
32
  /**
33
33
  * Create a provider based on configuration
34
34
  */
35
- createProvider(config) {
35
+ CreateProvider(config) {
36
36
  const existingProvider = this.providers.get(config.type);
37
37
  if (existingProvider) {
38
38
  return existingProvider;
@@ -43,7 +43,7 @@ export class AngularAuthProviderFactory {
43
43
  const provider = MJGlobal.Instance.ClassFactory.CreateInstance(MJAuthBase, config.type, config // Pass config as constructor argument, not injector
44
44
  );
45
45
  if (!provider) {
46
- throw new Error(`No provider registered for type: ${config.type}. Available types: ${this.getRegisteredTypes().join(', ')}`);
46
+ throw new Error(`No provider registered for type: ${config.type}. Available types: ${this.GetRegisteredTypes().join(', ')}`);
47
47
  }
48
48
  // Validate the configuration
49
49
  if (!provider.validateConfig(config)) {
@@ -59,39 +59,59 @@ export class AngularAuthProviderFactory {
59
59
  throw error;
60
60
  }
61
61
  }
62
+ /** @deprecated Use {@link CreateProvider}. */
63
+ createProvider(config) {
64
+ return this.CreateProvider(config);
65
+ }
62
66
  /**
63
67
  * Get a provider by type
64
68
  */
65
- getProvider(type) {
69
+ GetProvider(type) {
66
70
  return this.providers.get(type);
67
71
  }
72
+ /** @deprecated Use {@link GetProvider}. */
73
+ getProvider(type) {
74
+ return this.GetProvider(type);
75
+ }
68
76
  /**
69
77
  * Get all registered provider types
70
78
  */
71
- getRegisteredTypes() {
79
+ GetRegisteredTypes() {
72
80
  const registrations = MJGlobal.Instance.ClassFactory.GetRegistrationsByRootClass(MJAuthBase);
73
81
  const types = registrations.map(reg => reg.Key).filter((key) => key !== null);
74
82
  // Return unique types only, as multiple classes can be registered with the same key
75
83
  return [...new Set(types)];
76
84
  }
85
+ /** @deprecated Use {@link GetRegisteredTypes}. */
86
+ getRegisteredTypes() {
87
+ return this.GetRegisteredTypes();
88
+ }
77
89
  /**
78
90
  * Check if a provider type is registered
79
91
  */
92
+ IsTypeRegistered(type) {
93
+ return this.GetRegisteredTypes().includes(type);
94
+ }
95
+ /** @deprecated Use {@link IsTypeRegistered}. */
80
96
  isTypeRegistered(type) {
81
- return this.getRegisteredTypes().includes(type);
97
+ return this.IsTypeRegistered(type);
82
98
  }
83
99
  /**
84
100
  * Clear all providers (useful for testing)
85
101
  */
86
- clearProviders() {
102
+ ClearProviders() {
87
103
  this.providers.clear();
88
104
  this.providerConfigs.clear();
89
105
  }
106
+ /** @deprecated Use {@link ClearProviders}. */
107
+ clearProviders() {
108
+ return this.ClearProviders();
109
+ }
90
110
  /**
91
111
  * Get provider-specific Angular services that need to be injected
92
112
  * This uses the static angularProviderFactory property on each provider class for extensibility
93
113
  */
94
- static getProviderAngularServices(type, environment) {
114
+ static GetProviderAngularServices(type, environment) {
95
115
  const normalizedType = type?.toLowerCase();
96
116
  // Get the provider class from the ClassFactory
97
117
  const registration = MJGlobal.Instance.ClassFactory.GetRegistration(MJAuthBase, normalizedType);
@@ -116,6 +136,10 @@ export class AngularAuthProviderFactory {
116
136
  return [];
117
137
  }
118
138
  }
139
+ /** @deprecated Use {@link GetProviderAngularServices}. */
140
+ static getProviderAngularServices(type, environment) {
141
+ return this.GetProviderAngularServices(type, environment);
142
+ }
119
143
  static ɵfac = function AngularAuthProviderFactory_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AngularAuthProviderFactory)(i0.ɵɵinject(i0.Injector)); };
120
144
  static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: AngularAuthProviderFactory, factory: AngularAuthProviderFactory.ɵfac, providedIn: 'root' });
121
145
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AngularAuthProviderFactory.js","sourceRoot":"","sources":["../../src/lib/AngularAuthProviderFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Injector } from '@angular/core';\nimport { MJGlobal, GetGlobalObjectStore } from '@memberjunction/global';\nimport { MJAuthBase } from './mjexplorer-auth-base.service';\nimport { IAngularAuthProvider, AngularAuthProviderConfig } from './IAuthProvider';\n\n/**\n * Factory for creating Angular authentication providers\n * Uses MJGlobal ClassFactory pattern for extensibility\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class AngularAuthProviderFactory {\n private static readonly _globalStoreKey = '___SINGLETON__AngularAuthProviderFactory';\n private providers: Map<string, IAngularAuthProvider> = new Map();\n private providerConfigs: Map<string, any> = new Map();\n\n constructor(private injector: Injector) {\n const g = GetGlobalObjectStore()!;\n if (g[AngularAuthProviderFactory._globalStoreKey]) {\n return g[AngularAuthProviderFactory._globalStoreKey] as AngularAuthProviderFactory;\n }\n g[AngularAuthProviderFactory._globalStoreKey] = this;\n }\n\n /**\n * Get singleton instance\n */\n public static get Instance(): AngularAuthProviderFactory {\n const instance = GetGlobalObjectStore()![AngularAuthProviderFactory._globalStoreKey] as AngularAuthProviderFactory;\n if (!instance) {\n throw new Error('AngularAuthProviderFactory not initialized. Ensure it is provided in your module.');\n }\n return instance;\n }\n\n /**\n * Create a provider based on configuration\n */\n createProvider(config: AngularAuthProviderConfig): IAngularAuthProvider {\n \n const existingProvider = this.providers.get(config.type);\n if (existingProvider) {\n return existingProvider;\n }\n\n try {\n // Use MJGlobal ClassFactory to create the provider instance\n // Pass config as the first constructor argument\n const provider = MJGlobal.Instance.ClassFactory.CreateInstance<MJAuthBase>(\n MJAuthBase, \n config.type,\n config // Pass config as constructor argument, not injector\n );\n\n if (!provider) {\n throw new Error(`No provider registered for type: ${config.type}. Available types: ${this.getRegisteredTypes().join(', ')}`);\n }\n\n // Validate the configuration\n if (!provider.validateConfig(config)) {\n throw new Error(`Invalid configuration for provider type: ${config.type}`);\n }\n\n // Store the provider instance\n this.providers.set(config.type, provider);\n this.providerConfigs.set(config.type, config);\n\n return provider;\n } catch (error) {\n console.error(`Failed to create auth provider for type ${config.type}:`, error);\n throw error;\n }\n }\n\n /**\n * Get a provider by type\n */\n getProvider(type: string): IAngularAuthProvider | undefined {\n return this.providers.get(type);\n }\n\n /**\n * Get all registered provider types\n */\n getRegisteredTypes(): string[] {\n const registrations = MJGlobal.Instance.ClassFactory.GetRegistrationsByRootClass(MJAuthBase);\n const types = registrations.map(reg => reg.Key).filter((key): key is string => key !== null);\n // Return unique types only, as multiple classes can be registered with the same key\n return [...new Set(types)];\n }\n\n /**\n * Check if a provider type is registered\n */\n isTypeRegistered(type: string): boolean {\n return this.getRegisteredTypes().includes(type);\n }\n\n /**\n * Clear all providers (useful for testing)\n */\n clearProviders(): void {\n this.providers.clear();\n this.providerConfigs.clear();\n }\n\n /**\n * Get provider-specific Angular services that need to be injected\n * This uses the static angularProviderFactory property on each provider class for extensibility\n */\n static getProviderAngularServices(type: string, environment: any): any[] {\n \n const normalizedType = type?.toLowerCase();\n \n // Get the provider class from the ClassFactory\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(\n MJAuthBase, \n normalizedType\n );\n const providerClass = registration?.SubClass as any;\n \n if (!providerClass) {\n console.warn(`No provider class registered for type: ${type}`);\n return [];\n }\n \n // Check if the provider class has the factory property (new pattern)\n if (providerClass.angularProviderFactory) {\n // Call the factory function to get the required providers\n const services = providerClass.angularProviderFactory(environment);\n return services;\n } \n // Fallback to old method name for backward compatibility\n else if (typeof providerClass.getRequiredAngularProviders === 'function') {\n console.warn(`Provider ${type} uses deprecated getRequiredAngularProviders method. Please update to use angularProviderFactory property.`);\n return providerClass.getRequiredAngularProviders(environment);\n } \n else {\n // Provider doesn't define required Angular services (might not need any)\n return [];\n }\n }\n\n}"]}
1
+ {"version":3,"file":"AngularAuthProviderFactory.js","sourceRoot":"","sources":["../../src/lib/AngularAuthProviderFactory.ts"],"names":[],"mappings":"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","sourcesContent":["import { Injectable, Injector } from '@angular/core';\nimport { MJGlobal, GetGlobalObjectStore } from '@memberjunction/global';\nimport { MJAuthBase } from './mjexplorer-auth-base.service';\nimport { IAngularAuthProvider, AngularAuthProviderConfig } from './IAuthProvider';\n\n/**\n * Factory for creating Angular authentication providers\n * Uses MJGlobal ClassFactory pattern for extensibility\n */\n@Injectable({\n providedIn: 'root'\n})\nexport class AngularAuthProviderFactory {\n private static readonly _globalStoreKey = '___SINGLETON__AngularAuthProviderFactory';\n private providers: Map<string, IAngularAuthProvider> = new Map();\n private providerConfigs: Map<string, any> = new Map();\n\n constructor(private injector: Injector) {\n const g = GetGlobalObjectStore()!;\n if (g[AngularAuthProviderFactory._globalStoreKey]) {\n return g[AngularAuthProviderFactory._globalStoreKey] as AngularAuthProviderFactory;\n }\n g[AngularAuthProviderFactory._globalStoreKey] = this;\n }\n\n /**\n * Get singleton instance\n */\n public static get Instance(): AngularAuthProviderFactory {\n const instance = GetGlobalObjectStore()![AngularAuthProviderFactory._globalStoreKey] as AngularAuthProviderFactory;\n if (!instance) {\n throw new Error('AngularAuthProviderFactory not initialized. Ensure it is provided in your module.');\n }\n return instance;\n }\n\n /**\n * Create a provider based on configuration\n */\n CreateProvider(config: AngularAuthProviderConfig): IAngularAuthProvider {\n \n const existingProvider = this.providers.get(config.type);\n if (existingProvider) {\n return existingProvider;\n }\n\n try {\n // Use MJGlobal ClassFactory to create the provider instance\n // Pass config as the first constructor argument\n const provider = MJGlobal.Instance.ClassFactory.CreateInstance<MJAuthBase>(\n MJAuthBase, \n config.type,\n config // Pass config as constructor argument, not injector\n );\n\n if (!provider) {\n throw new Error(`No provider registered for type: ${config.type}. Available types: ${this.GetRegisteredTypes().join(', ')}`);\n }\n\n // Validate the configuration\n if (!provider.validateConfig(config)) {\n throw new Error(`Invalid configuration for provider type: ${config.type}`);\n }\n\n // Store the provider instance\n this.providers.set(config.type, provider);\n this.providerConfigs.set(config.type, config);\n\n return provider;\n } catch (error) {\n console.error(`Failed to create auth provider for type ${config.type}:`, error);\n throw error;\n }\n }\n\n /** @deprecated Use {@link CreateProvider}. */\n createProvider(config: AngularAuthProviderConfig): IAngularAuthProvider {\n return this.CreateProvider(config);\n }\n\n /**\n * Get a provider by type\n */\n GetProvider(type: string): IAngularAuthProvider | undefined {\n return this.providers.get(type);\n }\n\n /** @deprecated Use {@link GetProvider}. */\n getProvider(type: string): IAngularAuthProvider | undefined {\n return this.GetProvider(type);\n }\n\n /**\n * Get all registered provider types\n */\n GetRegisteredTypes(): string[] {\n const registrations = MJGlobal.Instance.ClassFactory.GetRegistrationsByRootClass(MJAuthBase);\n const types = registrations.map(reg => reg.Key).filter((key): key is string => key !== null);\n // Return unique types only, as multiple classes can be registered with the same key\n return [...new Set(types)];\n }\n\n /** @deprecated Use {@link GetRegisteredTypes}. */\n getRegisteredTypes(): string[] {\n return this.GetRegisteredTypes();\n }\n\n /**\n * Check if a provider type is registered\n */\n IsTypeRegistered(type: string): boolean {\n return this.GetRegisteredTypes().includes(type);\n }\n\n /** @deprecated Use {@link IsTypeRegistered}. */\n isTypeRegistered(type: string): boolean {\n return this.IsTypeRegistered(type);\n }\n\n /**\n * Clear all providers (useful for testing)\n */\n ClearProviders(): void {\n this.providers.clear();\n this.providerConfigs.clear();\n }\n\n /** @deprecated Use {@link ClearProviders}. */\n clearProviders(): void {\n return this.ClearProviders();\n }\n\n /**\n * Get provider-specific Angular services that need to be injected\n * This uses the static angularProviderFactory property on each provider class for extensibility\n */\n static GetProviderAngularServices(type: string, environment: any): any[] {\n \n const normalizedType = type?.toLowerCase();\n \n // Get the provider class from the ClassFactory\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(\n MJAuthBase, \n normalizedType\n );\n const providerClass = registration?.SubClass as any;\n \n if (!providerClass) {\n console.warn(`No provider class registered for type: ${type}`);\n return [];\n }\n \n // Check if the provider class has the factory property (new pattern)\n if (providerClass.angularProviderFactory) {\n // Call the factory function to get the required providers\n const services = providerClass.angularProviderFactory(environment);\n return services;\n } \n // Fallback to old method name for backward compatibility\n else if (typeof providerClass.getRequiredAngularProviders === 'function') {\n console.warn(`Provider ${type} uses deprecated getRequiredAngularProviders method. Please update to use angularProviderFactory property.`);\n return providerClass.getRequiredAngularProviders(environment);\n } \n else {\n // Provider doesn't define required Angular services (might not need any)\n return [];\n }\n }\n\n /** @deprecated Use {@link GetProviderAngularServices}. */\n static getProviderAngularServices(type: string, environment: any): any[] {\n return this.GetProviderAngularServices(type, environment);\n }\n\n}"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IAuthProvider.js","sourceRoot":"","sources":["../../src/lib/IAuthProvider.ts"],"names":[],"mappings":"","sourcesContent":["import { Observable } from 'rxjs';\nimport { AuthProviderConfig } from '@memberjunction/core';\nimport {\n StandardUserInfo,\n StandardAuthToken,\n StandardAuthError,\n TokenRefreshResult\n} from './auth-types';\n\n// Create an alias for Angular-specific config that extends the base\nexport interface AngularAuthProviderConfig extends AuthProviderConfig {\n // Angular-specific extensions can be added here if needed\n}\n\n/**\n * Interface for Angular authentication providers - v3.0.0\n *\n * This interface defines the contract that all auth providers must implement.\n * It ensures consistent behavior across different OAuth providers while hiding\n * provider-specific implementation details.\n *\n * ## Breaking Changes from v2.x:\n * - Removed: getUserProfile() - Use getUserInfo() instead\n * - Removed: getUser() - Use getUserInfo() instead\n * - Removed: getUserClaims() - Use getTokenInfo() instead\n * - Removed: getToken() - Use getIdToken() instead\n * - Removed: refresh() - Use refreshToken() instead\n * - Removed: checkExpiredTokenError() - Use classifyError() instead\n *\n * @version 3.0.0\n */\nexport interface IAngularAuthProvider {\n /**\n * Provider type identifier (e.g., 'msal', 'auth0', 'okta')\n */\n readonly type: string;\n\n // ============================================================================\n // CORE AUTHENTICATION METHODS\n // ============================================================================\n\n /**\n * Initialize the authentication provider\n *\n * This should handle callback processing, session restoration, etc.\n * Called automatically during app startup.\n */\n initialize(): Promise<void>;\n\n /**\n * Initiate login flow\n *\n * @param options Optional provider-specific login options\n * @returns Observable for backward compatibility, can also return Promise\n *\n * @example\n * ```typescript\n * await this.authBase.login({ appState: { target: '/dashboard' } });\n * ```\n */\n login(options?: Record<string, unknown>): Observable<void> | Promise<void>;\n\n /**\n * Log out the current user\n *\n * Clears local session and redirects to provider's logout endpoint.\n *\n * @example\n * ```typescript\n * await this.authBase.logout();\n * ```\n */\n logout(): Promise<void>;\n\n /**\n * Handle OAuth callback after redirect\n *\n * This is called automatically by the redirect component.\n * Application code typically doesn't need to call this directly.\n */\n handleCallback(): Promise<void>;\n\n // ============================================================================\n // AUTHENTICATION STATE (Observable Streams)\n // ============================================================================\n\n /**\n * Observable stream of authentication state\n *\n * Emits true when user is authenticated, false otherwise.\n * Subscribe to this for reactive UI updates.\n *\n * @example\n * ```typescript\n * this.authBase.isAuthenticated().subscribe(isAuth => {\n * this.showLoginButton = !isAuth;\n * });\n * ```\n */\n isAuthenticated(): Observable<boolean>;\n\n /**\n * Observable stream of user profile information\n *\n * Emits StandardUserInfo when authenticated, null otherwise.\n * This replaces the old getUserProfile() which returned 'any'.\n *\n * @example\n * ```typescript\n * this.authBase.getUserInfo().subscribe(user => {\n * if (user) {\n * console.log(`Welcome ${user.name}!`);\n * }\n * });\n * ```\n */\n getUserInfo(): Observable<StandardUserInfo | null>;\n\n /**\n * Observable stream of user's email address\n *\n * Emits email string when authenticated, empty string otherwise.\n *\n * @example\n * ```typescript\n * this.userEmail$ = this.authBase.getUserEmail();\n * ```\n */\n getUserEmail(): Observable<string>;\n\n // ============================================================================\n // TOKEN MANAGEMENT (v3.0.0 - Fixes Leaky Abstraction)\n // ============================================================================\n\n /**\n * Get the current ID token as a string\n *\n * This is the primary method applications should use to get the token\n * for backend API calls. It abstracts away provider-specific token storage\n * (Auth0's __raw vs MSAL's idToken).\n *\n * @returns Promise resolving to the ID token string, or null if not authenticated\n *\n * @example\n * ```typescript\n * const token = await this.authBase.getIdToken();\n * if (token) {\n * // Use token for GraphQL or REST API calls\n * setupGraphQLClient(token, apiUrl);\n * }\n * ```\n */\n getIdToken(): Promise<string | null>;\n\n /**\n * Get complete token information\n *\n * Returns a standardized token object with ID token, access token, and expiration.\n * Use this when you need more than just the token string.\n *\n * @returns Promise resolving to StandardAuthToken or null if not authenticated\n *\n * @example\n * ```typescript\n * const tokenInfo = await this.authBase.getTokenInfo();\n * if (tokenInfo) {\n * console.log(`Token expires at: ${new Date(tokenInfo.expiresAt)}`);\n * }\n * ```\n */\n getTokenInfo(): Promise<StandardAuthToken | null>;\n\n /**\n * Refresh the current authentication token\n *\n * Attempts to obtain a fresh authentication token using the provider's\n * refresh mechanism. If silent refresh fails due to session expiry, the\n * provider will handle re-authentication automatically (which may involve\n * redirecting to the auth provider's login page).\n *\n * Returns a fresh token on success, or throws on complete failure.\n *\n * IMPORTANT: If the provider requires interactive re-authentication (redirect\n * or popup), this method may never return. The app will reload after\n * authentication completes and re-initialize with a fresh token.\n *\n * @returns Promise resolving to StandardAuthToken or throws on failure\n *\n * @example\n * ```typescript\n * const token = await this.authBase.refreshToken();\n * return token.idToken; // Always succeeds or throws\n * ```\n */\n refreshToken(): Promise<StandardAuthToken>;\n\n // ============================================================================\n // ERROR HANDLING (v3.0.0 - Fixes Error Type Leakage)\n // ============================================================================\n\n /**\n * Classify an error into a standard error type\n *\n * This method converts provider-specific errors into semantic error types\n * that application code can handle consistently. Eliminates the need for\n * consumers to check provider-specific error names like 'BrowserAuthError'.\n *\n * @param error The error to classify (can be any type)\n * @returns StandardAuthError with categorized error type\n *\n * @example\n * ```typescript\n * try {\n * await this.authBase.login();\n * } catch (err) {\n * const authError = this.authBase.classifyError(err);\n *\n * switch (authError.type) {\n * case AuthErrorType.TOKEN_EXPIRED:\n * // Show \"session expired\" message\n * break;\n * case AuthErrorType.USER_CANCELLED:\n * // User cancelled - don't show error\n * break;\n * default:\n * // Show generic error\n * alert(authError.userMessage);\n * }\n * }\n * ```\n */\n classifyError(error: unknown): StandardAuthError;\n\n // ============================================================================\n // CONFIGURATION & VALIDATION\n // ============================================================================\n\n /**\n * Get list of required configuration fields for this provider\n *\n * @returns Array of required config field names\n *\n * @example\n * ```typescript\n * // Auth0 requires: ['clientId', 'domain']\n * // MSAL requires: ['clientId', 'tenantId']\n * ```\n */\n getRequiredConfig(): string[];\n\n /**\n * Validate provider configuration\n *\n * @param config Configuration object to validate\n * @returns True if configuration is valid\n */\n validateConfig(config: Record<string, unknown>): boolean;\n}"]}
1
+ {"version":3,"file":"IAuthProvider.js","sourceRoot":"","sources":["../../src/lib/IAuthProvider.ts"],"names":[],"mappings":"","sourcesContent":["import { Observable } from 'rxjs';\nimport { AuthProviderConfig } from '@memberjunction/core';\nimport {\n StandardUserInfo,\n StandardAuthToken,\n StandardAuthError,\n TokenRefreshResult\n} from './auth-types';\n\n// Create an alias for Angular-specific config that extends the base\nexport interface AngularAuthProviderConfig extends AuthProviderConfig {\n // Angular-specific extensions can be added here if needed\n}\n\n/**\n * Interface for Angular authentication providers - v3.0.0\n *\n * This interface defines the contract that all auth providers must implement.\n * It ensures consistent behavior across different OAuth providers while hiding\n * provider-specific implementation details.\n *\n * ## Breaking Changes from v2.x:\n * - Removed: getUserProfile() - Use getUserInfo() instead\n * - Removed: getUser() - Use getUserInfo() instead\n * - Removed: getUserClaims() - Use getTokenInfo() instead\n * - Removed: getToken() - Use getIdToken() instead\n * - Removed: refresh() - Use refreshToken() instead\n * - Removed: checkExpiredTokenError() - Use classifyError() instead\n *\n * @version 3.0.0\n */\nexport interface IAngularAuthProvider {\n /**\n * Provider type identifier (e.g., 'msal', 'auth0', 'okta')\n */\n readonly type: string; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n // ============================================================================\n // CORE AUTHENTICATION METHODS\n // ============================================================================\n\n /**\n * Initialize the authentication provider\n *\n * This should handle callback processing, session restoration, etc.\n * Called automatically during app startup.\n */\n initialize(): Promise<void>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Initiate login flow\n *\n * @param options Optional provider-specific login options\n * @returns Observable for backward compatibility, can also return Promise\n *\n * @example\n * ```typescript\n * await this.authBase.login({ appState: { target: '/dashboard' } });\n * ```\n */\n login(options?: Record<string, unknown>): Observable<void> | Promise<void>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Log out the current user\n *\n * Clears local session and redirects to provider's logout endpoint.\n *\n * @example\n * ```typescript\n * await this.authBase.logout();\n * ```\n */\n logout(): Promise<void>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Handle OAuth callback after redirect\n *\n * This is called automatically by the redirect component.\n * Application code typically doesn't need to call this directly.\n */\n handleCallback(): Promise<void>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n // ============================================================================\n // AUTHENTICATION STATE (Observable Streams)\n // ============================================================================\n\n /**\n * Observable stream of authentication state\n *\n * Emits true when user is authenticated, false otherwise.\n * Subscribe to this for reactive UI updates.\n *\n * @example\n * ```typescript\n * this.authBase.isAuthenticated().subscribe(isAuth => {\n * this.showLoginButton = !isAuth;\n * });\n * ```\n */\n isAuthenticated(): Observable<boolean>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Observable stream of user profile information\n *\n * Emits StandardUserInfo when authenticated, null otherwise.\n * This replaces the old getUserProfile() which returned 'any'.\n *\n * @example\n * ```typescript\n * this.authBase.getUserInfo().subscribe(user => {\n * if (user) {\n * console.log(`Welcome ${user.name}!`);\n * }\n * });\n * ```\n */\n getUserInfo(): Observable<StandardUserInfo | null>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Observable stream of user's email address\n *\n * Emits email string when authenticated, empty string otherwise.\n *\n * @example\n * ```typescript\n * this.userEmail$ = this.authBase.getUserEmail();\n * ```\n */\n getUserEmail(): Observable<string>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n // ============================================================================\n // TOKEN MANAGEMENT (v3.0.0 - Fixes Leaky Abstraction)\n // ============================================================================\n\n /**\n * Get the current ID token as a string\n *\n * This is the primary method applications should use to get the token\n * for backend API calls. It abstracts away provider-specific token storage\n * (Auth0's __raw vs MSAL's idToken).\n *\n * @returns Promise resolving to the ID token string, or null if not authenticated\n *\n * @example\n * ```typescript\n * const token = await this.authBase.getIdToken();\n * if (token) {\n * // Use token for GraphQL or REST API calls\n * setupGraphQLClient(token, apiUrl);\n * }\n * ```\n */\n getIdToken(): Promise<string | null>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Get complete token information\n *\n * Returns a standardized token object with ID token, access token, and expiration.\n * Use this when you need more than just the token string.\n *\n * @returns Promise resolving to StandardAuthToken or null if not authenticated\n *\n * @example\n * ```typescript\n * const tokenInfo = await this.authBase.getTokenInfo();\n * if (tokenInfo) {\n * console.log(`Token expires at: ${new Date(tokenInfo.expiresAt)}`);\n * }\n * ```\n */\n getTokenInfo(): Promise<StandardAuthToken | null>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Refresh the current authentication token\n *\n * Attempts to obtain a fresh authentication token using the provider's\n * refresh mechanism. If silent refresh fails due to session expiry, the\n * provider will handle re-authentication automatically (which may involve\n * redirecting to the auth provider's login page).\n *\n * Returns a fresh token on success, or throws on complete failure.\n *\n * IMPORTANT: If the provider requires interactive re-authentication (redirect\n * or popup), this method may never return. The app will reload after\n * authentication completes and re-initialize with a fresh token.\n *\n * @returns Promise resolving to StandardAuthToken or throws on failure\n *\n * @example\n * ```typescript\n * const token = await this.authBase.refreshToken();\n * return token.idToken; // Always succeeds or throws\n * ```\n */\n refreshToken(): Promise<StandardAuthToken>; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n // ============================================================================\n // ERROR HANDLING (v3.0.0 - Fixes Error Type Leakage)\n // ============================================================================\n\n /**\n * Classify an error into a standard error type\n *\n * This method converts provider-specific errors into semantic error types\n * that application code can handle consistently. Eliminates the need for\n * consumers to check provider-specific error names like 'BrowserAuthError'.\n *\n * @param error The error to classify (can be any type)\n * @returns StandardAuthError with categorized error type\n *\n * @example\n * ```typescript\n * try {\n * await this.authBase.login();\n * } catch (err) {\n * const authError = this.authBase.classifyError(err);\n *\n * switch (authError.type) {\n * case AuthErrorType.TOKEN_EXPIRED:\n * // Show \"session expired\" message\n * break;\n * case AuthErrorType.USER_CANCELLED:\n * // User cancelled - don't show error\n * break;\n * default:\n * // Show generic error\n * alert(authError.userMessage);\n * }\n * }\n * ```\n */\n classifyError(error: unknown): StandardAuthError; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n // ============================================================================\n // CONFIGURATION & VALIDATION\n // ============================================================================\n\n /**\n * Get list of required configuration fields for this provider\n *\n * @returns Array of required config field names\n *\n * @example\n * ```typescript\n * // Auth0 requires: ['clientId', 'domain']\n * // MSAL requires: ['clientId', 'tenantId']\n * ```\n */\n getRequiredConfig(): string[]; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n\n /**\n * Validate provider configuration\n *\n * @param config Configuration object to validate\n * @returns True if configuration is valid\n */\n validateConfig(config: Record<string, unknown>): boolean; // case-violation-ok-legacy-back-compat: the type is named in an exported signature, so consumers build object literals against it; an interface has no runtime carrier for a stub\n}"]}
@@ -39,6 +39,8 @@ export declare class AuthServicesModule {
39
39
  * behaviour is byte-for-byte what it was before the catalog existed, which is what
40
40
  * keeps every existing deployment working untouched.
41
41
  */
42
+ static ForRoot(environment: any, catalog?: PublicAuthProviderInfo[]): ModuleWithProviders<AuthServicesModule>;
43
+ /** @deprecated Use {@link ForRoot}. */
42
44
  static forRoot(environment: any, catalog?: PublicAuthProviderInfo[]): ModuleWithProviders<AuthServicesModule>;
43
45
  static ɵfac: i0.ɵɵFactoryDeclaration<AuthServicesModule, never>;
44
46
  static ɵmod: i0.ɵɵNgModuleDeclaration<AuthServicesModule, [typeof i1.RedirectComponent], [typeof i2.CommonModule, typeof i3.MJLoginPickerComponent], [typeof i1.RedirectComponent, typeof i3.MJLoginPickerComponent]>;
@@ -1 +1 @@
1
- {"version":3,"file":"auth-services.module.d.ts","sourceRoot":"","sources":["../../src/lib/auth-services.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,mBAAmB,EAAE,cAAc,EAAY,MAAM,eAAe,CAAC;AAMxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAK3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;;;;AAGzD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,wCAA4E,CAAC;AAKrH;;;GAGG;AACH,qBAKa,kBAAkB;IAC7B;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,sBAAsB,EAAE,GAAG,mBAAmB,CAAC,kBAAkB,CAAC;yCApBlG,kBAAkB;0CAAlB,kBAAkB;0CAAlB,kBAAkB;CA6F9B"}
1
+ {"version":3,"file":"auth-services.module.d.ts","sourceRoot":"","sources":["../../src/lib/auth-services.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,mBAAmB,EAAE,cAAc,EAAY,MAAM,eAAe,CAAC;AAMxF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAuB,KAAK,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAK3F,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;;;;;AAGzD,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,wCAA4E,CAAC;AAKrH;;;GAGG;AACH,qBAKa,kBAAkB;IAC7B;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,sBAAsB,EAAE,GAAG,mBAAmB,CAAC,kBAAkB,CAAC;IA0E7G,uCAAuC;IACvC,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,sBAAsB,EAAE,GAAG,mBAAmB,CAAC,kBAAkB,CAAC;yCA/FlG,kBAAkB;0CAAlB,kBAAkB;0CAAlB,kBAAkB;CAkG9B"}
@@ -5,7 +5,7 @@ import { AngularAuthProviderFactory } from './AngularAuthProviderFactory';
5
5
  import { MJMagicLinkProvider } from './providers/mjexplorer-magic-link-provider.service';
6
6
  import { MJGlobal } from '@memberjunction/global';
7
7
  import { AuthProviderCatalog } from './auth-provider-catalog';
8
- import { mergeCatalogEnvironment } from './catalog-environment';
8
+ import { MergeCatalogEnvironment } from './catalog-environment';
9
9
  import { MJLoginPickerComponent } from './login-picker.component';
10
10
  // Import our generic redirect component
11
11
  import { RedirectComponent } from './redirect.component';
@@ -46,7 +46,7 @@ export class AuthServicesModule {
46
46
  * behaviour is byte-for-byte what it was before the catalog existed, which is what
47
47
  * keeps every existing deployment working untouched.
48
48
  */
49
- static forRoot(environment, catalog) {
49
+ static ForRoot(environment, catalog) {
50
50
  const env = environment;
51
51
  const providers = [];
52
52
  const configuredType = env['AUTH_TYPE']?.toLowerCase();
@@ -82,7 +82,7 @@ export class AuthServicesModule {
82
82
  // environment, so the driver receives the row's values overlaid on the app's environment.
83
83
  // Magic-link is excluded: its session is established by the redeem flow, not by catalog config.
84
84
  const effectiveEnvironment = resolution.active && !magicLinkActive
85
- ? mergeCatalogEnvironment(environment, resolution.active, providerClass)
85
+ ? MergeCatalogEnvironment(environment, resolution.active, providerClass)
86
86
  : environment;
87
87
  // Use the factory to get provider-specific Angular services
88
88
  // This uses the static method on each provider class for extensibility
@@ -105,6 +105,10 @@ export class AuthServicesModule {
105
105
  providers: providers
106
106
  };
107
107
  }
108
+ /** @deprecated Use {@link ForRoot}. */
109
+ static forRoot(environment, catalog) {
110
+ return this.ForRoot(environment, catalog);
111
+ }
108
112
  static ɵfac = function AuthServicesModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AuthServicesModule)(); };
109
113
  static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: AuthServicesModule });
110
114
  static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule] });
@@ -1 +1 @@
1
- {"version":3,"file":"auth-services.module.js","sourceRoot":"","sources":["../../src/lib/auth-services.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { NgModule, ModuleWithProviders, InjectionToken, Provider } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MJAuthBase } from './mjexplorer-auth-base.service';\nimport { AngularAuthProviderFactory } from './AngularAuthProviderFactory';\nimport { MJMagicLinkProvider } from './providers/mjexplorer-magic-link-provider.service';\nimport { MJGlobal } from '@memberjunction/global';\nimport type { PublicAuthProviderInfo } from '@memberjunction/core';\nimport { AuthProviderCatalog, type AuthProviderResolution } from './auth-provider-catalog';\nimport { mergeCatalogEnvironment, type CatalogEnvironmentMapper } from './catalog-environment';\nimport { MJLoginPickerComponent } from './login-picker.component';\n\n// Import our generic redirect component\nimport { RedirectComponent } from './redirect.component';\n\n// Export the generic redirect component for backward compatibility\nexport { RedirectComponent };\n\n/**\n * Injection token carrying how authentication resolved for this page load.\n *\n * A login surface injects this to decide whether to render the multi-provider picker or the\n * single sign-in button, and whether to start the login flow immediately after a picker\n * choice caused a reload.\n */\nexport const MJ_AUTH_PROVIDER_RESOLUTION = new InjectionToken<AuthProviderResolution>('MJ_AUTH_PROVIDER_RESOLUTION');\n\n/** The resolution used when no catalog is supplied — i.e. the pre-existing single-provider path. */\nconst NO_CATALOG_RESOLUTION: AuthProviderResolution = { active: null, choices: [], showPicker: false, autoLogin: false };\n\n/**\n * Extensible authentication module that supports N providers\n * Uses MJGlobal ClassFactory pattern for dynamic provider creation\n */\n@NgModule({\n imports: [CommonModule, MJLoginPickerComponent],\n declarations: [RedirectComponent],\n exports: [RedirectComponent, MJLoginPickerComponent]\n})\nexport class AuthServicesModule {\n /**\n * Wires the authentication provider into DI.\n *\n * @param environment The app's compiled environment. Typed loosely on purpose: every app\n * declares its own environment shape (`MJEnvironmentConfig` and downstream equivalents\n * are interfaces, which TypeScript will not assign to an indexed record), so narrowing\n * this parameter would break every existing caller. It is narrowed once, below.\n * @param catalog Optional pre-auth provider catalog. Defaults to whatever the app preloaded\n * via {@link AuthProviderCatalog.Preload} in its bootstrap entry point — passing it\n * explicitly is for tests and for apps that source the catalog some other way. Callers\n * must NOT pass `AuthProviderCatalog.GetPreloaded()` themselves: Angular's compiler\n * requires every `imports` entry to be statically analyzable, and a function call in\n * the argument list fails AOT with \"Value could not be determined statically\".\n *\n * When the catalog is empty — an older server, a failed fetch, or a deployment that\n * never adopted the entity — resolution falls back to `environment.AUTH_TYPE` and\n * behaviour is byte-for-byte what it was before the catalog existed, which is what\n * keeps every existing deployment working untouched.\n */\n static forRoot(environment: any, catalog?: PublicAuthProviderInfo[]): ModuleWithProviders<AuthServicesModule> {\n const env = environment as Record<string, unknown>;\n const providers: Provider[] = [];\n const configuredType = (env['AUTH_TYPE'] as string | undefined)?.toLowerCase();\n const resolvedCatalog = catalog ?? AuthProviderCatalog.GetPreloaded();\n\n // Coexistence resolution: a single Explorer deployment can serve both SSO\n // users and magic-link guests. If a magic-link session token is present for\n // this page load (URL fragment from /redeem, or stored earlier this tab), use\n // the magic-link provider regardless of the configured primary IdP. Otherwise\n // use the catalog selection, then the configured AUTH_TYPE. This auto-falls-back\n // to the IdP once a guest's token is gone (expired/logged out), so the normal\n // login button works again.\n const magicLinkActive = MJMagicLinkProvider.hasSessionToken();\n\n // The catalog resolves which provider this load uses; it never overrides an active\n // magic-link session, which is a property of THIS page load rather than a configured choice.\n const resolution = resolvedCatalog.length ? AuthProviderCatalog.Resolve(resolvedCatalog) : NO_CATALOG_RESOLUTION;\n providers.push({ provide: MJ_AUTH_PROVIDER_RESOLUTION, useValue: resolution });\n\n const catalogType = resolution.active?.driverClass?.toLowerCase();\n const authType = magicLinkActive ? MJMagicLinkProvider.PROVIDER_TYPE : (catalogType ?? configuredType);\n\n if (!authType) {\n console.error('No authentication provider available: the server published no catalog and no AUTH_TYPE is set in the environment');\n return {\n ngModule: AuthServicesModule,\n providers: providers as never[]\n };\n }\n\n if (magicLinkActive && authType !== (catalogType ?? configuredType)) {\n console.log(`[Auth] Magic-link session token detected — using the magic-link provider for this load (configured primary: '${catalogType ?? configuredType ?? 'none'}').`);\n }\n\n // Get the provider class from ClassFactory for extensibility\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(\n MJAuthBase,\n authType\n );\n const providerClass = registration?.SubClass;\n\n // A catalog-selected provider takes its settings from metadata rather than from the compiled\n // environment, so the driver receives the row's values overlaid on the app's environment.\n // Magic-link is excluded: its session is established by the redeem flow, not by catalog config.\n const effectiveEnvironment =\n resolution.active && !magicLinkActive\n ? mergeCatalogEnvironment(environment, resolution.active, providerClass as CatalogEnvironmentMapper | undefined)\n : environment;\n\n // Use the factory to get provider-specific Angular services\n // This uses the static method on each provider class for extensibility\n const angularServices = AngularAuthProviderFactory.getProviderAngularServices(authType, effectiveEnvironment);\n providers.push(...angularServices);\n\n if (providerClass) {\n // Add the provider itself\n providers.push({\n provide: MJAuthBase,\n useClass: providerClass\n });\n } else {\n console.error(`No provider class registered for auth type: ${authType}`);\n }\n\n // Add the factory itself\n providers.push(AngularAuthProviderFactory);\n\n return {\n ngModule: AuthServicesModule,\n providers: providers as never[]\n };\n }\n}\n"]}
1
+ {"version":3,"file":"auth-services.module.js","sourceRoot":"","sources":["../../src/lib/auth-services.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { NgModule, ModuleWithProviders, InjectionToken, Provider } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MJAuthBase } from './mjexplorer-auth-base.service';\nimport { AngularAuthProviderFactory } from './AngularAuthProviderFactory';\nimport { MJMagicLinkProvider } from './providers/mjexplorer-magic-link-provider.service';\nimport { MJGlobal } from '@memberjunction/global';\nimport type { PublicAuthProviderInfo } from '@memberjunction/core';\nimport { AuthProviderCatalog, type AuthProviderResolution } from './auth-provider-catalog';\nimport { MergeCatalogEnvironment, type CatalogEnvironmentMapper } from './catalog-environment';\nimport { MJLoginPickerComponent } from './login-picker.component';\n\n// Import our generic redirect component\nimport { RedirectComponent } from './redirect.component';\n\n// Export the generic redirect component for backward compatibility\nexport { RedirectComponent };\n\n/**\n * Injection token carrying how authentication resolved for this page load.\n *\n * A login surface injects this to decide whether to render the multi-provider picker or the\n * single sign-in button, and whether to start the login flow immediately after a picker\n * choice caused a reload.\n */\nexport const MJ_AUTH_PROVIDER_RESOLUTION = new InjectionToken<AuthProviderResolution>('MJ_AUTH_PROVIDER_RESOLUTION');\n\n/** The resolution used when no catalog is supplied — i.e. the pre-existing single-provider path. */\nconst NO_CATALOG_RESOLUTION: AuthProviderResolution = { active: null, choices: [], showPicker: false, autoLogin: false };\n\n/**\n * Extensible authentication module that supports N providers\n * Uses MJGlobal ClassFactory pattern for dynamic provider creation\n */\n@NgModule({\n imports: [CommonModule, MJLoginPickerComponent],\n declarations: [RedirectComponent],\n exports: [RedirectComponent, MJLoginPickerComponent]\n})\nexport class AuthServicesModule {\n /**\n * Wires the authentication provider into DI.\n *\n * @param environment The app's compiled environment. Typed loosely on purpose: every app\n * declares its own environment shape (`MJEnvironmentConfig` and downstream equivalents\n * are interfaces, which TypeScript will not assign to an indexed record), so narrowing\n * this parameter would break every existing caller. It is narrowed once, below.\n * @param catalog Optional pre-auth provider catalog. Defaults to whatever the app preloaded\n * via {@link AuthProviderCatalog.Preload} in its bootstrap entry point — passing it\n * explicitly is for tests and for apps that source the catalog some other way. Callers\n * must NOT pass `AuthProviderCatalog.GetPreloaded()` themselves: Angular's compiler\n * requires every `imports` entry to be statically analyzable, and a function call in\n * the argument list fails AOT with \"Value could not be determined statically\".\n *\n * When the catalog is empty — an older server, a failed fetch, or a deployment that\n * never adopted the entity — resolution falls back to `environment.AUTH_TYPE` and\n * behaviour is byte-for-byte what it was before the catalog existed, which is what\n * keeps every existing deployment working untouched.\n */\n static ForRoot(environment: any, catalog?: PublicAuthProviderInfo[]): ModuleWithProviders<AuthServicesModule> {\n const env = environment as Record<string, unknown>;\n const providers: Provider[] = [];\n const configuredType = (env['AUTH_TYPE'] as string | undefined)?.toLowerCase();\n const resolvedCatalog = catalog ?? AuthProviderCatalog.GetPreloaded();\n\n // Coexistence resolution: a single Explorer deployment can serve both SSO\n // users and magic-link guests. If a magic-link session token is present for\n // this page load (URL fragment from /redeem, or stored earlier this tab), use\n // the magic-link provider regardless of the configured primary IdP. Otherwise\n // use the catalog selection, then the configured AUTH_TYPE. This auto-falls-back\n // to the IdP once a guest's token is gone (expired/logged out), so the normal\n // login button works again.\n const magicLinkActive = MJMagicLinkProvider.hasSessionToken();\n\n // The catalog resolves which provider this load uses; it never overrides an active\n // magic-link session, which is a property of THIS page load rather than a configured choice.\n const resolution = resolvedCatalog.length ? AuthProviderCatalog.Resolve(resolvedCatalog) : NO_CATALOG_RESOLUTION;\n providers.push({ provide: MJ_AUTH_PROVIDER_RESOLUTION, useValue: resolution });\n\n const catalogType = resolution.active?.driverClass?.toLowerCase();\n const authType = magicLinkActive ? MJMagicLinkProvider.PROVIDER_TYPE : (catalogType ?? configuredType);\n\n if (!authType) {\n console.error('No authentication provider available: the server published no catalog and no AUTH_TYPE is set in the environment');\n return {\n ngModule: AuthServicesModule,\n providers: providers as never[]\n };\n }\n\n if (magicLinkActive && authType !== (catalogType ?? configuredType)) {\n console.log(`[Auth] Magic-link session token detected — using the magic-link provider for this load (configured primary: '${catalogType ?? configuredType ?? 'none'}').`);\n }\n\n // Get the provider class from ClassFactory for extensibility\n const registration = MJGlobal.Instance.ClassFactory.GetRegistration(\n MJAuthBase,\n authType\n );\n const providerClass = registration?.SubClass;\n\n // A catalog-selected provider takes its settings from metadata rather than from the compiled\n // environment, so the driver receives the row's values overlaid on the app's environment.\n // Magic-link is excluded: its session is established by the redeem flow, not by catalog config.\n const effectiveEnvironment =\n resolution.active && !magicLinkActive\n ? MergeCatalogEnvironment(environment, resolution.active, providerClass as CatalogEnvironmentMapper | undefined)\n : environment;\n\n // Use the factory to get provider-specific Angular services\n // This uses the static method on each provider class for extensibility\n const angularServices = AngularAuthProviderFactory.getProviderAngularServices(authType, effectiveEnvironment);\n providers.push(...angularServices);\n\n if (providerClass) {\n // Add the provider itself\n providers.push({\n provide: MJAuthBase,\n useClass: providerClass\n });\n } else {\n console.error(`No provider class registered for auth type: ${authType}`);\n }\n\n // Add the factory itself\n providers.push(AngularAuthProviderFactory);\n\n return {\n ngModule: AuthServicesModule,\n providers: providers as never[]\n };\n }\n\n /** @deprecated Use {@link ForRoot}. */\n static forRoot(environment: any, catalog?: PublicAuthProviderInfo[]): ModuleWithProviders<AuthServicesModule> {\n return this.ForRoot(environment, catalog);\n }\n}\n"]}
@@ -33,6 +33,8 @@ export interface CatalogEnvironmentMapper {
33
33
  * `buildProviderConfig`, where a blob must not silently redefine a described, reviewable column
34
34
  * (`{"scopes": "..."}` in the blob would otherwise clobber the parsed `Scopes` column).
35
35
  */
36
+ export declare function BuildGenericEnvironmentOverlay(info: PublicAuthProviderInfo): Record<string, unknown>;
37
+ /** @deprecated Use {@link BuildGenericEnvironmentOverlay}. */
36
38
  export declare function buildGenericEnvironmentOverlay(info: PublicAuthProviderInfo): Record<string, unknown>;
37
39
  /**
38
40
  * Produces the environment record to hand a driver for a catalog-selected provider.
@@ -46,5 +48,7 @@ export declare function buildGenericEnvironmentOverlay(info: PublicAuthProviderI
46
48
  * @param info The provider selected from the catalog.
47
49
  * @param providerClass The resolved `MJAuthBase` subclass, consulted for a custom mapper.
48
50
  */
51
+ export declare function MergeCatalogEnvironment(environment: Record<string, unknown>, info: PublicAuthProviderInfo, providerClass?: CatalogEnvironmentMapper): Record<string, unknown>;
52
+ /** @deprecated Use {@link MergeCatalogEnvironment}. */
49
53
  export declare function mergeCatalogEnvironment(environment: Record<string, unknown>, info: PublicAuthProviderInfo, providerClass?: CatalogEnvironmentMapper): Record<string, unknown>;
50
54
  //# sourceMappingURL=catalog-environment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-environment.d.ts","sourceRoot":"","sources":["../../src/lib/catalog-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpF;AAmBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BpG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,IAAI,EAAE,sBAAsB,EAC5B,aAAa,CAAC,EAAE,wBAAwB,GACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB"}
1
+ {"version":3,"file":"catalog-environment.d.ts","sourceRoot":"","sources":["../../src/lib/catalog-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpF;AAmBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6BpG;AAED,8DAA8D;AAC9D,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEpG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,IAAI,EAAE,sBAAsB,EAC5B,aAAa,CAAC,EAAE,wBAAwB,GACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAOzB;AAED,uDAAuD;AACvD,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,IAAI,EAAE,sBAAsB,EAC5B,aAAa,CAAC,EAAE,wBAAwB,GACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzB"}
@@ -39,7 +39,7 @@ function environmentPrefix(driverClass) {
39
39
  * `buildProviderConfig`, where a blob must not silently redefine a described, reviewable column
40
40
  * (`{"scopes": "..."}` in the blob would otherwise clobber the parsed `Scopes` column).
41
41
  */
42
- export function buildGenericEnvironmentOverlay(info) {
42
+ export function BuildGenericEnvironmentOverlay(info) {
43
43
  const prefix = environmentPrefix(info.driverClass);
44
44
  const overlay = {};
45
45
  for (const [key, value] of Object.entries(info.clientConfiguration ?? {})) {
@@ -66,6 +66,10 @@ export function buildGenericEnvironmentOverlay(info) {
66
66
  }
67
67
  return overlay;
68
68
  }
69
+ /** @deprecated Use {@link BuildGenericEnvironmentOverlay}. */
70
+ export function buildGenericEnvironmentOverlay(info) {
71
+ return BuildGenericEnvironmentOverlay(info);
72
+ }
69
73
  /**
70
74
  * Produces the environment record to hand a driver for a catalog-selected provider.
71
75
  *
@@ -78,10 +82,14 @@ export function buildGenericEnvironmentOverlay(info) {
78
82
  * @param info The provider selected from the catalog.
79
83
  * @param providerClass The resolved `MJAuthBase` subclass, consulted for a custom mapper.
80
84
  */
81
- export function mergeCatalogEnvironment(environment, info, providerClass) {
85
+ export function MergeCatalogEnvironment(environment, info, providerClass) {
82
86
  const overlay = typeof providerClass?.EnvironmentFromCatalog === 'function'
83
87
  ? providerClass.EnvironmentFromCatalog(info)
84
- : buildGenericEnvironmentOverlay(info);
88
+ : BuildGenericEnvironmentOverlay(info);
85
89
  return { ...environment, ...overlay, AUTH_TYPE: info.driverClass };
86
90
  }
91
+ /** @deprecated Use {@link MergeCatalogEnvironment}. */
92
+ export function mergeCatalogEnvironment(environment, info, providerClass) {
93
+ return MergeCatalogEnvironment(environment, info, providerClass);
94
+ }
87
95
  //# sourceMappingURL=catalog-environment.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"catalog-environment.js","sourceRoot":"","sources":["../../src/lib/catalog-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH;;GAEG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,GAAG;SACP,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,WAAW,EAAE,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,WAAmB;IAC5C,OAAO,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,8BAA8B,CAAC,IAA4B;IACzE,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,OAAO,GAA4B,EAAE,CAAC;IAE5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC,EAAE,CAAC;QAC1E,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;QACzD,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,MAAM,WAAW,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5C,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,yFAAyF;QACzF,2FAA2F;QAC3F,2FAA2F;QAC3F,2FAA2F;QAC3F,mDAAmD;QACnD,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CACrC,WAAoC,EACpC,IAA4B,EAC5B,aAAwC;IAExC,MAAM,OAAO,GACX,OAAO,aAAa,EAAE,sBAAsB,KAAK,UAAU;QACzD,CAAC,CAAC,aAAa,CAAC,sBAAsB,CAAC,IAAI,CAAC;QAC5C,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,CAAC;IAE3C,OAAO,EAAE,GAAG,WAAW,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;AACrE,CAAC","sourcesContent":["/**\n * @fileoverview Bridges a metadata provider row to the flat `environment` record that the\n * browser auth drivers already consume.\n *\n * Every `MJAuthBase` subclass exposes `static angularProviderFactory(environment)` and reads\n * its settings from prefixed keys on that record (`AUTH0_DOMAIN`, `WORKOS_CLIENTID`, ...).\n * Rather than rewrite each driver to accept a catalog row, the catalog is projected INTO that\n * record — so a provider configured from metadata and one configured from `environment.ts`\n * take an identical code path, and drivers keep working untouched.\n *\n * @module @memberjunction/ng-auth-services\n */\n\nimport type { PublicAuthProviderInfo } from '@memberjunction/core';\n\n/**\n * Optional hook a provider class may expose when the generic prefixed-key convention does not\n * describe its configuration. MSAL is the built-in example: it reads unprefixed `CLIENT_ID` /\n * `CLIENT_AUTHORITY`, so it maps the catalog row itself.\n */\nexport interface CatalogEnvironmentMapper {\n EnvironmentFromCatalog?: (info: PublicAuthProviderInfo) => Record<string, unknown>;\n}\n\n/**\n * `redirectUri` → `REDIRECT_URI`, `apiHostname` → `API_HOSTNAME`, `userPoolId` → `USER_POOL_ID`.\n */\nfunction camelToUpperSnake(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[-\\s]+/g, '_')\n .toUpperCase();\n}\n\n/**\n * The environment-key prefix for a driver: `workos` → `WORKOS`, `magic-link` → `MAGIC_LINK`.\n */\nfunction environmentPrefix(driverClass: string): string {\n return camelToUpperSnake(driverClass);\n}\n\n/**\n * Projects a catalog row onto the conventional prefixed environment keys.\n *\n * The convention — `<DRIVER>_CLIENTID`, `<DRIVER>_DOMAIN`, `<DRIVER>_SCOPES`, plus one key per\n * `clientConfiguration` entry — is exactly what the Auth0, Okta, Cognito and WorkOS drivers\n * already read, so those four need no per-driver mapping at all. A driver that deviates\n * supplies `EnvironmentFromCatalog`.\n *\n * Only defined values are emitted, so a catalog row never blanks out a key the app's compiled\n * environment legitimately supplies. `clientConfiguration` entries are projected FIRST so the\n * modelled columns win a key collision — the same precedence the server enforces in\n * `buildProviderConfig`, where a blob must not silently redefine a described, reviewable column\n * (`{\"scopes\": \"...\"}` in the blob would otherwise clobber the parsed `Scopes` column).\n */\nexport function buildGenericEnvironmentOverlay(info: PublicAuthProviderInfo): Record<string, unknown> {\n const prefix = environmentPrefix(info.driverClass);\n const overlay: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(info.clientConfiguration ?? {})) {\n if (value !== null && value !== undefined) {\n overlay[`${prefix}_${camelToUpperSnake(key)}`] = value;\n }\n }\n\n if (info.clientId) {\n overlay[`${prefix}_CLIENTID`] = info.clientId;\n }\n if (info.domain) {\n overlay[`${prefix}_DOMAIN`] = info.domain;\n }\n if (Array.isArray(info.scopes) && info.scopes.length > 0) {\n // The catalog publishes scopes pre-parsed (the server splits the delimited column at the\n // trust boundary). The drivers that read this key — Okta and Cognito — hand it straight to\n // SDK config typed `string[]`. The Array.isArray guard keeps a malformed or older server's\n // string value from reaching those SDKs: this module runs at bootstrap, where the contract\n // is degrade-to-compiled-environment, never throw.\n overlay[`${prefix}_SCOPES`] = info.scopes;\n }\n if (info.issuer) {\n overlay[`${prefix}_ISSUER`] = info.issuer;\n }\n\n return overlay;\n}\n\n/**\n * Produces the environment record to hand a driver for a catalog-selected provider.\n *\n * The app's compiled environment stays the base layer — it carries app-wide settings such as\n * `GRAPHQL_URI` that have nothing to do with the identity provider — and the catalog overlays\n * only the provider's own keys on top. Metadata therefore wins over a stale compiled value for\n * the settings it owns, without the catalog having to restate the whole environment.\n *\n * @param environment The app's compiled environment object.\n * @param info The provider selected from the catalog.\n * @param providerClass The resolved `MJAuthBase` subclass, consulted for a custom mapper.\n */\nexport function mergeCatalogEnvironment(\n environment: Record<string, unknown>,\n info: PublicAuthProviderInfo,\n providerClass?: CatalogEnvironmentMapper\n): Record<string, unknown> {\n const overlay =\n typeof providerClass?.EnvironmentFromCatalog === 'function'\n ? providerClass.EnvironmentFromCatalog(info)\n : buildGenericEnvironmentOverlay(info);\n\n return { ...environment, ...overlay, AUTH_TYPE: info.driverClass };\n}\n"]}
1
+ {"version":3,"file":"catalog-environment.js","sourceRoot":"","sources":["../../src/lib/catalog-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH;;GAEG;AACH,SAAS,iBAAiB,CAAC,GAAW;IACpC,OAAO,GAAG;SACP,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC;SACvB,WAAW,EAAE,CAAC;AACnB,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,WAAmB;IAC5C,OAAO,iBAAiB,CAAC,WAAW,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,8BAA8B,CAAC,IAA4B;IACzE,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,OAAO,GAA4B,EAAE,CAAC;IAE5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,mBAAmB,IAAI,EAAE,CAAC,EAAE,CAAC;QAC1E,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,MAAM,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;QACzD,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,MAAM,WAAW,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5C,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,yFAAyF;QACzF,2FAA2F;QAC3F,2FAA2F;QAC3F,2FAA2F;QAC3F,mDAAmD;QACnD,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5C,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;IAC5C,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,8BAA8B,CAAC,IAA4B;IACzE,OAAO,8BAA8B,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,uBAAuB,CACrC,WAAoC,EACpC,IAA4B,EAC5B,aAAwC;IAExC,MAAM,OAAO,GACX,OAAO,aAAa,EAAE,sBAAsB,KAAK,UAAU;QACzD,CAAC,CAAC,aAAa,CAAC,sBAAsB,CAAC,IAAI,CAAC;QAC5C,CAAC,CAAC,8BAA8B,CAAC,IAAI,CAAC,CAAC;IAE3C,OAAO,EAAE,GAAG,WAAW,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;AACrE,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,uBAAuB,CACrC,WAAoC,EACpC,IAA4B,EAC5B,aAAwC;IAExC,OAAO,uBAAuB,CAAC,WAAW,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC;AACnE,CAAC","sourcesContent":["/**\n * @fileoverview Bridges a metadata provider row to the flat `environment` record that the\n * browser auth drivers already consume.\n *\n * Every `MJAuthBase` subclass exposes `static angularProviderFactory(environment)` and reads\n * its settings from prefixed keys on that record (`AUTH0_DOMAIN`, `WORKOS_CLIENTID`, ...).\n * Rather than rewrite each driver to accept a catalog row, the catalog is projected INTO that\n * record — so a provider configured from metadata and one configured from `environment.ts`\n * take an identical code path, and drivers keep working untouched.\n *\n * @module @memberjunction/ng-auth-services\n */\n\nimport type { PublicAuthProviderInfo } from '@memberjunction/core';\n\n/**\n * Optional hook a provider class may expose when the generic prefixed-key convention does not\n * describe its configuration. MSAL is the built-in example: it reads unprefixed `CLIENT_ID` /\n * `CLIENT_AUTHORITY`, so it maps the catalog row itself.\n */\nexport interface CatalogEnvironmentMapper {\n EnvironmentFromCatalog?: (info: PublicAuthProviderInfo) => Record<string, unknown>;\n}\n\n/**\n * `redirectUri` → `REDIRECT_URI`, `apiHostname` → `API_HOSTNAME`, `userPoolId` → `USER_POOL_ID`.\n */\nfunction camelToUpperSnake(key: string): string {\n return key\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/[-\\s]+/g, '_')\n .toUpperCase();\n}\n\n/**\n * The environment-key prefix for a driver: `workos` → `WORKOS`, `magic-link` → `MAGIC_LINK`.\n */\nfunction environmentPrefix(driverClass: string): string {\n return camelToUpperSnake(driverClass);\n}\n\n/**\n * Projects a catalog row onto the conventional prefixed environment keys.\n *\n * The convention — `<DRIVER>_CLIENTID`, `<DRIVER>_DOMAIN`, `<DRIVER>_SCOPES`, plus one key per\n * `clientConfiguration` entry — is exactly what the Auth0, Okta, Cognito and WorkOS drivers\n * already read, so those four need no per-driver mapping at all. A driver that deviates\n * supplies `EnvironmentFromCatalog`.\n *\n * Only defined values are emitted, so a catalog row never blanks out a key the app's compiled\n * environment legitimately supplies. `clientConfiguration` entries are projected FIRST so the\n * modelled columns win a key collision — the same precedence the server enforces in\n * `buildProviderConfig`, where a blob must not silently redefine a described, reviewable column\n * (`{\"scopes\": \"...\"}` in the blob would otherwise clobber the parsed `Scopes` column).\n */\nexport function BuildGenericEnvironmentOverlay(info: PublicAuthProviderInfo): Record<string, unknown> {\n const prefix = environmentPrefix(info.driverClass);\n const overlay: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(info.clientConfiguration ?? {})) {\n if (value !== null && value !== undefined) {\n overlay[`${prefix}_${camelToUpperSnake(key)}`] = value;\n }\n }\n\n if (info.clientId) {\n overlay[`${prefix}_CLIENTID`] = info.clientId;\n }\n if (info.domain) {\n overlay[`${prefix}_DOMAIN`] = info.domain;\n }\n if (Array.isArray(info.scopes) && info.scopes.length > 0) {\n // The catalog publishes scopes pre-parsed (the server splits the delimited column at the\n // trust boundary). The drivers that read this key — Okta and Cognito — hand it straight to\n // SDK config typed `string[]`. The Array.isArray guard keeps a malformed or older server's\n // string value from reaching those SDKs: this module runs at bootstrap, where the contract\n // is degrade-to-compiled-environment, never throw.\n overlay[`${prefix}_SCOPES`] = info.scopes;\n }\n if (info.issuer) {\n overlay[`${prefix}_ISSUER`] = info.issuer;\n }\n\n return overlay;\n}\n\n/** @deprecated Use {@link BuildGenericEnvironmentOverlay}. */\nexport function buildGenericEnvironmentOverlay(info: PublicAuthProviderInfo): Record<string, unknown> {\n return BuildGenericEnvironmentOverlay(info);\n}\n\n/**\n * Produces the environment record to hand a driver for a catalog-selected provider.\n *\n * The app's compiled environment stays the base layer — it carries app-wide settings such as\n * `GRAPHQL_URI` that have nothing to do with the identity provider — and the catalog overlays\n * only the provider's own keys on top. Metadata therefore wins over a stale compiled value for\n * the settings it owns, without the catalog having to restate the whole environment.\n *\n * @param environment The app's compiled environment object.\n * @param info The provider selected from the catalog.\n * @param providerClass The resolved `MJAuthBase` subclass, consulted for a custom mapper.\n */\nexport function MergeCatalogEnvironment(\n environment: Record<string, unknown>,\n info: PublicAuthProviderInfo,\n providerClass?: CatalogEnvironmentMapper\n): Record<string, unknown> {\n const overlay =\n typeof providerClass?.EnvironmentFromCatalog === 'function'\n ? providerClass.EnvironmentFromCatalog(info)\n : BuildGenericEnvironmentOverlay(info);\n\n return { ...environment, ...overlay, AUTH_TYPE: info.driverClass };\n}\n\n/** @deprecated Use {@link MergeCatalogEnvironment}. */\nexport function mergeCatalogEnvironment(\n environment: Record<string, unknown>,\n info: PublicAuthProviderInfo,\n providerClass?: CatalogEnvironmentMapper\n): Record<string, unknown> {\n return MergeCatalogEnvironment(environment, info, providerClass);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"login-picker.component.d.ts","sourceRoot":"","sources":["../../src/lib/login-picker.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAEvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;;AAiBnE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAgMa,sBAAsB;IACjC,yDAAyD;IAChD,SAAS,EAAE,sBAAsB,EAAE,CAAM;IAElD,gDAAgD;IACvC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAY;IAE3C,2DAA2D;IAClD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C;;;OAGG;IACM,IAAI,UAAS;IAEtB;;;;;;OAMG;IACM,aAAa,UAAQ;IAE9B;;;;;;;OAOG;IACM,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhD,gFAAgF;IACtE,gBAAgB,uCAA8C;IAExE,6FAA6F;IACnF,gBAAgB,qBAA4B;IAEtD,kFAAkF;IAClF,IAAW,gBAAgB,IAAI,OAAO,CAErC;IAED,oEAAoE;IAC7D,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM;IAIzD;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,GAAG,IAAI;IAOpE,mDAAmD;IAC5C,UAAU,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM;IAIpD,MAAM,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;yCAnE1C,sBAAsB;2CAAtB,sBAAsB;CAwElC"}
1
+ {"version":3,"file":"login-picker.component.d.ts","sourceRoot":"","sources":["../../src/lib/login-picker.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,YAAY,EAAiB,MAAM,eAAe,CAAC;AAEvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;;AAiBnE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAyMa,sBAAsB;IACjC,yDAAyD;IAChD,SAAS,EAAE,sBAAsB,EAAE,CAAM;IAElD,gDAAgD;IACvC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAY;IAE3C,2DAA2D;IAClD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE1C;;;OAGG;IACM,IAAI,UAAS;IAEtB;;;;;;OAMG;IACM,aAAa,UAAQ;IAE9B;;;;;;;OAOG;IACM,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEhD,gFAAgF;IACtE,gBAAgB,uCAA8C;IAExE,6FAA6F;IACnF,gBAAgB,qBAA4B;IAEtD,kFAAkF;IAClF,IAAW,gBAAgB,IAAI,OAAO,CAErC;IAED,oEAAoE;IAC7D,QAAQ,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM;IAIzD;;;OAGG;IACI,YAAY,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,GAAG,IAAI;IAOpE,mDAAmD;IAC5C,UAAU,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM;IAIpD,MAAM,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;yCAnE1C,sBAAsB;2CAAtB,sBAAsB;CAwElC"}
@@ -199,7 +199,7 @@ export class MJLoginPickerComponent {
199
199
  i0.ɵɵconditional(!ctx.Providers.length && ctx.FallbackCtaLabel ? 6 : -1);
200
200
  i0.ɵɵadvance();
201
201
  i0.ɵɵconditional(ctx.ShowPoweredBy ? 7 : -1);
202
- } }, dependencies: [MJButtonDirective], styles: [".mj-login-picker[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n max-width: 400px;\n }\n\n \n\n .mj-login-picker__heading[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-2xl, 1.5rem);\n font-weight: var(--mj-font-bold, 700);\n color: var(--mj-text-primary);\n text-align: left;\n }\n\n .mj-login-picker__subheading[_ngcontent-%COMP%] {\n margin: 0 0 var(--mj-space-5, 1.25rem);\n font-size: var(--mj-text-base, 1rem);\n color: var(--mj-text-secondary);\n text-align: left;\n }\n\n .mj-login-picker__list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2, 0.5rem);\n }\n\n \n\n .mj-login-picker__row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n text-align: left;\n }\n\n \n\n\n .mj-login-picker__row--default[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n }\n\n \n .mj-login-picker__row--fallback[_ngcontent-%COMP%] {\n justify-content: center;\n text-align: center;\n }\n\n .mj-login-picker__chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: var(--mj-radius-sm, 0.25rem);\n background: color-mix(in srgb, currentColor 12%, transparent);\n font-size: var(--mj-text-sm, 0.875rem);\n font-weight: 700;\n }\n\n \n .mj-login-picker__label[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n white-space: normal;\n }\n\n .mj-login-picker__pill[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n padding: 0.125rem var(--mj-space-2, 0.5rem);\n border-radius: var(--mj-radius-full, 999px);\n \n\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n font-size: var(--mj-text-xs, 0.75rem);\n font-weight: var(--mj-font-bold, 700);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n \n\n\n .mj-login-picker__chevron[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: var(--mj-text-sm, 0.875rem);\n color: var(--mj-text-muted);\n transition: color 120ms ease, transform 120ms ease;\n }\n\n .mj-login-picker__row[_ngcontent-%COMP%]:hover .mj-login-picker__chevron[_ngcontent-%COMP%], \n .mj-login-picker__row[_ngcontent-%COMP%]:focus-visible .mj-login-picker__chevron[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .mj-login-picker__chevron[_ngcontent-%COMP%] {\n transition: none;\n }\n\n .mj-login-picker__row[_ngcontent-%COMP%]:hover .mj-login-picker__chevron[_ngcontent-%COMP%], \n .mj-login-picker__row[_ngcontent-%COMP%]:focus-visible .mj-login-picker__chevron[_ngcontent-%COMP%] {\n transform: none;\n }\n }\n\n .mj-login-picker__attribution[_ngcontent-%COMP%] {\n margin: var(--mj-space-2, 0.5rem) 0 0;\n font-size: var(--mj-text-xs, 0.75rem);\n color: var(--mj-text-muted);\n text-align: center;\n }"] });
202
+ } }, dependencies: [MJButtonDirective], styles: [".mj-login-picker[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n \n\n max-width: var(--mj-login-picker-max-width, 400px);\n }\n\n \n\n .mj-login-picker__heading[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-2xl, 1.5rem);\n font-weight: var(--mj-font-bold, 700);\n \n\n\n\n\n\n\n color: var(--mj-login-panel-text, var(--mj-text-primary));\n text-align: left;\n }\n\n .mj-login-picker__subheading[_ngcontent-%COMP%] {\n margin: 0 0 var(--mj-space-5, 1.25rem);\n font-size: var(--mj-text-base, 1rem);\n color: var(--mj-login-panel-text-secondary, var(--mj-text-secondary));\n text-align: left;\n }\n\n .mj-login-picker__list[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2, 0.5rem);\n }\n\n \n\n .mj-login-picker__row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n text-align: left;\n }\n\n \n\n\n .mj-login-picker__row--default[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n }\n\n \n .mj-login-picker__row--fallback[_ngcontent-%COMP%] {\n justify-content: center;\n text-align: center;\n }\n\n .mj-login-picker__chip[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: var(--mj-radius-sm, 0.25rem);\n background: color-mix(in srgb, currentColor 12%, transparent);\n font-size: var(--mj-text-sm, 0.875rem);\n font-weight: 700;\n }\n\n \n .mj-login-picker__label[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n white-space: normal;\n }\n\n .mj-login-picker__pill[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n padding: 0.125rem var(--mj-space-2, 0.5rem);\n border-radius: var(--mj-radius-full, 999px);\n \n\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n font-size: var(--mj-text-xs, 0.75rem);\n font-weight: var(--mj-font-bold, 700);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n \n\n\n .mj-login-picker__chevron[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: var(--mj-text-sm, 0.875rem);\n color: var(--mj-login-panel-text-muted, var(--mj-text-muted));\n transition: color 120ms ease, transform 120ms ease;\n }\n\n .mj-login-picker__row[_ngcontent-%COMP%]:hover .mj-login-picker__chevron[_ngcontent-%COMP%], \n .mj-login-picker__row[_ngcontent-%COMP%]:focus-visible .mj-login-picker__chevron[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .mj-login-picker__chevron[_ngcontent-%COMP%] {\n transition: none;\n }\n\n .mj-login-picker__row[_ngcontent-%COMP%]:hover .mj-login-picker__chevron[_ngcontent-%COMP%], \n .mj-login-picker__row[_ngcontent-%COMP%]:focus-visible .mj-login-picker__chevron[_ngcontent-%COMP%] {\n transform: none;\n }\n }\n\n .mj-login-picker__attribution[_ngcontent-%COMP%] {\n margin: var(--mj-space-2, 0.5rem) 0 0;\n font-size: var(--mj-text-xs, 0.75rem);\n color: var(--mj-login-panel-text-muted, var(--mj-text-muted));\n text-align: center;\n }"] });
203
203
  }
204
204
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MJLoginPickerComponent, [{
205
205
  type: Component,
@@ -262,7 +262,7 @@ export class MJLoginPickerComponent {
262
262
  <p class="mj-login-picker__attribution">Powered by MemberJunction</p>
263
263
  }
264
264
  </div>
265
- `, styles: ["\n .mj-login-picker {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n max-width: 400px;\n }\n\n /* Left-aligned per the locked Login C direction \u2014 the heading, lede and rows share\n one leading edge; only the attribution centers. */\n .mj-login-picker__heading {\n margin: 0;\n font-size: var(--mj-text-2xl, 1.5rem);\n font-weight: var(--mj-font-bold, 700);\n color: var(--mj-text-primary);\n text-align: left;\n }\n\n .mj-login-picker__subheading {\n margin: 0 0 var(--mj-space-5, 1.25rem);\n font-size: var(--mj-text-base, 1rem);\n color: var(--mj-text-secondary);\n text-align: left;\n }\n\n .mj-login-picker__list {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2, 0.5rem);\n }\n\n /* Layout only \u2014 every visual affordance of the row (fill, radius, focus ring,\n hit target) belongs to the mjButton directive and is deliberately not restated. */\n .mj-login-picker__row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n text-align: left;\n }\n\n /* The default provider reads as the recommended path. Border only \u2014 fill, radius, focus\n ring and hit target all still come from the mjButton directive, and this targets the\n picker's own row class rather than .mj-btn, so the directive stays authoritative. */\n .mj-login-picker__row--default {\n border-color: var(--mj-brand-primary);\n }\n\n /* No icon chip or chevron to align against, so this one centres. */\n .mj-login-picker__row--fallback {\n justify-content: center;\n text-align: center;\n }\n\n .mj-login-picker__chip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: var(--mj-radius-sm, 0.25rem);\n background: color-mix(in srgb, currentColor 12%, transparent);\n font-size: var(--mj-text-sm, 0.875rem);\n font-weight: 700;\n }\n\n /* Long provider names wrap instead of forcing horizontal overflow on narrow screens. */\n .mj-login-picker__label {\n flex: 1 1 auto;\n min-width: 0;\n white-space: normal;\n }\n\n .mj-login-picker__pill {\n flex: 0 0 auto;\n padding: 0.125rem var(--mj-space-2, 0.5rem);\n border-radius: var(--mj-radius-full, 999px);\n /* Brand-tinted rather than currentColor \u2014 the default provider is the one call to\n action on the surface, and Login C gives it the brand accent. */\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n font-size: var(--mj-text-xs, 0.75rem);\n font-weight: var(--mj-font-bold, 700);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n /* Trailing affordance from the locked login mockup \u2014 signals that a row navigates\n away rather than toggling in place. Decorative, so it is aria-hidden and the row's\n accessible name still comes from the directive's ariaLabel. */\n .mj-login-picker__chevron {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: var(--mj-text-sm, 0.875rem);\n color: var(--mj-text-muted);\n transition: color 120ms ease, transform 120ms ease;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .mj-login-picker__chevron {\n transition: none;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n transform: none;\n }\n }\n\n .mj-login-picker__attribution {\n margin: var(--mj-space-2, 0.5rem) 0 0;\n font-size: var(--mj-text-xs, 0.75rem);\n color: var(--mj-text-muted);\n text-align: center;\n }\n "] }]
265
+ `, styles: ["\n .mj-login-picker {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n /* From the login token group so a themed deployment can widen or narrow the\n sign-in column without reaching into this component's internals. */\n max-width: var(--mj-login-picker-max-width, 400px);\n }\n\n /* Left-aligned per the locked Login C direction \u2014 the heading, lede and rows share\n one leading edge; only the attribution centers. */\n .mj-login-picker__heading {\n margin: 0;\n font-size: var(--mj-text-2xl, 1.5rem);\n font-weight: var(--mj-font-bold, 700);\n /* LOGIN PANEL TOKEN FIRST, semantic token as the fallback \u2014 and the same pattern on the\n lede and attribution below. The pitch of the login surface is \"override tokens, never\n write CSS against this DOM\"; without this the heading kept --mj-text-primary while the\n panel behind it took --mj-login-panel-bg, so the first thing a white-label deployment\n does (a dark panel in light mode) left a near-black heading on it and the only way out\n was piercing into these internals. Unset tokens fall through to the semantics, so an\n app that themes nothing is byte-identical. */\n color: var(--mj-login-panel-text, var(--mj-text-primary));\n text-align: left;\n }\n\n .mj-login-picker__subheading {\n margin: 0 0 var(--mj-space-5, 1.25rem);\n font-size: var(--mj-text-base, 1rem);\n color: var(--mj-login-panel-text-secondary, var(--mj-text-secondary));\n text-align: left;\n }\n\n .mj-login-picker__list {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2, 0.5rem);\n }\n\n /* Layout only \u2014 every visual affordance of the row (fill, radius, focus ring,\n hit target) belongs to the mjButton directive and is deliberately not restated. */\n .mj-login-picker__row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n text-align: left;\n }\n\n /* The default provider reads as the recommended path. Border only \u2014 fill, radius, focus\n ring and hit target all still come from the mjButton directive, and this targets the\n picker's own row class rather than .mj-btn, so the directive stays authoritative. */\n .mj-login-picker__row--default {\n border-color: var(--mj-brand-primary);\n }\n\n /* No icon chip or chevron to align against, so this one centres. */\n .mj-login-picker__row--fallback {\n justify-content: center;\n text-align: center;\n }\n\n .mj-login-picker__chip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: var(--mj-radius-sm, 0.25rem);\n background: color-mix(in srgb, currentColor 12%, transparent);\n font-size: var(--mj-text-sm, 0.875rem);\n font-weight: 700;\n }\n\n /* Long provider names wrap instead of forcing horizontal overflow on narrow screens. */\n .mj-login-picker__label {\n flex: 1 1 auto;\n min-width: 0;\n white-space: normal;\n }\n\n .mj-login-picker__pill {\n flex: 0 0 auto;\n padding: 0.125rem var(--mj-space-2, 0.5rem);\n border-radius: var(--mj-radius-full, 999px);\n /* Brand-tinted rather than currentColor \u2014 the default provider is the one call to\n action on the surface, and Login C gives it the brand accent. */\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n font-size: var(--mj-text-xs, 0.75rem);\n font-weight: var(--mj-font-bold, 700);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n /* Trailing affordance from the locked login mockup \u2014 signals that a row navigates\n away rather than toggling in place. Decorative, so it is aria-hidden and the row's\n accessible name still comes from the directive's ariaLabel. */\n .mj-login-picker__chevron {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: var(--mj-text-sm, 0.875rem);\n color: var(--mj-login-panel-text-muted, var(--mj-text-muted));\n transition: color 120ms ease, transform 120ms ease;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .mj-login-picker__chevron {\n transition: none;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n transform: none;\n }\n }\n\n .mj-login-picker__attribution {\n margin: var(--mj-space-2, 0.5rem) 0 0;\n font-size: var(--mj-text-xs, 0.75rem);\n color: var(--mj-login-panel-text-muted, var(--mj-text-muted));\n text-align: center;\n }\n "] }]
266
266
  }], null, { Providers: [{
267
267
  type: Input
268
268
  }], Heading: [{
@@ -280,5 +280,5 @@ export class MJLoginPickerComponent {
280
280
  }], FallbackSelected: [{
281
281
  type: Output
282
282
  }] }); })();
283
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJLoginPickerComponent, { className: "MJLoginPickerComponent", filePath: "src/lib/login-picker.component.ts", lineNumber: 232 }); })();
283
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MJLoginPickerComponent, { className: "MJLoginPickerComponent", filePath: "src/lib/login-picker.component.ts", lineNumber: 241 }); })();
284
284
  //# sourceMappingURL=login-picker.component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"login-picker.component.js","sourceRoot":"","sources":["../../src/lib/login-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport type { PublicAuthProviderInfo } from '@memberjunction/core';\n\n/**\n * Brand keys the picker knows how to render as a coloured chip. Anything else falls back to a\n * neutral chip with the provider's Font Awesome icon (or its initial).\n */\nconst BRAND_ICON_CLASSES: Readonly<Record<string, string>> = {\n msal: 'fa-brands fa-microsoft',\n microsoft: 'fa-brands fa-microsoft',\n google: 'fa-brands fa-google',\n okta: 'fa-solid fa-circle-half-stroke',\n auth0: 'fa-solid fa-shield-halved',\n cognito: 'fa-brands fa-aws',\n workos: 'fa-solid fa-building-lock',\n 'magic-link': 'fa-solid fa-wand-magic-sparkles'\n};\n\n/**\n * Reusable, app-agnostic multi-IdP login picker.\n *\n * Presentational by design: it takes a provider catalog in and emits the user's choice out. It\n * owns no routing, no branding, and no knowledge of which app embeds it, so Explorer and any\n * other MJ application get the identical accessible picker by dropping in the element and\n * supplying their own surrounding login surface.\n *\n * Accessibility comes from the shared `mjButton` directive (focus ring, hit target, disabled\n * semantics) rather than from styles restated here, so it cannot drift from the rest of the app.\n *\n * @example\n * ```html\n * <mj-login-picker\n * [Providers]=\"Catalog\"\n * [Busy]=\"SigningIn\"\n * (ProviderSelected)=\"OnProviderSelected($event)\">\n * </mj-login-picker>\n * ```\n */\n@Component({\n selector: 'mj-login-picker',\n standalone: true,\n imports: [MJButtonDirective],\n template: `\n <div class=\"mj-login-picker\">\n @if (Heading) {\n <h3 class=\"mj-login-picker__heading\">{{ Heading }}</h3>\n }\n @if (Subheading) {\n <p class=\"mj-login-picker__subheading\">{{ Subheading }}</p>\n }\n\n <div class=\"mj-login-picker__list\" role=\"group\" [attr.aria-label]=\"Heading || 'Sign-in options'\">\n @for (provider of Providers; track provider.name) {\n <button\n mjButton\n [variant]=\"IsSingleProvider ? 'primary' : 'secondary'\"\n size=\"lg\"\n class=\"mj-login-picker__row\"\n [class.mj-login-picker__row--default]=\"provider.isDefault && !IsSingleProvider\"\n type=\"button\"\n [disabled]=\"Busy\"\n [ariaLabel]=\"LabelFor(provider)\"\n (click)=\"Select(provider)\">\n <span class=\"mj-login-picker__chip\" aria-hidden=\"true\">\n @if (IconClassFor(provider); as iconClass) {\n <i [class]=\"iconClass\"></i>\n } @else {\n {{ InitialFor(provider) }}\n }\n </span>\n <span class=\"mj-login-picker__label\">{{ LabelFor(provider) }}</span>\n @if (provider.isDefault && !IsSingleProvider) {\n <span class=\"mj-login-picker__pill\">Default</span>\n }\n <span class=\"mj-login-picker__chevron\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </span>\n </button>\n }\n </div>\n\n <!-- Empty catalog: the deployment is configured through config/env with nothing published,\n so there is no provider to name. Opt-in via FallbackCtaLabel — an app that passes\n nothing renders nothing, which is the prior behaviour. -->\n @if (!Providers.length && FallbackCtaLabel) {\n <button\n mjButton\n variant=\"primary\"\n size=\"lg\"\n class=\"mj-login-picker__row mj-login-picker__row--fallback\"\n type=\"button\"\n [disabled]=\"Busy\"\n (click)=\"FallbackSelected.emit()\">\n {{ FallbackCtaLabel }}\n </button>\n }\n\n @if (ShowPoweredBy) {\n <p class=\"mj-login-picker__attribution\">Powered by MemberJunction</p>\n }\n </div>\n `,\n styles: [\n `\n .mj-login-picker {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n max-width: 400px;\n }\n\n /* Left-aligned per the locked Login C direction — the heading, lede and rows share\n one leading edge; only the attribution centers. */\n .mj-login-picker__heading {\n margin: 0;\n font-size: var(--mj-text-2xl, 1.5rem);\n font-weight: var(--mj-font-bold, 700);\n color: var(--mj-text-primary);\n text-align: left;\n }\n\n .mj-login-picker__subheading {\n margin: 0 0 var(--mj-space-5, 1.25rem);\n font-size: var(--mj-text-base, 1rem);\n color: var(--mj-text-secondary);\n text-align: left;\n }\n\n .mj-login-picker__list {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2, 0.5rem);\n }\n\n /* Layout only — every visual affordance of the row (fill, radius, focus ring,\n hit target) belongs to the mjButton directive and is deliberately not restated. */\n .mj-login-picker__row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n text-align: left;\n }\n\n /* The default provider reads as the recommended path. Border only — fill, radius, focus\n ring and hit target all still come from the mjButton directive, and this targets the\n picker's own row class rather than .mj-btn, so the directive stays authoritative. */\n .mj-login-picker__row--default {\n border-color: var(--mj-brand-primary);\n }\n\n /* No icon chip or chevron to align against, so this one centres. */\n .mj-login-picker__row--fallback {\n justify-content: center;\n text-align: center;\n }\n\n .mj-login-picker__chip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: var(--mj-radius-sm, 0.25rem);\n background: color-mix(in srgb, currentColor 12%, transparent);\n font-size: var(--mj-text-sm, 0.875rem);\n font-weight: 700;\n }\n\n /* Long provider names wrap instead of forcing horizontal overflow on narrow screens. */\n .mj-login-picker__label {\n flex: 1 1 auto;\n min-width: 0;\n white-space: normal;\n }\n\n .mj-login-picker__pill {\n flex: 0 0 auto;\n padding: 0.125rem var(--mj-space-2, 0.5rem);\n border-radius: var(--mj-radius-full, 999px);\n /* Brand-tinted rather than currentColor — the default provider is the one call to\n action on the surface, and Login C gives it the brand accent. */\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n font-size: var(--mj-text-xs, 0.75rem);\n font-weight: var(--mj-font-bold, 700);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n /* Trailing affordance from the locked login mockup — signals that a row navigates\n away rather than toggling in place. Decorative, so it is aria-hidden and the row's\n accessible name still comes from the directive's ariaLabel. */\n .mj-login-picker__chevron {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: var(--mj-text-sm, 0.875rem);\n color: var(--mj-text-muted);\n transition: color 120ms ease, transform 120ms ease;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .mj-login-picker__chevron {\n transition: none;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n transform: none;\n }\n }\n\n .mj-login-picker__attribution {\n margin: var(--mj-space-2, 0.5rem) 0 0;\n font-size: var(--mj-text-xs, 0.75rem);\n color: var(--mj-text-muted);\n text-align: center;\n }\n `\n ]\n})\nexport class MJLoginPickerComponent {\n /** Providers to offer, already ordered by the caller. */\n @Input() Providers: PublicAuthProviderInfo[] = [];\n\n /** Optional heading rendered above the list. */\n @Input() Heading: string | null = 'Log in';\n\n /** Optional supporting line rendered under the heading. */\n @Input() Subheading: string | null = null;\n\n /**\n * Disables every row — set while a sign-in is being initiated so a second click cannot\n * start a competing redirect.\n */\n @Input() Busy = false;\n\n /**\n * Whether to render the \"Powered by MemberJunction\" attribution.\n *\n * On by default, and a host-supplied flag rather than a code change, because full\n * white-labelling is a commercial entitlement: a tenant that has paid to remove the\n * attribution must be satisfiable by configuration alone.\n */\n @Input() ShowPoweredBy = true;\n\n /**\n * Label for the call to action shown when the catalog published nothing.\n *\n * Lets one component cover all three states — 2+ providers (a list), exactly one (a single\n * primary CTA naming it), and none at all (this generic CTA, for deployments still configured\n * through `mj.config.cjs` / `AUTH_TYPE`). Null renders nothing, which is the prior behaviour\n * for hosts that handle the empty case themselves.\n */\n @Input() FallbackCtaLabel: string | null = null;\n\n /** Emitted with the chosen provider. The host decides what signing in means. */\n @Output() ProviderSelected = new EventEmitter<PublicAuthProviderInfo>();\n\n /** Emitted when the empty-catalog CTA is clicked. The host starts its configured sign-in. */\n @Output() FallbackSelected = new EventEmitter<void>();\n\n /** A single option is not a choice — it renders as one primary call to action. */\n public get IsSingleProvider(): boolean {\n return this.Providers.length === 1;\n }\n\n /** \"Continue with Okta\" — the conventional modern auth phrasing. */\n public LabelFor(provider: PublicAuthProviderInfo): string {\n return `Continue with ${provider.displayName || provider.name}`;\n }\n\n /**\n * Resolves the icon class for a provider: an explicit `Icon` from metadata wins, otherwise\n * a known brand mapping for the driver, otherwise null (the chip falls back to an initial).\n */\n public IconClassFor(provider: PublicAuthProviderInfo): string | null {\n if (provider.icon) {\n return provider.icon.startsWith('fa-') ? provider.icon : (BRAND_ICON_CLASSES[provider.icon.toLowerCase()] ?? null);\n }\n return BRAND_ICON_CLASSES[provider.driverClass?.toLowerCase()] ?? null;\n }\n\n /** Fallback chip content when no icon resolves. */\n public InitialFor(provider: PublicAuthProviderInfo): string {\n return (provider.displayName || provider.name || '?').charAt(0).toUpperCase();\n }\n\n public Select(provider: PublicAuthProviderInfo): void {\n if (!this.Busy) {\n this.ProviderSelected.emit(provider);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"login-picker.component.js","sourceRoot":"","sources":["../../src/lib/login-picker.component.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventEmitter, Input, Output } from '@angular/core';\nimport { MJButtonDirective } from '@memberjunction/ng-ui-components';\nimport type { PublicAuthProviderInfo } from '@memberjunction/core';\n\n/**\n * Brand keys the picker knows how to render as a coloured chip. Anything else falls back to a\n * neutral chip with the provider's Font Awesome icon (or its initial).\n */\nconst BRAND_ICON_CLASSES: Readonly<Record<string, string>> = {\n msal: 'fa-brands fa-microsoft',\n microsoft: 'fa-brands fa-microsoft',\n google: 'fa-brands fa-google',\n okta: 'fa-solid fa-circle-half-stroke',\n auth0: 'fa-solid fa-shield-halved',\n cognito: 'fa-brands fa-aws',\n workos: 'fa-solid fa-building-lock',\n 'magic-link': 'fa-solid fa-wand-magic-sparkles'\n};\n\n/**\n * Reusable, app-agnostic multi-IdP login picker.\n *\n * Presentational by design: it takes a provider catalog in and emits the user's choice out. It\n * owns no routing, no branding, and no knowledge of which app embeds it, so Explorer and any\n * other MJ application get the identical accessible picker by dropping in the element and\n * supplying their own surrounding login surface.\n *\n * Accessibility comes from the shared `mjButton` directive (focus ring, hit target, disabled\n * semantics) rather than from styles restated here, so it cannot drift from the rest of the app.\n *\n * @example\n * ```html\n * <mj-login-picker\n * [Providers]=\"Catalog\"\n * [Busy]=\"SigningIn\"\n * (ProviderSelected)=\"OnProviderSelected($event)\">\n * </mj-login-picker>\n * ```\n */\n@Component({\n selector: 'mj-login-picker',\n standalone: true,\n imports: [MJButtonDirective],\n template: `\n <div class=\"mj-login-picker\">\n @if (Heading) {\n <h3 class=\"mj-login-picker__heading\">{{ Heading }}</h3>\n }\n @if (Subheading) {\n <p class=\"mj-login-picker__subheading\">{{ Subheading }}</p>\n }\n\n <div class=\"mj-login-picker__list\" role=\"group\" [attr.aria-label]=\"Heading || 'Sign-in options'\">\n @for (provider of Providers; track provider.name) {\n <button\n mjButton\n [variant]=\"IsSingleProvider ? 'primary' : 'secondary'\"\n size=\"lg\"\n class=\"mj-login-picker__row\"\n [class.mj-login-picker__row--default]=\"provider.isDefault && !IsSingleProvider\"\n type=\"button\"\n [disabled]=\"Busy\"\n [ariaLabel]=\"LabelFor(provider)\"\n (click)=\"Select(provider)\">\n <span class=\"mj-login-picker__chip\" aria-hidden=\"true\">\n @if (IconClassFor(provider); as iconClass) {\n <i [class]=\"iconClass\"></i>\n } @else {\n {{ InitialFor(provider) }}\n }\n </span>\n <span class=\"mj-login-picker__label\">{{ LabelFor(provider) }}</span>\n @if (provider.isDefault && !IsSingleProvider) {\n <span class=\"mj-login-picker__pill\">Default</span>\n }\n <span class=\"mj-login-picker__chevron\" aria-hidden=\"true\">\n <i class=\"fa-solid fa-arrow-right\"></i>\n </span>\n </button>\n }\n </div>\n\n <!-- Empty catalog: the deployment is configured through config/env with nothing published,\n so there is no provider to name. Opt-in via FallbackCtaLabel — an app that passes\n nothing renders nothing, which is the prior behaviour. -->\n @if (!Providers.length && FallbackCtaLabel) {\n <button\n mjButton\n variant=\"primary\"\n size=\"lg\"\n class=\"mj-login-picker__row mj-login-picker__row--fallback\"\n type=\"button\"\n [disabled]=\"Busy\"\n (click)=\"FallbackSelected.emit()\">\n {{ FallbackCtaLabel }}\n </button>\n }\n\n @if (ShowPoweredBy) {\n <p class=\"mj-login-picker__attribution\">Powered by MemberJunction</p>\n }\n </div>\n `,\n styles: [\n `\n .mj-login-picker {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n /* From the login token group so a themed deployment can widen or narrow the\n sign-in column without reaching into this component's internals. */\n max-width: var(--mj-login-picker-max-width, 400px);\n }\n\n /* Left-aligned per the locked Login C direction — the heading, lede and rows share\n one leading edge; only the attribution centers. */\n .mj-login-picker__heading {\n margin: 0;\n font-size: var(--mj-text-2xl, 1.5rem);\n font-weight: var(--mj-font-bold, 700);\n /* LOGIN PANEL TOKEN FIRST, semantic token as the fallback — and the same pattern on the\n lede and attribution below. The pitch of the login surface is \"override tokens, never\n write CSS against this DOM\"; without this the heading kept --mj-text-primary while the\n panel behind it took --mj-login-panel-bg, so the first thing a white-label deployment\n does (a dark panel in light mode) left a near-black heading on it and the only way out\n was piercing into these internals. Unset tokens fall through to the semantics, so an\n app that themes nothing is byte-identical. */\n color: var(--mj-login-panel-text, var(--mj-text-primary));\n text-align: left;\n }\n\n .mj-login-picker__subheading {\n margin: 0 0 var(--mj-space-5, 1.25rem);\n font-size: var(--mj-text-base, 1rem);\n color: var(--mj-login-panel-text-secondary, var(--mj-text-secondary));\n text-align: left;\n }\n\n .mj-login-picker__list {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2, 0.5rem);\n }\n\n /* Layout only — every visual affordance of the row (fill, radius, focus ring,\n hit target) belongs to the mjButton directive and is deliberately not restated. */\n .mj-login-picker__row {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3, 0.75rem);\n width: 100%;\n text-align: left;\n }\n\n /* The default provider reads as the recommended path. Border only — fill, radius, focus\n ring and hit target all still come from the mjButton directive, and this targets the\n picker's own row class rather than .mj-btn, so the directive stays authoritative. */\n .mj-login-picker__row--default {\n border-color: var(--mj-brand-primary);\n }\n\n /* No icon chip or chevron to align against, so this one centres. */\n .mj-login-picker__row--fallback {\n justify-content: center;\n text-align: center;\n }\n\n .mj-login-picker__chip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: 0 0 auto;\n width: 1.75rem;\n height: 1.75rem;\n border-radius: var(--mj-radius-sm, 0.25rem);\n background: color-mix(in srgb, currentColor 12%, transparent);\n font-size: var(--mj-text-sm, 0.875rem);\n font-weight: 700;\n }\n\n /* Long provider names wrap instead of forcing horizontal overflow on narrow screens. */\n .mj-login-picker__label {\n flex: 1 1 auto;\n min-width: 0;\n white-space: normal;\n }\n\n .mj-login-picker__pill {\n flex: 0 0 auto;\n padding: 0.125rem var(--mj-space-2, 0.5rem);\n border-radius: var(--mj-radius-full, 999px);\n /* Brand-tinted rather than currentColor — the default provider is the one call to\n action on the surface, and Login C gives it the brand accent. */\n color: var(--mj-brand-primary);\n background: color-mix(in srgb, var(--mj-brand-primary) 12%, transparent);\n font-size: var(--mj-text-xs, 0.75rem);\n font-weight: var(--mj-font-bold, 700);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n }\n\n /* Trailing affordance from the locked login mockup — signals that a row navigates\n away rather than toggling in place. Decorative, so it is aria-hidden and the row's\n accessible name still comes from the directive's ariaLabel. */\n .mj-login-picker__chevron {\n display: inline-flex;\n align-items: center;\n flex: 0 0 auto;\n font-size: var(--mj-text-sm, 0.875rem);\n color: var(--mj-login-panel-text-muted, var(--mj-text-muted));\n transition: color 120ms ease, transform 120ms ease;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n color: var(--mj-brand-primary);\n transform: translateX(2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .mj-login-picker__chevron {\n transition: none;\n }\n\n .mj-login-picker__row:hover .mj-login-picker__chevron,\n .mj-login-picker__row:focus-visible .mj-login-picker__chevron {\n transform: none;\n }\n }\n\n .mj-login-picker__attribution {\n margin: var(--mj-space-2, 0.5rem) 0 0;\n font-size: var(--mj-text-xs, 0.75rem);\n color: var(--mj-login-panel-text-muted, var(--mj-text-muted));\n text-align: center;\n }\n `\n ]\n})\nexport class MJLoginPickerComponent {\n /** Providers to offer, already ordered by the caller. */\n @Input() Providers: PublicAuthProviderInfo[] = [];\n\n /** Optional heading rendered above the list. */\n @Input() Heading: string | null = 'Log in';\n\n /** Optional supporting line rendered under the heading. */\n @Input() Subheading: string | null = null;\n\n /**\n * Disables every row — set while a sign-in is being initiated so a second click cannot\n * start a competing redirect.\n */\n @Input() Busy = false;\n\n /**\n * Whether to render the \"Powered by MemberJunction\" attribution.\n *\n * On by default, and a host-supplied flag rather than a code change, because full\n * white-labelling is a commercial entitlement: a tenant that has paid to remove the\n * attribution must be satisfiable by configuration alone.\n */\n @Input() ShowPoweredBy = true;\n\n /**\n * Label for the call to action shown when the catalog published nothing.\n *\n * Lets one component cover all three states — 2+ providers (a list), exactly one (a single\n * primary CTA naming it), and none at all (this generic CTA, for deployments still configured\n * through `mj.config.cjs` / `AUTH_TYPE`). Null renders nothing, which is the prior behaviour\n * for hosts that handle the empty case themselves.\n */\n @Input() FallbackCtaLabel: string | null = null;\n\n /** Emitted with the chosen provider. The host decides what signing in means. */\n @Output() ProviderSelected = new EventEmitter<PublicAuthProviderInfo>();\n\n /** Emitted when the empty-catalog CTA is clicked. The host starts its configured sign-in. */\n @Output() FallbackSelected = new EventEmitter<void>();\n\n /** A single option is not a choice — it renders as one primary call to action. */\n public get IsSingleProvider(): boolean {\n return this.Providers.length === 1;\n }\n\n /** \"Continue with Okta\" — the conventional modern auth phrasing. */\n public LabelFor(provider: PublicAuthProviderInfo): string {\n return `Continue with ${provider.displayName || provider.name}`;\n }\n\n /**\n * Resolves the icon class for a provider: an explicit `Icon` from metadata wins, otherwise\n * a known brand mapping for the driver, otherwise null (the chip falls back to an initial).\n */\n public IconClassFor(provider: PublicAuthProviderInfo): string | null {\n if (provider.icon) {\n return provider.icon.startsWith('fa-') ? provider.icon : (BRAND_ICON_CLASSES[provider.icon.toLowerCase()] ?? null);\n }\n return BRAND_ICON_CLASSES[provider.driverClass?.toLowerCase()] ?? null;\n }\n\n /** Fallback chip content when no icon resolves. */\n public InitialFor(provider: PublicAuthProviderInfo): string {\n return (provider.displayName || provider.name || '?').charAt(0).toUpperCase();\n }\n\n public Select(provider: PublicAuthProviderInfo): void {\n if (!this.Busy) {\n this.ProviderSelected.emit(provider);\n }\n }\n}\n"]}