@dereekb/dbx-firebase 13.11.4 → 13.11.5

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.
@@ -1,15 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { input, computed, output, ChangeDetectionStrategy, Component, inject, Injectable, signal, effect, Directive, viewChild, provideAppInitializer, makeEnvironmentProviders } from '@angular/core';
3
- import * as i1$1 from '@dereekb/dbx-web';
4
- import { DbxBasicLoadingComponent, DbxErrorComponent, DbxButtonComponent, DbxAvatarComponent, DbxLoadingComponent, DbxButtonSpacerDirective, AbstractDbxSelectionListWrapperDirective, DbxListWrapperComponentImportsModule, provideDbxListViewWrapper, DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxSelectionListViewDirective, DbxSelectionValueListViewComponentImportsModule, provideDbxListView, DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxValueListViewItemComponent, DbxSpacerDirective, DbxActionConfirmDirective, DbxActionSnackbarErrorDirective, DbxContentPitDirective, DbxDetailBlockComponent, DbxClickToCopyTextComponent } from '@dereekb/dbx-web';
3
+ import * as i1 from '@dereekb/dbx-web';
4
+ import { DbxBasicLoadingComponent, DbxErrorComponent, DbxButtonComponent, DbxAvatarComponent, DbxButtonSpacerDirective, DbxActionSnackbarErrorDirective, AbstractDbxSelectionListWrapperDirective, DbxListWrapperComponentImportsModule, DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxSelectionListViewDirective, DbxSelectionValueListViewComponentImportsModule, provideDbxListView, DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE, AbstractDbxValueListViewItemComponent, provideDbxListViewWrapper, DbxSpacerDirective, DbxActionConfirmDirective, DbxContentPitDirective, DbxDetailBlockComponent, DbxClickToCopyTextComponent } from '@dereekb/dbx-web';
5
5
  import { readableError, SPACE_STRING_SPLIT_JOIN, separateValues, generatePkceCodeVerifier, generatePkceCodeChallenge } from '@dereekb/util';
6
- import { DbxInjectionComponent, DBX_INJECTION_COMPONENT_DATA, DbxRouterService, dbxRouteParamReaderInstance, completeOnDestroy, DbxActionDirective, DbxActionHandlerDirective, DbxActionButtonDirective, DbxActionEnforceModifiedDirective, DbxAppAuthRouterService } from '@dereekb/dbx-core';
6
+ import { DbxInjectionComponent, DbxActionDirective, DbxActionHandlerDirective, DbxActionValueDirective, DbxActionButtonDirective, DBX_INJECTION_COMPONENT_DATA, DbxRouterService, dbxRouteParamReaderInstance, completeOnDestroy, DbxActionEnforceModifiedDirective, DbxAppAuthRouterService } from '@dereekb/dbx-core';
7
+ import { of, map, first, switchMap, tap, BehaviorSubject } from 'rxjs';
8
+ import * as i1$1 from '@dereekb/dbx-form';
9
+ import { dbxForgeListSelectionField, AbstractConfigAsyncForgeFormDirective, DbxForgeFormComponentImportsModule, dbxForgeFormComponentProviders, DBX_FORGE_FORM_COMPONENT_TEMPLATE, DbxActionFormDirective, dbxForgeValueSelectionField, dbxForgeTextField, dbxForgeSearchableStringChipField, isWebsiteUrlValidator, dbxForgeContainer, dbxForgePickableChipField, pickableValueFieldValuesConfigForStaticLabeledValues, DbxFormSourceDirective, DbxFormValueChangeDirective } from '@dereekb/dbx-form';
10
+ import { successResult } from '@dereekb/rxjs';
7
11
  import { toSignal } from '@angular/core/rxjs-interop';
8
12
  import { DbxFirebaseAuthService, AbstractDbxFirebaseDocumentStore, firebaseDocumentStoreCreateFunction, firebaseDocumentStoreUpdateFunction, firebaseDocumentStoreDeleteFunction, AbstractDbxFirebaseCollectionStore, DbxFirebaseCollectionStoreDirective, provideDbxFirebaseCollectionStoreDirective, DbxFirebaseCollectionListDirective, DbxFirebaseCollectionChangeDirective, DbxFirebaseDocumentStoreDirective, provideDbxFirebaseDocumentStoreDirective } from '@dereekb/dbx-firebase';
9
13
  import { HttpClient } from '@angular/common/http';
10
- import { first, switchMap, of, map, BehaviorSubject, tap } from 'rxjs';
11
- import * as i1 from '@dereekb/dbx-form';
12
- import { dbxForgeValueSelectionField, dbxForgeTextField, dbxForgeSearchableStringChipField, isWebsiteUrlValidator, dbxForgeContainer, dbxForgePickableChipField, pickableValueFieldValuesConfigForStaticLabeledValues, AbstractConfigAsyncForgeFormDirective, DbxForgeFormComponentImportsModule, dbxForgeFormComponentProviders, DBX_FORGE_FORM_COMPONENT_TEMPLATE, DbxActionFormDirective, DbxFormSourceDirective, DbxFormValueChangeDirective } from '@dereekb/dbx-form';
13
14
  import { ALL_OIDC_TOKEN_ENDPOINT_AUTH_METHOD_OPTIONS, PRIVATE_KEY_JWT_TOKEN_ENDPOINT_AUTH_METHOD, OidcModelFunctions, OidcModelFirestoreCollections, OIDC_ENTRY_CLIENT_TYPE, oidcGrantEntriesByUidQuery } from '@dereekb/firebase';
14
15
  import { DatePipe, CommonModule } from '@angular/common';
15
16
 
@@ -94,15 +95,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
94
95
  }]
95
96
  }], propDecorators: { loginStateCase: [{ type: i0.Input, args: [{ isSignal: true, alias: "loginStateCase", required: true }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], retryClick: [{ type: i0.Output, args: ["retryClick"] }] } });
96
97
 
98
+ /**
99
+ * Default required scopes — `openid` is mandatory for any OIDC flow, so the
100
+ * UI always treats it as not-deselectable.
101
+ */
102
+ const DEFAULT_OAUTH_CONSENT_REQUIRED_SCOPES = ['openid'];
97
103
  /**
98
104
  * Presentational component for the OIDC OAuth consent screen.
99
105
  *
100
- * Accepts an `OAuthInteractionLoginDetails` input that contains all client and scope
101
- * information. Renders the client name, logo, client URL, scopes (via `<dbx-injection>`),
102
- * error/loading states, and approve/deny action buttons.
106
+ * Wires up two `dbxAction` contexts an outer one for Approve (which hosts
107
+ * the scope-selection forge form via `dbxActionForm`) and a nested one for
108
+ * Deny (which carries no value). Buttons are bound by Angular DI's
109
+ * nearest-ancestor lookup: the Approve button picks up the outer action, the
110
+ * Deny button (wrapped in its own `<ng-container dbxAction>`) picks up the
111
+ * inner.
103
112
  *
104
- * Supports ng-content projection — content provided is rendered for the `'no_user'` state
105
- * (so apps can project a login view, mirroring `DbxFirebaseOAuthLoginViewComponent`).
113
+ * Supports ng-content projection — anything provided is rendered for the
114
+ * `'no_user'` state (so apps can project a login view, mirroring
115
+ * `DbxFirebaseOAuthLoginViewComponent`).
106
116
  *
107
117
  * @example
108
118
  * ```html
@@ -110,37 +120,46 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
110
120
  * [details]="loginDetails"
111
121
  * [consentStateCase]="'user'"
112
122
  * [scopeInjectionConfig]="scopeConfig"
113
- * (approveClick)="onApprove()"
114
- * (denyClick)="onDeny()">
123
+ * [approveHandler]="handleApprove"
124
+ * [denyHandler]="handleDeny">
115
125
  * </dbx-firebase-oauth-consent-view>
116
126
  * ```
117
127
  */
118
128
  class DbxFirebaseOAuthConsentViewComponent {
119
129
  details = input(...(ngDevMode ? [undefined, { debugName: "details" }] : /* istanbul ignore next */ []));
120
130
  consentStateCase = input.required(...(ngDevMode ? [{ debugName: "consentStateCase" }] : /* istanbul ignore next */ []));
121
- error = input(...(ngDevMode ? [undefined, { debugName: "error" }] : /* istanbul ignore next */ []));
122
131
  scopeInjectionConfig = input.required(...(ngDevMode ? [{ debugName: "scopeInjectionConfig" }] : /* istanbul ignore next */ []));
132
+ /**
133
+ * Scopes that cannot be deselected by the user. Forwarded to the scope
134
+ * view so it can render an "Always granted" hint. Defaults to `['openid']`.
135
+ */
136
+ requiredScopes = input(DEFAULT_OAUTH_CONSENT_REQUIRED_SCOPES, ...(ngDevMode ? [{ debugName: "requiredScopes" }] : /* istanbul ignore next */ []));
137
+ /**
138
+ * Approve handler — called with the form value when the Approve button
139
+ * triggers the outer action. Receives a `WorkUsingContext` to drive the
140
+ * action's loading/success/error pipeline.
141
+ */
142
+ approveHandler = input.required(...(ngDevMode ? [{ debugName: "approveHandler" }] : /* istanbul ignore next */ []));
143
+ /**
144
+ * Deny handler — called when the Deny button triggers the inner action.
145
+ * No value is passed (`dbxActionValue` provides an empty payload).
146
+ */
147
+ denyHandler = input.required(...(ngDevMode ? [{ debugName: "denyHandler" }] : /* istanbul ignore next */ []));
123
148
  clientName = computed(() => this.details()?.client_name ?? '', ...(ngDevMode ? [{ debugName: "clientName" }] : /* istanbul ignore next */ []));
124
149
  clientUri = computed(() => this.details()?.client_uri, ...(ngDevMode ? [{ debugName: "clientUri" }] : /* istanbul ignore next */ []));
125
150
  logoUri = computed(() => this.details()?.logo_uri, ...(ngDevMode ? [{ debugName: "logoUri" }] : /* istanbul ignore next */ []));
126
151
  scopes = computed(() => SPACE_STRING_SPLIT_JOIN.splitStrings(this.details()?.scopes ?? ''), ...(ngDevMode ? [{ debugName: "scopes" }] : /* istanbul ignore next */ []));
127
- resolvedError = computed(() => {
128
- const error = this.error();
129
- return typeof error === 'string' ? readableError('ERROR', error) : error;
130
- }, ...(ngDevMode ? [{ debugName: "resolvedError" }] : /* istanbul ignore next */ []));
131
- approveClick = output();
132
- denyClick = output();
133
- retryClick = output();
134
152
  resolvedScopeInjectionConfig = computed(() => {
135
153
  const data = {
136
154
  details: this.details(),
137
155
  scopes: this.scopes(),
138
- clientName: this.clientName()
156
+ clientName: this.clientName(),
157
+ requiredScopes: this.requiredScopes()
139
158
  };
140
159
  return { ...this.scopeInjectionConfig(), data };
141
160
  }, ...(ngDevMode ? [{ debugName: "resolvedScopeInjectionConfig" }] : /* istanbul ignore next */ []));
142
161
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
143
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-view", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: false, transformFunction: null }, consentStateCase: { classPropertyName: "consentStateCase", publicName: "consentStateCase", isSignal: true, isRequired: true, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, scopeInjectionConfig: { classPropertyName: "scopeInjectionConfig", publicName: "scopeInjectionConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { approveClick: "approveClick", denyClick: "denyClick", retryClick: "retryClick" }, host: { classAttribute: "d-block dbx-firebase-oauth-consent-view" }, ngImport: i0, template: `
162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-view", inputs: { details: { classPropertyName: "details", publicName: "details", isSignal: true, isRequired: false, transformFunction: null }, consentStateCase: { classPropertyName: "consentStateCase", publicName: "consentStateCase", isSignal: true, isRequired: true, transformFunction: null }, scopeInjectionConfig: { classPropertyName: "scopeInjectionConfig", publicName: "scopeInjectionConfig", isSignal: true, isRequired: true, transformFunction: null }, requiredScopes: { classPropertyName: "requiredScopes", publicName: "requiredScopes", isSignal: true, isRequired: false, transformFunction: null }, approveHandler: { classPropertyName: "approveHandler", publicName: "approveHandler", isSignal: true, isRequired: true, transformFunction: null }, denyHandler: { classPropertyName: "denyHandler", publicName: "denyHandler", isSignal: true, isRequired: true, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-oauth-consent-view" }, ngImport: i0, template: `
144
163
  <div class="dbx-firebase-oauth-consent-view">
145
164
  @switch (consentStateCase()) {
146
165
  @case ('unknown') {
@@ -149,13 +168,6 @@ class DbxFirebaseOAuthConsentViewComponent {
149
168
  @case ('no_user') {
150
169
  <ng-content></ng-content>
151
170
  }
152
- @case ('submitting') {
153
- <dbx-loading [loading]="true" text="Processing..."></dbx-loading>
154
- }
155
- @case ('error') {
156
- <dbx-button text="Retry" [raised]="true" (buttonClick)="retryClick.emit()"></dbx-button>
157
- <dbx-error [error]="resolvedError()"></dbx-error>
158
- }
159
171
  @case ('user') {
160
172
  <div class="dbx-firebase-oauth-consent-header">
161
173
  @if (clientName()) {
@@ -170,20 +182,32 @@ class DbxFirebaseOAuthConsentViewComponent {
170
182
  </span>
171
183
  </div>
172
184
  </div>
173
- <dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
174
- <div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
175
- <dbx-button text="Approve" [raised]="true" color="primary" (buttonClick)="approveClick.emit()"></dbx-button>
176
- <dbx-button-spacer></dbx-button-spacer>
177
- <dbx-button text="Deny" [flat]="true" color="warn" (buttonClick)="denyClick.emit()"></dbx-button>
185
+ @if (clientName()) {
186
+ <p class="dbx-firebase-oauth-consent-prompt">
187
+ <strong>{{ clientName() }}</strong>
188
+ is requesting these permissions:
189
+ </p>
190
+ }
191
+
192
+ <div dbxAction dbxActionSnackbarError [dbxActionHandler]="approveHandler()">
193
+ <dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
194
+
195
+ <div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
196
+ <dbx-button dbxActionButton text="Approve" [raised]="true" color="primary"></dbx-button>
197
+ <dbx-button-spacer></dbx-button-spacer>
198
+ <ng-container dbxAction dbxActionSnackbarError dbxActionValue [dbxActionHandler]="denyHandler()">
199
+ <dbx-button dbxActionButton text="Deny" [flat]="true" color="warn"></dbx-button>
200
+ </ng-container>
201
+ </div>
178
202
  </div>
179
203
  }
180
204
  }
181
205
  </div>
182
- `, isInline: true, styles: [".dbx-firebase-oauth-consent-view .dbx-firebase-oauth-consent-header-info{align-items:center;gap:12px}\n"], dependencies: [{ kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }, { kind: "component", type: DbxAvatarComponent, selector: "dbx-avatar", inputs: ["context", "avatarSelector", "avatarUid", "avatarUrl", "avatarKey", "avatarIcon", "avatarStyle", "avatarSize", "avatarHideOnError"] }, { kind: "component", type: DbxBasicLoadingComponent, selector: "dbx-basic-loading", inputs: ["diameter", "mode", "color", "text", "linear", "show", "loading", "error"] }, { kind: "component", type: DbxLoadingComponent, selector: "dbx-loading", inputs: ["padding", "show", "text", "mode", "color", "diameter", "linear", "loading", "error", "context"] }, { kind: "component", type: DbxErrorComponent, selector: "dbx-error", inputs: ["error", "iconOnly"], outputs: ["popoverOpened"] }, { kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }, { kind: "directive", type: DbxButtonSpacerDirective, selector: "dbx-button-spacer,[dbxButtonSpacer]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
206
+ `, isInline: true, styles: [".dbx-firebase-oauth-consent-view .dbx-firebase-oauth-consent-header-info{align-items:center;gap:12px}\n"], dependencies: [{ kind: "component", type: DbxInjectionComponent, selector: "dbx-injection, [dbxInjection], [dbx-injection]", inputs: ["config", "template"] }, { kind: "component", type: DbxAvatarComponent, selector: "dbx-avatar", inputs: ["context", "avatarSelector", "avatarUid", "avatarUrl", "avatarKey", "avatarIcon", "avatarStyle", "avatarSize", "avatarHideOnError"] }, { kind: "component", type: DbxBasicLoadingComponent, selector: "dbx-basic-loading", inputs: ["diameter", "mode", "color", "text", "linear", "show", "loading", "error"] }, { kind: "component", type: DbxButtonComponent, selector: "dbx-button", inputs: ["bar", "type", "buttonStyle", "color", "spinnerColor", "customButtonColor", "customTextColor", "customSpinnerColor", "basic", "tonal", "raised", "stroked", "flat", "iconOnly", "fab", "customContent", "allowClickPropagation", "mode"] }, { kind: "directive", type: DbxButtonSpacerDirective, selector: "dbx-button-spacer,[dbxButtonSpacer]" }, { kind: "directive", type: DbxActionDirective, selector: "dbx-action,[dbxAction]", exportAs: ["action", "dbxAction"] }, { kind: "directive", type: DbxActionHandlerDirective, selector: "[dbxActionHandler]", inputs: ["dbxActionHandler"] }, { kind: "directive", type: DbxActionValueDirective, selector: "dbxActionValue,[dbxActionValue]", inputs: ["dbxActionValue"] }, { kind: "directive", type: DbxActionButtonDirective, selector: "[dbxActionButton]", inputs: ["dbxActionButtonEcho"] }, { kind: "directive", type: DbxActionSnackbarErrorDirective, selector: "[dbxActionSnackbarError]", inputs: ["dbxActionSnackbarError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
183
207
  }
184
208
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentViewComponent, decorators: [{
185
209
  type: Component,
186
- args: [{ selector: 'dbx-firebase-oauth-consent-view', standalone: true, imports: [DbxInjectionComponent, DbxAvatarComponent, DbxBasicLoadingComponent, DbxLoadingComponent, DbxErrorComponent, DbxButtonComponent, DbxButtonSpacerDirective], template: `
210
+ args: [{ selector: 'dbx-firebase-oauth-consent-view', standalone: true, imports: [DbxInjectionComponent, DbxAvatarComponent, DbxBasicLoadingComponent, DbxButtonComponent, DbxButtonSpacerDirective, DbxActionDirective, DbxActionHandlerDirective, DbxActionValueDirective, DbxActionButtonDirective, DbxActionSnackbarErrorDirective], template: `
187
211
  <div class="dbx-firebase-oauth-consent-view">
188
212
  @switch (consentStateCase()) {
189
213
  @case ('unknown') {
@@ -192,13 +216,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
192
216
  @case ('no_user') {
193
217
  <ng-content></ng-content>
194
218
  }
195
- @case ('submitting') {
196
- <dbx-loading [loading]="true" text="Processing..."></dbx-loading>
197
- }
198
- @case ('error') {
199
- <dbx-button text="Retry" [raised]="true" (buttonClick)="retryClick.emit()"></dbx-button>
200
- <dbx-error [error]="resolvedError()"></dbx-error>
201
- }
202
219
  @case ('user') {
203
220
  <div class="dbx-firebase-oauth-consent-header">
204
221
  @if (clientName()) {
@@ -213,11 +230,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
213
230
  </span>
214
231
  </div>
215
232
  </div>
216
- <dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
217
- <div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
218
- <dbx-button text="Approve" [raised]="true" color="primary" (buttonClick)="approveClick.emit()"></dbx-button>
219
- <dbx-button-spacer></dbx-button-spacer>
220
- <dbx-button text="Deny" [flat]="true" color="warn" (buttonClick)="denyClick.emit()"></dbx-button>
233
+ @if (clientName()) {
234
+ <p class="dbx-firebase-oauth-consent-prompt">
235
+ <strong>{{ clientName() }}</strong>
236
+ is requesting these permissions:
237
+ </p>
238
+ }
239
+
240
+ <div dbxAction dbxActionSnackbarError [dbxActionHandler]="approveHandler()">
241
+ <dbx-injection [config]="resolvedScopeInjectionConfig()"></dbx-injection>
242
+
243
+ <div class="dbx-pt3 dbx-pb3 dbx-firebase-oauth-consent-actions">
244
+ <dbx-button dbxActionButton text="Approve" [raised]="true" color="primary"></dbx-button>
245
+ <dbx-button-spacer></dbx-button-spacer>
246
+ <ng-container dbxAction dbxActionSnackbarError dbxActionValue [dbxActionHandler]="denyHandler()">
247
+ <dbx-button dbxActionButton text="Deny" [flat]="true" color="warn"></dbx-button>
248
+ </ng-container>
249
+ </div>
221
250
  </div>
222
251
  }
223
252
  }
@@ -225,13 +254,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
225
254
  `, host: {
226
255
  class: 'd-block dbx-firebase-oauth-consent-view'
227
256
  }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".dbx-firebase-oauth-consent-view .dbx-firebase-oauth-consent-header-info{align-items:center;gap:12px}\n"] }]
228
- }], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: false }] }], consentStateCase: [{ type: i0.Input, args: [{ isSignal: true, alias: "consentStateCase", required: true }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], scopeInjectionConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeInjectionConfig", required: true }] }], approveClick: [{ type: i0.Output, args: ["approveClick"] }], denyClick: [{ type: i0.Output, args: ["denyClick"] }], retryClick: [{ type: i0.Output, args: ["retryClick"] }] } });
257
+ }], propDecorators: { details: [{ type: i0.Input, args: [{ isSignal: true, alias: "details", required: false }] }], consentStateCase: [{ type: i0.Input, args: [{ isSignal: true, alias: "consentStateCase", required: true }] }], scopeInjectionConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopeInjectionConfig", required: true }] }], requiredScopes: [{ type: i0.Input, args: [{ isSignal: true, alias: "requiredScopes", required: false }] }], approveHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "approveHandler", required: true }] }], denyHandler: [{ type: i0.Input, args: [{ isSignal: true, alias: "denyHandler", required: true }] }] } });
229
258
 
230
259
  /**
231
260
  * Abstract base class for consent scope view components.
232
261
  *
233
- * Provides typed access to the `DbxFirebaseOAuthConsentScopesViewData` injected
234
- * via `DBX_INJECTION_COMPONENT_DATA`. Subclasses only need to define a template.
262
+ * Provides typed access to the `DbxFirebaseOAuthConsentScopesViewData`
263
+ * injected via `DBX_INJECTION_COMPONENT_DATA`. Subclasses define the
264
+ * template that renders the requested scopes and (optionally) hosts a
265
+ * forge form decorated with `dbxActionForm`.
235
266
  *
236
267
  * @example
237
268
  * ```typescript
@@ -246,43 +277,200 @@ class AbstractDbxFirebaseOAuthConsentScopeViewComponent {
246
277
  clientName = computed(() => this.data?.clientName ?? '', ...(ngDevMode ? [{ debugName: "clientName" }] : /* istanbul ignore next */ []));
247
278
  clientUri = computed(() => this.data?.details?.client_uri, ...(ngDevMode ? [{ debugName: "clientUri" }] : /* istanbul ignore next */ []));
248
279
  logoUri = computed(() => this.data?.details?.logo_uri, ...(ngDevMode ? [{ debugName: "logoUri" }] : /* istanbul ignore next */ []));
280
+ requiredScopes = computed(() => this.data?.requiredScopes ?? [], ...(ngDevMode ? [{ debugName: "requiredScopes" }] : /* istanbul ignore next */ []));
281
+ isScopeRequired(scope) {
282
+ return this.requiredScopes().includes(scope);
283
+ }
249
284
  }
250
285
 
251
286
  /**
252
- * Standalone presentational component that renders a list of OAuth consent scopes.
287
+ * Selection-list wrapper used as the `listComponentClass` for the OIDC
288
+ * consent scope `dbxForgeListSelectionField`.
289
+ *
290
+ * Reuses the workspace's `dbx-list` selection infrastructure so the existing
291
+ * scope-row visual treatment (name + description) remains intact while the
292
+ * selection state participates in the surrounding `dbxAction`/`dbxActionForm`
293
+ * pipeline.
253
294
  *
254
295
  * @example
255
- * ```html
256
- * <dbx-firebase-oauth-consent-scope-list [scopes]="mappedScopes"></dbx-firebase-oauth-consent-scope-list>
296
+ * ```ts
297
+ * dbxForgeListSelectionField<OAuthConsentScope, DbxFirebaseOAuthConsentScopeListComponent, OidcScope>({
298
+ * key: 'grantedOIDCScopes',
299
+ * props: {
300
+ * listComponentClass: of(DbxFirebaseOAuthConsentScopeListComponent),
301
+ * readKey: (scope) => scope.name,
302
+ * state$: of(successResult(optionalScopes)),
303
+ * wrapped: false,
304
+ * maxHeight: 'none'
305
+ * }
306
+ * });
257
307
  * ```
258
308
  */
259
- class DbxFirebaseOAuthConsentScopeListComponent {
260
- scopes = input([], ...(ngDevMode ? [{ debugName: "scopes" }] : /* istanbul ignore next */ []));
309
+ class DbxFirebaseOAuthConsentScopeListComponent extends AbstractDbxSelectionListWrapperDirective {
310
+ constructor() {
311
+ super({ componentClass: DbxFirebaseOAuthConsentScopeListViewComponent, defaultSelectionMode: 'select' });
312
+ }
261
313
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
262
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-list", inputs: { scopes: { classPropertyName: "scopes", publicName: "scopes", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
263
- @for (scope of scopes(); track scope.name) {
264
- <div class="dbx-firebase-oauth-consent-scope-list-item dbx-mb2">
265
- <span class="dbx-firebase-oauth-consent-scope-name dbx-pb2">{{ scope.name }}</span>
266
- @if (scope.description) {
267
- <span class="dbx-firebase-oauth-consent-scope-description">{{ scope.description }}</span>
314
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-list", host: { classAttribute: "dbx-list-no-hover-effects dbx-list-card-items-list" }, usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
315
+ }
316
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListComponent, decorators: [{
317
+ type: Component,
318
+ args: [{
319
+ selector: 'dbx-firebase-oauth-consent-scope-list',
320
+ template: DEFAULT_LIST_WRAPPER_COMPONENT_CONFIGURATION_TEMPLATE,
321
+ host: {
322
+ class: 'dbx-list-no-hover-effects dbx-list-card-items-list'
323
+ },
324
+ imports: [DbxListWrapperComponentImportsModule],
325
+ changeDetection: ChangeDetectionStrategy.OnPush,
326
+ standalone: true
327
+ }]
328
+ }], ctorParameters: () => [] });
329
+ /**
330
+ * Selection list view that pairs with `DbxFirebaseOAuthConsentScopeListComponent`.
331
+ * Maps each `OAuthConsentScope` to a `DbxValueListItem` keyed by the scope name
332
+ * and renders it through `DbxFirebaseOAuthConsentScopeListItemComponent`.
333
+ */
334
+ class DbxFirebaseOAuthConsentScopeListViewComponent extends AbstractDbxSelectionListViewDirective {
335
+ config = {
336
+ componentClass: DbxFirebaseOAuthConsentScopeListItemComponent,
337
+ mapValuesToItemValues: (values) => of(values.map((scope) => ({ ...scope, key: scope.name, itemValue: scope })))
338
+ };
339
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
340
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-list-view", providers: provideDbxListView(DbxFirebaseOAuthConsentScopeListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
341
+ }
342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListViewComponent, decorators: [{
343
+ type: Component,
344
+ args: [{
345
+ selector: 'dbx-firebase-oauth-consent-scope-list-view',
346
+ template: DEFAULT_DBX_SELECTION_VALUE_LIST_COMPONENT_CONFIGURATION_TEMPLATE,
347
+ imports: [DbxSelectionValueListViewComponentImportsModule],
348
+ providers: provideDbxListView(DbxFirebaseOAuthConsentScopeListViewComponent),
349
+ changeDetection: ChangeDetectionStrategy.OnPush,
350
+ standalone: true
351
+ }]
352
+ }] });
353
+ /**
354
+ * Item row inside the OIDC consent scope selection list. Shown as the visual
355
+ * row for both selected and unselected scopes — the selection chrome (the
356
+ * leading checkbox/highlight) is provided by the wrapping
357
+ * `dbx-selection-list-view`.
358
+ */
359
+ class DbxFirebaseOAuthConsentScopeListItemComponent extends AbstractDbxValueListViewItemComponent {
360
+ get name() {
361
+ return this.itemValue.name;
362
+ }
363
+ get description() {
364
+ return this.itemValue.description;
365
+ }
366
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListItemComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
367
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeListItemComponent, isStandalone: true, selector: "ng-component", usesInheritance: true, ngImport: i0, template: `
368
+ <div class="dbx-list-item-padded dbx-list-item-padded-thick dbx-list-two-line-item">
369
+ <div class="item-left">
370
+ <div class="mat-subtitle-2">{{ name }}</div>
371
+ @if (description) {
372
+ <div class="item-details">{{ description }}</div>
268
373
  }
269
374
  </div>
270
- }
271
- `, isInline: true, styles: [".dbx-firebase-oauth-consent-scope-list-item{display:flex;flex-direction:column;padding:8px 12px;border-left:3px solid var(--dbx-primary-color);background:color-mix(in srgb,var(--dbx-color-current) 10%,transparent)}.dbx-firebase-oauth-consent-scope-list-item .dbx-firebase-oauth-consent-scope-name{font-weight:500}.dbx-firebase-oauth-consent-scope-list-item .dbx-firebase-oauth-consent-scope-description{font-size:.85em;opacity:.7}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
375
+ </div>
376
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
272
377
  }
273
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListComponent, decorators: [{
378
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeListItemComponent, decorators: [{
274
379
  type: Component,
275
- args: [{ selector: 'dbx-firebase-oauth-consent-scope-list', standalone: true, template: `
276
- @for (scope of scopes(); track scope.name) {
277
- <div class="dbx-firebase-oauth-consent-scope-list-item dbx-mb2">
278
- <span class="dbx-firebase-oauth-consent-scope-name dbx-pb2">{{ scope.name }}</span>
279
- @if (scope.description) {
280
- <span class="dbx-firebase-oauth-consent-scope-description">{{ scope.description }}</span>
380
+ args: [{
381
+ template: `
382
+ <div class="dbx-list-item-padded dbx-list-item-padded-thick dbx-list-two-line-item">
383
+ <div class="item-left">
384
+ <div class="mat-subtitle-2">{{ name }}</div>
385
+ @if (description) {
386
+ <div class="item-details">{{ description }}</div>
281
387
  }
282
388
  </div>
283
- }
284
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".dbx-firebase-oauth-consent-scope-list-item{display:flex;flex-direction:column;padding:8px 12px;border-left:3px solid var(--dbx-primary-color);background:color-mix(in srgb,var(--dbx-color-current) 10%,transparent)}.dbx-firebase-oauth-consent-scope-list-item .dbx-firebase-oauth-consent-scope-name{font-weight:500}.dbx-firebase-oauth-consent-scope-list-item .dbx-firebase-oauth-consent-scope-description{font-size:.85em;opacity:.7}\n"] }]
285
- }], propDecorators: { scopes: [{ type: i0.Input, args: [{ isSignal: true, alias: "scopes", required: false }] }] } });
389
+ </div>
390
+ `,
391
+ standalone: true,
392
+ changeDetection: ChangeDetectionStrategy.OnPush
393
+ }]
394
+ }] });
395
+
396
+ /**
397
+ * Validator key emitted when the user has not selected any optional scope.
398
+ * Surfaces alongside the form's invalid state so the action button stays disabled.
399
+ */
400
+ const OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND = 'mustSelectAtLeastOneScope';
401
+ /**
402
+ * Default message shown when the user has cleared every optional scope.
403
+ */
404
+ const OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_DEFAULT_MESSAGE = 'Select at least one scope to grant.';
405
+ /**
406
+ * Builds a complete `FormConfig` ready to feed into a forge form component.
407
+ *
408
+ * The resulting form has a single `grantedOIDCScopes` field — a
409
+ * `dbxForgeListSelectionField` rendered through
410
+ * `DbxFirebaseOAuthConsentScopeListComponent` (a `dbx-list` selection wrapper).
411
+ * The list renders bare (no Material form-field wrapper) and without the
412
+ * default 300px height cap so it grows to fit the scope list.
413
+ *
414
+ * @param config - The consent scopes form fields configuration.
415
+ * @returns A `FormConfig` whose single field selects an `OidcScope[]` of granted scopes.
416
+ */
417
+ function oauthConsentScopesFormConfig(config) {
418
+ const { optionalScopes, initiallySelected } = config;
419
+ const value = (initiallySelected ?? optionalScopes.map((scope) => scope.name)).slice();
420
+ const optionalScopesArray = optionalScopes.slice();
421
+ const validators = [
422
+ {
423
+ type: 'custom',
424
+ expression: 'fieldValue && fieldValue.length > 0',
425
+ kind: OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND
426
+ }
427
+ ];
428
+ return {
429
+ fields: [
430
+ dbxForgeListSelectionField({
431
+ key: 'grantedOIDCScopes',
432
+ value,
433
+ validators,
434
+ validationMessages: {
435
+ [OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND]: OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_DEFAULT_MESSAGE
436
+ },
437
+ props: {
438
+ listComponentClass: of(DbxFirebaseOAuthConsentScopeListComponent),
439
+ readKey: (scope) => scope.name,
440
+ state$: of(successResult(optionalScopesArray)),
441
+ wrapped: false,
442
+ maxHeight: 'none'
443
+ }
444
+ })
445
+ ]
446
+ };
447
+ }
448
+
449
+ /**
450
+ * Reusable forge form component that renders one checkbox per OIDC scope
451
+ * defined in {@link OAuthConsentScopesFormFieldsConfig}. Required scopes are
452
+ * rendered as checked-and-disabled.
453
+ *
454
+ * Pair with `<dbx-firebase-oauth-consent-scope-default-view>` for the default
455
+ * consent flow, or embed directly in custom consent UIs that supply their
456
+ * own scope/required configuration.
457
+ */
458
+ class DbxFirebaseOAuthConsentScopeFormComponent extends AbstractConfigAsyncForgeFormDirective {
459
+ formConfig$ = this.currentConfig$.pipe(map((config) => (config ? oauthConsentScopesFormConfig(config) : undefined)));
460
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
461
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeFormComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1$1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
462
+ }
463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeFormComponent, decorators: [{
464
+ type: Component,
465
+ args: [{
466
+ selector: 'dbx-firebase-oauth-consent-scope-form',
467
+ template: DBX_FORGE_FORM_COMPONENT_TEMPLATE,
468
+ providers: dbxForgeFormComponentProviders(),
469
+ imports: [DbxForgeFormComponentImportsModule],
470
+ changeDetection: ChangeDetectionStrategy.OnPush,
471
+ standalone: true
472
+ }]
473
+ }] });
286
474
 
287
475
  const DEFAULT_OIDC_AUTHORIZATION_ENDPOINT_PATH = '/oidc/auth';
288
476
  const DEFAULT_OIDC_INTERACTION_ENDPOINT_PATH = '/interaction';
@@ -366,18 +554,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
366
554
  }] });
367
555
 
368
556
  /**
369
- * Default consent scope view component that maps scope names to descriptions
370
- * using the `OidcScopeDetails` from the app-level OIDC configuration.
557
+ * Default consent scope view component.
558
+ *
559
+ * Reads the requested scopes (and required scopes) from the
560
+ * `DBX_INJECTION_COMPONENT_DATA` provided by the parent consent view,
561
+ * resolves human-readable descriptions from the app-level
562
+ * `DbxFirebaseOidcConfigService`, then renders a
563
+ * `DbxFirebaseOAuthConsentScopeFormComponent` with `dbxActionForm` so the
564
+ * form's value participates in the surrounding `dbxAction` (the consent
565
+ * view's outer Approve action).
371
566
  *
372
- * Apps can override this by providing a custom `consentScopeListViewClass`
373
- * in `DbxFirebaseOidcConfig` or `DbxOAuthConsentComponentConfig`.
567
+ * Required scopes are not user-selectable. They are surfaced as an "Always
568
+ * granted" hint above the form because the server enforces them regardless
569
+ * of payload — including them in the selection list would just add noise.
570
+ *
571
+ * Apps can override this default via
572
+ * `DbxFirebaseOidcConfig.consentScopeListViewClass` or
573
+ * `DbxOAuthConsentComponentConfig.consentScopeListViewClass`. Custom views
574
+ * should similarly apply `dbxActionForm` to a forge form whose value matches
575
+ * `OAuthConsentScopesFormValue`.
374
576
  */
375
- class DbxFirebaseOAuthConsentScopeDefaultViewComponent extends AbstractDbxFirebaseOAuthConsentScopeViewComponent {
376
- oidcConfigService = inject(DbxFirebaseOidcConfigService);
577
+ class DbxFirebaseOAuthConsentScopeDefaultViewComponent {
578
+ _oidcConfigService = inject(DbxFirebaseOidcConfigService);
579
+ _data = inject(DBX_INJECTION_COMPONENT_DATA);
377
580
  mappedScopes = computed(() => {
378
- const availableScopes = this.oidcConfigService.availableScopes;
581
+ const availableScopes = this._oidcConfigService.availableScopes;
379
582
  const availableScopeValues = new Set(availableScopes.map((s) => s.value));
380
- const { included: knownScopes, excluded: unknownScopes } = separateValues(this.scopes(), (name) => availableScopeValues.has(name));
583
+ const { included: knownScopes, excluded: unknownScopes } = separateValues(this._data.scopes, (name) => availableScopeValues.has(name));
381
584
  return [
382
585
  ...knownScopes.map((name) => {
383
586
  const details = availableScopes.find((s) => s.value === name);
@@ -386,29 +589,38 @@ class DbxFirebaseOAuthConsentScopeDefaultViewComponent extends AbstractDbxFireba
386
589
  ...unknownScopes.map((name) => ({ name, description: 'unknown' }))
387
590
  ];
388
591
  }, ...(ngDevMode ? [{ debugName: "mappedScopes" }] : /* istanbul ignore next */ []));
389
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
390
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-default-view", usesInheritance: true, ngImport: i0, template: `
391
- <p>
392
- <strong>{{ clientName() }}</strong>
393
- is requesting these permissions:
394
- </p>
395
- <dbx-firebase-oauth-consent-scope-list [scopes]="mappedScopes()"></dbx-firebase-oauth-consent-scope-list>
396
- `, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseOAuthConsentScopeListComponent, selector: "dbx-firebase-oauth-consent-scope-list", inputs: ["scopes"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
592
+ optionalScopes = computed(() => {
593
+ const requiredSet = new Set(this._data.requiredScopes ?? []);
594
+ return this.mappedScopes().filter((scope) => !requiredSet.has(scope.name));
595
+ }, ...(ngDevMode ? [{ debugName: "optionalScopes" }] : /* istanbul ignore next */ []));
596
+ alwaysGrantedLabel = computed(() => {
597
+ const required = this._data.requiredScopes ?? [];
598
+ return required.length > 0 ? required.join(', ') : null;
599
+ }, ...(ngDevMode ? [{ debugName: "alwaysGrantedLabel" }] : /* istanbul ignore next */ []));
600
+ formFieldsConfig = computed(() => ({
601
+ optionalScopes: this.optionalScopes()
602
+ }), ...(ngDevMode ? [{ debugName: "formFieldsConfig" }] : /* istanbul ignore next */ []));
603
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
604
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.11", type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent-scope-default-view", ngImport: i0, template: `
605
+ @if (alwaysGrantedLabel(); as label) {
606
+ <p class="dbx-firebase-oauth-consent-always-granted dbx-hint">Always granted: {{ label }}</p>
607
+ }
608
+ <dbx-firebase-oauth-consent-scope-form dbxActionForm [config]="formFieldsConfig()"></dbx-firebase-oauth-consent-scope-form>
609
+ `, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseOAuthConsentScopeFormComponent, selector: "dbx-firebase-oauth-consent-scope-form" }, { kind: "directive", type: DbxActionFormDirective, selector: "[dbxActionForm]", inputs: ["dbxActionFormDisabledOnWorking", "dbxActionFormIsValid", "dbxActionFormIsEqual", "dbxActionFormIsModified", "dbxActionFormMapValue"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
397
610
  }
398
611
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOAuthConsentScopeDefaultViewComponent, decorators: [{
399
612
  type: Component,
400
613
  args: [{
401
614
  selector: 'dbx-firebase-oauth-consent-scope-default-view',
402
- standalone: true,
403
- imports: [DbxFirebaseOAuthConsentScopeListComponent],
404
615
  template: `
405
- <p>
406
- <strong>{{ clientName() }}</strong>
407
- is requesting these permissions:
408
- </p>
409
- <dbx-firebase-oauth-consent-scope-list [scopes]="mappedScopes()"></dbx-firebase-oauth-consent-scope-list>
616
+ @if (alwaysGrantedLabel(); as label) {
617
+ <p class="dbx-firebase-oauth-consent-always-granted dbx-hint">Always granted: {{ label }}</p>
618
+ }
619
+ <dbx-firebase-oauth-consent-scope-form dbxActionForm [config]="formFieldsConfig()"></dbx-firebase-oauth-consent-scope-form>
410
620
  `,
411
- changeDetection: ChangeDetectionStrategy.OnPush
621
+ imports: [DbxFirebaseOAuthConsentScopeFormComponent, DbxActionFormDirective],
622
+ changeDetection: ChangeDetectionStrategy.OnPush,
623
+ standalone: true
412
624
  }]
413
625
  }] });
414
626
 
@@ -448,14 +660,23 @@ class DbxFirebaseOidcInteractionService {
448
660
  /**
449
661
  * Submit consent decision to complete the consent interaction.
450
662
  *
451
- * Automatically attaches the current user's Firebase ID token.
663
+ * Automatically attaches the current user's Firebase ID token. When `approved`
664
+ * is true, optional `grants` may be passed to grant only a subset of the
665
+ * requested scopes/claims/resource scopes; the server validates that any
666
+ * subset is contained in the corresponding `missing*` set on the prompt.
667
+ *
668
+ * When `approved` is false, `grants` is ignored (not sent).
452
669
  *
453
670
  * @param uid - The OIDC interaction UID identifying the current consent interaction.
454
671
  * @param approved - Whether the user approved or denied the consent request.
672
+ * @param grants - Optional subset of OIDC scopes / OIDC claims / resource scopes to grant.
455
673
  * @returns Observable that emits the redirect URL from the server response.
456
674
  */
457
- submitConsent(uid, approved) {
458
- return this._authService.idTokenString$.pipe(first(), switchMap((idToken) => this.http.post(`${this.baseUrl}/${uid}/consent`, { idToken, approved })));
675
+ submitConsent(uid, approved, grants) {
676
+ return this._authService.idTokenString$.pipe(first(), switchMap((idToken) => {
677
+ const body = approved && grants ? { idToken, approved, ...grants } : { idToken, approved };
678
+ return this.http.post(`${this.baseUrl}/${uid}/consent`, body);
679
+ }));
459
680
  }
460
681
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcInteractionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
461
682
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcInteractionService, providedIn: 'root' });
@@ -564,14 +785,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
564
785
  }]
565
786
  }], ctorParameters: () => [] });
566
787
 
788
+ /**
789
+ * OIDC scopes that cannot be deselected on the consent screen. `openid` is
790
+ * mandatory for any OIDC flow, so the UI shows it as always-granted and the
791
+ * server enforces it regardless of payload.
792
+ */
793
+ const OAUTH_CONSENT_REQUIRED_SCOPES = ['openid'];
567
794
  /**
568
795
  * Container component for the OIDC OAuth consent screen.
569
796
  *
570
- * Manages all state: route param reading, Firebase Auth observation, consent submission,
571
- * and error handling. Delegates visual rendering to `DbxFirebaseOAuthConsentViewComponent`.
572
- *
573
797
  * Reads interaction UID and client details from route params (populated by
574
- * the server redirect), then assembles them into `OAuthInteractionLoginDetails`.
798
+ * the server redirect), assembles them into `OAuthInteractionLoginDetails`,
799
+ * and exposes Approve / Deny handlers that drive the view's nested
800
+ * `dbxAction` contexts.
801
+ *
802
+ * Submission progress and error states are owned by the action stores; this
803
+ * container is just routing-glue + handler factories.
575
804
  *
576
805
  * Supports ng-content projection — any content provided is passed through to
577
806
  * the view component for the `'no_user'` state (e.g. an app's login view).
@@ -619,15 +848,12 @@ class DbxOAuthConsentComponent {
619
848
  scopeInjectionConfig = computed(() => ({
620
849
  componentClass: this.config()?.consentScopeListViewClass ?? this.oidcConfigService.consentScopeListViewClass ?? DbxFirebaseOAuthConsentScopeDefaultViewComponent
621
850
  }), ...(ngDevMode ? [{ debugName: "scopeInjectionConfig" }] : /* istanbul ignore next */ []));
622
- submitting = signal(false, ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
623
- errorMessage = signal(null, ...(ngDevMode ? [{ debugName: "errorMessage" }] : /* istanbul ignore next */ []));
851
+ /**
852
+ * Scopes the user cannot deselect. Forwarded to the view, which shows
853
+ * them as a static "Always granted" hint above the selection list.
854
+ */
855
+ requiredScopes = OAUTH_CONSENT_REQUIRED_SCOPES;
624
856
  consentStateCase = computed(() => {
625
- if (this.submitting()) {
626
- return 'submitting';
627
- }
628
- if (this.errorMessage()) {
629
- return 'error';
630
- }
631
857
  const isLoggedIn = this.isLoggedIn();
632
858
  if (isLoggedIn === undefined) {
633
859
  return 'unknown';
@@ -645,45 +871,47 @@ class DbxOAuthConsentComponent {
645
871
  this.logoUriParamReader.destroy();
646
872
  this.scopesParamReader.destroy();
647
873
  }
648
- approve() {
649
- this._submitConsent(true);
650
- }
651
- deny() {
652
- this._submitConsent(false);
653
- }
654
- retry() {
655
- this.errorMessage.set(null);
656
- }
657
- _submitConsent(approved) {
658
- if (this.consentStateCase() !== 'user') {
874
+ /**
875
+ * Handles the Approve action. Pulls the form's selected scope array
876
+ * straight off the form value (it already matches the API field name
877
+ * `grantedOIDCScopes`) and forwards it through `submitConsent`. On a
878
+ * successful response, hard-navigates to the OIDC server's redirect URL.
879
+ */
880
+ handleApprove = (formValue, context) => {
881
+ const uid = this.resolvedInteractionUid();
882
+ if (!uid) {
883
+ context.reject(new Error('Missing interaction UID'));
659
884
  return;
660
885
  }
886
+ const grantedOIDCScopes = formValue.grantedOIDCScopes;
887
+ context.startWorkingWithObservable(this.interactionService.submitConsent(uid, true, { grantedOIDCScopes }).pipe(tap((response) => {
888
+ if (response.redirectTo) {
889
+ window.location.href = response.redirectTo;
890
+ }
891
+ })));
892
+ };
893
+ /**
894
+ * Handles the Deny action. No payload is sent — the server returns
895
+ * `access_denied` to the OAuth client.
896
+ */
897
+ handleDeny = (_value, context) => {
661
898
  const uid = this.resolvedInteractionUid();
662
899
  if (!uid) {
663
- this.errorMessage.set('Missing interaction UID');
900
+ context.reject(new Error('Missing interaction UID'));
664
901
  return;
665
902
  }
666
- this.submitting.set(true);
667
- this.errorMessage.set(null);
668
- this.interactionService.submitConsent(uid, approved).subscribe({
669
- next: (response) => {
670
- this.submitting.set(false);
671
- if (response.redirectTo) {
672
- window.location.href = response.redirectTo;
673
- }
674
- },
675
- error: () => {
676
- this.submitting.set(false);
677
- this.errorMessage.set('Failed to process consent. Please try again.');
903
+ context.startWorkingWithObservable(this.interactionService.submitConsent(uid, false).pipe(tap((response) => {
904
+ if (response.redirectTo) {
905
+ window.location.href = response.redirectTo;
678
906
  }
679
- });
680
- }
907
+ })));
908
+ };
681
909
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxOAuthConsentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
682
910
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.11", type: DbxOAuthConsentComponent, isStandalone: true, selector: "dbx-firebase-oauth-consent", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "d-block dbx-firebase-oauth-consent" }, ngImport: i0, template: `
683
- <dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [consentStateCase]="consentStateCase()" [error]="errorMessage()" [scopeInjectionConfig]="scopeInjectionConfig()" (approveClick)="approve()" (denyClick)="deny()" (retryClick)="retry()">
911
+ <dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [consentStateCase]="consentStateCase()" [scopeInjectionConfig]="scopeInjectionConfig()" [requiredScopes]="requiredScopes" [approveHandler]="handleApprove" [denyHandler]="handleDeny">
684
912
  <ng-content />
685
913
  </dbx-firebase-oauth-consent-view>
686
- `, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseOAuthConsentViewComponent, selector: "dbx-firebase-oauth-consent-view", inputs: ["details", "consentStateCase", "error", "scopeInjectionConfig"], outputs: ["approveClick", "denyClick", "retryClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
914
+ `, isInline: true, dependencies: [{ kind: "component", type: DbxFirebaseOAuthConsentViewComponent, selector: "dbx-firebase-oauth-consent-view", inputs: ["details", "consentStateCase", "scopeInjectionConfig", "requiredScopes", "approveHandler", "denyHandler"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
687
915
  }
688
916
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxOAuthConsentComponent, decorators: [{
689
917
  type: Component,
@@ -692,7 +920,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
692
920
  standalone: true,
693
921
  imports: [DbxFirebaseOAuthConsentViewComponent],
694
922
  template: `
695
- <dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [consentStateCase]="consentStateCase()" [error]="errorMessage()" [scopeInjectionConfig]="scopeInjectionConfig()" (approveClick)="approve()" (denyClick)="deny()" (retryClick)="retry()">
923
+ <dbx-firebase-oauth-consent-view [details]="resolvedDetails()" [consentStateCase]="consentStateCase()" [scopeInjectionConfig]="scopeInjectionConfig()" [requiredScopes]="requiredScopes" [approveHandler]="handleApprove" [denyHandler]="handleDeny">
696
924
  <ng-content />
697
925
  </dbx-firebase-oauth-consent-view>
698
926
  `,
@@ -922,7 +1150,7 @@ class DbxFirebaseOidcEntryClientForgeFormComponent extends AbstractConfigAsyncFo
922
1150
  });
923
1151
  }));
924
1152
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientForgeFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
925
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1$1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
926
1154
  }
927
1155
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientForgeFormComponent, decorators: [{
928
1156
  type: Component,
@@ -944,7 +1172,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImpo
944
1172
  class DbxFirebaseOidcEntryClientTestForgeFormComponent extends AbstractConfigAsyncForgeFormDirective {
945
1173
  formConfig$ = this.currentConfig$.pipe(map((config) => (config ? oidcEntryClientTestForgeFormFields(config) : undefined)));
946
1174
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientTestForgeFormComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
947
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientTestForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-test-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1175
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientTestForgeFormComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-test-forge-form", providers: dbxForgeFormComponentProviders(), usesInheritance: true, ngImport: i0, template: "<dbx-forge></dbx-forge>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxForgeFormComponentImportsModule }, { kind: "component", type: i1$1.DbxForgeFormComponent, selector: "dbx-forge" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
948
1176
  }
949
1177
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientTestForgeFormComponent, decorators: [{
950
1178
  type: Component,
@@ -1010,7 +1238,7 @@ class DbxFirebaseOidcEntryGrantListComponent extends AbstractDbxSelectionListWra
1010
1238
  });
1011
1239
  }
1012
1240
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1013
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list", host: { classAttribute: "dbx-list-no-hover-effects dbx-list-card-items-list" }, providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryGrantListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1$1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1241
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list", host: { classAttribute: "dbx-list-no-hover-effects dbx-list-card-items-list" }, providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryGrantListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1014
1242
  }
1015
1243
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListComponent, decorators: [{
1016
1244
  type: Component,
@@ -1035,7 +1263,7 @@ class DbxFirebaseOidcEntryGrantListViewComponent extends AbstractDbxSelectionLis
1035
1263
  }))
1036
1264
  };
1037
1265
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1038
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryGrantListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1$1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1266
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryGrantListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-grant-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryGrantListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1039
1267
  }
1040
1268
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryGrantListViewComponent, decorators: [{
1041
1269
  type: Component,
@@ -1133,7 +1361,7 @@ class DbxFirebaseOidcEntryClientListComponent extends AbstractDbxSelectionListWr
1133
1361
  });
1134
1362
  }
1135
1363
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1136
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list", providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryClientListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1$1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }] });
1364
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list", providers: provideDbxListViewWrapper(DbxFirebaseOidcEntryClientListComponent), usesInheritance: true, ngImport: i0, template: "\n <dbx-list [state]=\"currentState$\" [config]=\"configSignal()\" [hasMore]=\"hasMore()\" [disabled]=\"disabledSignal()\" [selectionMode]=\"selectionModeSignal()\">\n <ng-content top select=\"[top]\"></ng-content>\n <ng-content bottom select=\"[bottom]\"></ng-content>\n <ng-content empty select=\"[empty]\"></ng-content>\n <ng-content emptyLoading select=\"[emptyLoading]\"></ng-content>\n <ng-content end select=\"[end]\"></ng-content>\n </dbx-list>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxListWrapperComponentImportsModule }, { kind: "component", type: i1.DbxListComponent, selector: "dbx-list", inputs: ["padded", "state", "config", "disabled", "selectionMode", "hasMore"], outputs: ["contentScrolled"] }] });
1137
1365
  }
1138
1366
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListComponent, decorators: [{
1139
1367
  type: Component,
@@ -1151,7 +1379,7 @@ class DbxFirebaseOidcEntryClientListViewComponent extends AbstractDbxSelectionLi
1151
1379
  mapValuesToItemValues: (x) => of(x.map((y, i) => ({ ...y, key: `oidc_${i}`, itemValue: y })))
1152
1380
  };
1153
1381
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListViewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1154
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryClientListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1$1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }] });
1382
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.11", type: DbxFirebaseOidcEntryClientListViewComponent, isStandalone: true, selector: "dbx-firebase-oidc-client-list-view", providers: provideDbxListView(DbxFirebaseOidcEntryClientListViewComponent), usesInheritance: true, ngImport: i0, template: "<dbx-selection-list-view [config]=\"config\"></dbx-selection-list-view>", isInline: true, dependencies: [{ kind: "ngmodule", type: DbxSelectionValueListViewComponentImportsModule }, { kind: "component", type: i1.DbxSelectionValueListViewComponent, selector: "dbx-selection-list-view" }] });
1155
1383
  }
1156
1384
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.11", ngImport: i0, type: DbxFirebaseOidcEntryClientListViewComponent, decorators: [{
1157
1385
  type: Component,
@@ -1700,5 +1928,5 @@ function provideDbxFirebaseOidc(config) {
1700
1928
  * Generated bundle index. Do not edit.
1701
1929
  */
1702
1930
 
1703
- export { AbstractDbxFirebaseOAuthConsentScopeViewComponent, DEFAULT_OIDC_AUTHORIZATION_ENDPOINT_PATH, DEFAULT_OIDC_CLIENT_ID_PARAM_KEY, DEFAULT_OIDC_CLIENT_NAME_PARAM_KEY, DEFAULT_OIDC_CLIENT_URI_PARAM_KEY, DEFAULT_OIDC_INTERACTION_ENDPOINT_PATH, DEFAULT_OIDC_INTERACTION_UID_PARAM_KEY, DEFAULT_OIDC_LOGO_URI_PARAM_KEY, DEFAULT_OIDC_SCOPES_PARAM_KEY, DEFAULT_OIDC_TOKEN_ENDPOINT_AUTH_METHODS, DbxFirebaseOAuthConsentScopeDefaultViewComponent, DbxFirebaseOAuthConsentScopeListComponent, DbxFirebaseOAuthConsentViewComponent, DbxFirebaseOAuthLoginComponent, DbxFirebaseOAuthLoginViewComponent, DbxFirebaseOidcConfig, DbxFirebaseOidcConfigService, DbxFirebaseOidcEntryClientCreateComponent, DbxFirebaseOidcEntryClientForgeFormComponent, DbxFirebaseOidcEntryClientListComponent, DbxFirebaseOidcEntryClientListViewComponent, DbxFirebaseOidcEntryClientListViewItemClientComponent, DbxFirebaseOidcEntryClientListViewItemComponent, DbxFirebaseOidcEntryClientListViewItemDefaultComponent, DbxFirebaseOidcEntryClientTestComponent, DbxFirebaseOidcEntryClientTestForgeFormComponent, DbxFirebaseOidcEntryClientUpdateComponent, DbxFirebaseOidcEntryClientViewComponent, DbxFirebaseOidcEntryGrantListComponent, DbxFirebaseOidcEntryGrantListContainerComponent, DbxFirebaseOidcEntryGrantListViewComponent, DbxFirebaseOidcEntryGrantListViewItemComponent, DbxFirebaseOidcInteractionService, DbxOAuthConsentComponent, OidcEntryCollectionStore, OidcEntryCollectionStoreDirective, OidcEntryDocumentStore, OidcEntryDocumentStoreDirective, oidcClientHomepageUriForgeField, oidcClientJwksUriForgeField, oidcClientLogoUriForgeField, oidcClientNameForgeField, oidcClientRedirectUrisForgeField, oidcClientTestClientIdForgeField, oidcClientTestRedirectUriForgeField, oidcClientTestScopesForgeField, oidcClientTokenEndpointAuthMethodForgeField, oidcEntryClientForgeFormFields, oidcEntryClientTestForgeFormFields, oidcEntryClientUpdateForgeFormFields, provideDbxFirebaseOidc, provideOidcModelFirestoreCollections };
1931
+ export { AbstractDbxFirebaseOAuthConsentScopeViewComponent, DEFAULT_OIDC_AUTHORIZATION_ENDPOINT_PATH, DEFAULT_OIDC_CLIENT_ID_PARAM_KEY, DEFAULT_OIDC_CLIENT_NAME_PARAM_KEY, DEFAULT_OIDC_CLIENT_URI_PARAM_KEY, DEFAULT_OIDC_INTERACTION_ENDPOINT_PATH, DEFAULT_OIDC_INTERACTION_UID_PARAM_KEY, DEFAULT_OIDC_LOGO_URI_PARAM_KEY, DEFAULT_OIDC_SCOPES_PARAM_KEY, DEFAULT_OIDC_TOKEN_ENDPOINT_AUTH_METHODS, DbxFirebaseOAuthConsentScopeDefaultViewComponent, DbxFirebaseOAuthConsentScopeFormComponent, DbxFirebaseOAuthConsentScopeListComponent, DbxFirebaseOAuthConsentScopeListItemComponent, DbxFirebaseOAuthConsentScopeListViewComponent, DbxFirebaseOAuthConsentViewComponent, DbxFirebaseOAuthLoginComponent, DbxFirebaseOAuthLoginViewComponent, DbxFirebaseOidcConfig, DbxFirebaseOidcConfigService, DbxFirebaseOidcEntryClientCreateComponent, DbxFirebaseOidcEntryClientForgeFormComponent, DbxFirebaseOidcEntryClientListComponent, DbxFirebaseOidcEntryClientListViewComponent, DbxFirebaseOidcEntryClientListViewItemClientComponent, DbxFirebaseOidcEntryClientListViewItemComponent, DbxFirebaseOidcEntryClientListViewItemDefaultComponent, DbxFirebaseOidcEntryClientTestComponent, DbxFirebaseOidcEntryClientTestForgeFormComponent, DbxFirebaseOidcEntryClientUpdateComponent, DbxFirebaseOidcEntryClientViewComponent, DbxFirebaseOidcEntryGrantListComponent, DbxFirebaseOidcEntryGrantListContainerComponent, DbxFirebaseOidcEntryGrantListViewComponent, DbxFirebaseOidcEntryGrantListViewItemComponent, DbxFirebaseOidcInteractionService, DbxOAuthConsentComponent, OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_DEFAULT_MESSAGE, OAUTH_CONSENT_SCOPES_REQUIRED_VALIDATOR_KIND, OidcEntryCollectionStore, OidcEntryCollectionStoreDirective, OidcEntryDocumentStore, OidcEntryDocumentStoreDirective, oauthConsentScopesFormConfig, oidcClientHomepageUriForgeField, oidcClientJwksUriForgeField, oidcClientLogoUriForgeField, oidcClientNameForgeField, oidcClientRedirectUrisForgeField, oidcClientTestClientIdForgeField, oidcClientTestRedirectUriForgeField, oidcClientTestScopesForgeField, oidcClientTokenEndpointAuthMethodForgeField, oidcEntryClientForgeFormFields, oidcEntryClientTestForgeFormFields, oidcEntryClientUpdateForgeFormFields, provideDbxFirebaseOidc, provideOidcModelFirestoreCollections };
1704
1932
  //# sourceMappingURL=dereekb-dbx-firebase-oidc.mjs.map