@dereekb/firebase-server 13.28.0 → 13.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,12 @@
1
1
  import { type Maybe } from '@dereekb/util';
2
- import { type OnCallTypedModelParams } from '@dereekb/firebase';
2
+ import { type FirestoreModelType, type OidcModelScopeRequirement, type OidcScopeTerm, type OnCallTypedModelParams } from '@dereekb/firebase';
3
3
  import { type INestApplicationContext } from '@nestjs/common';
4
4
  import { type Request } from 'express';
5
5
  import { type OnCallWithNestContext } from '../../function/call';
6
6
  import { type OnCallApiDetailsRef, type ModelApiDetailsResult } from '../../model/api.details';
7
7
  import { type MakeNestContext } from '../../nest.provider';
8
8
  import { type FirebaseServerAuthData } from '../auth.context.server';
9
+ import { type ModelApiOidcScopeConfig } from './model.api.scope';
9
10
  /**
10
11
  * The combined type of the function returned by onCallModel() with _apiDetails attached.
11
12
  */
@@ -27,7 +28,7 @@ export type OnCallModelFnWithApiDetails = OnCallWithNestContext<unknown, OnCallT
27
28
  * }
28
29
  * ```
29
30
  */
30
- export declare abstract class ModelApiDispatchConfig {
31
+ export declare abstract class ModelApiDispatchConfig implements ModelApiOidcScopeConfig {
31
32
  /**
32
33
  * The onCallModel() return value with _apiDetails attached.
33
34
  */
@@ -36,6 +37,17 @@ export declare abstract class ModelApiDispatchConfig {
36
37
  * Factory to create typed nest context from INestApplicationContext.
37
38
  */
38
39
  readonly makeNestContext: MakeNestContext<unknown>;
40
+ /**
41
+ * Optional model-api-layer OIDC group-scope default. See {@link ModelApiOidcScopeConfig.defaultRequiredScope}.
42
+ * This is the home for the callModel group-scope default; providing it here enforces it across
43
+ * dispatch AND the `/get` reads.
44
+ */
45
+ readonly defaultRequiredScope?: OidcScopeTerm;
46
+ /**
47
+ * Optional per-model OIDC group-scope overrides. See {@link ModelApiOidcScopeConfig.modelRequiredScopes}.
48
+ * The only place a plain `/get` read (no per-function handler) can be scope-gated beyond `model.read`.
49
+ */
50
+ readonly modelRequiredScopes?: Record<FirestoreModelType, OidcModelScopeRequirement>;
39
51
  }
40
52
  /**
41
53
  * Injection token for providing the NestJS application context to the dispatch service.
@@ -61,8 +61,22 @@ export declare function modelAccessReadErrorFromUseMultipleModelsFailure(entry:
61
61
  */
62
62
  export declare class ModelApiGetService {
63
63
  private readonly _nestContext;
64
+ private readonly _defaultRequiredScope;
65
+ private readonly _modelRequiredScopes;
64
66
  private _identityByModelType;
65
67
  constructor(config: ModelApiDispatchConfig, nestApplication: INestApplicationContext);
68
+ /**
69
+ * Enforces the OIDC read-scope requirement for a direct document read before it hits Firestore.
70
+ *
71
+ * A direct `/get` read is the `read` verb: it requires the per-verb `model.read` scope AND any
72
+ * effective group term for the target model (per-model requirement > module default). This is the
73
+ * ONLY gate on the direct-read path — it does not touch the callModel dispatch chain — so without it
74
+ * an OIDC client scoped to a subset could read any model through `/get`. Non-OIDC callers bypass.
75
+ *
76
+ * @param modelType - The Firestore model type being read.
77
+ * @param auth - The request's auth data (OIDC scopes are read from it).
78
+ */
79
+ private _assertReadScope;
66
80
  /**
67
81
  * Returns the registered {@link FirestoreModelIdentity} for the given `modelType` string, or
68
82
  * `undefined` when no model of that type is registered.
@@ -0,0 +1,102 @@
1
+ import { type Maybe } from '@dereekb/util';
2
+ import { type FirestoreModelType, type OidcModelScopeRequirement, type OidcScope, type OidcScopeTerm, type OnCallFunctionType } from '@dereekb/firebase';
3
+ import { type FirebaseServerAuthData } from '../auth.context.server';
4
+ /**
5
+ * OIDC scope-grouping configuration for the model-api layer, mixed into {@link ModelApiDispatchConfig}
6
+ * and read by both {@link ModelApiCallModelDispatchService} and {@link ModelApiGetService}.
7
+ *
8
+ * This is the model-api-layer home for the callModel group-scope requirements. Providing them here
9
+ * enforces them uniformly across ALL three `ModelApiController` access patterns — path/direct
10
+ * dispatch AND the `/get` direct reads — and
11
+ * (via the MCP server routing through the same services) the MCP surface, without riding the shared
12
+ * callModel function that also serves the app's first-party Firebase `onCall` path.
13
+ *
14
+ * With NEITHER field supplied, enforcement is byte-for-byte the pre-grouping behavior: an OIDC caller
15
+ * still needs the per-verb `model.<call>` scope (plus any per-function `requiredScope` on dispatch),
16
+ * and non-OIDC callers bypass entirely.
17
+ */
18
+ export interface ModelApiOidcScopeConfig {
19
+ /**
20
+ * Group term required on EVERY model-api op unless a finer term overrides it (a per-function
21
+ * `requiredScope`, then a {@link ModelApiOidcScopeConfig.modelRequiredScopes} entry). Lets an app
22
+ * require e.g. `'hellosubs'` across all models without editing individual handlers. Set this to the
23
+ * SAME value passed to the MCP `McpModuleConfig.defaultRequiredScope` so tool listing == callability.
24
+ */
25
+ readonly defaultRequiredScope?: OidcScopeTerm;
26
+ /**
27
+ * Per-model group-term overrides keyed by {@link FirestoreModelType}. The ONLY place a plain `/get`
28
+ * read (which has no per-function handler) can be scope-gated beyond the per-verb `model.read` scope.
29
+ * A verb-keyed entry can require different terms per verb (e.g. `lms` reads, `hellosubs` writes). Set
30
+ * this to the SAME value passed to the MCP `McpModuleConfig.modelRequiredScopes` so tool listing ==
31
+ * callability.
32
+ */
33
+ readonly modelRequiredScopes?: Record<FirestoreModelType, OidcModelScopeRequirement>;
34
+ }
35
+ /**
36
+ * Reads the set of OIDC scopes carried by a model-api request's auth, or `undefined` for a non-OIDC
37
+ * (regular Firebase ID-token) caller.
38
+ *
39
+ * The OIDC bearer-token middleware attaches the validated access-token claims at
40
+ * `auth.oidcValidatedToken` (with the space-delimited `scope` string); a non-OIDC caller has neither
41
+ * that field nor a `scope` on `auth.token`. Reading is defensive (the auth shape is only typed as
42
+ * {@link FirebaseServerAuthData} here — the OIDC-specific `oidcValidatedToken` lives in the
43
+ * `@dereekb/firebase-server/oidc` sub-package this core layer cannot import), delegating the actual
44
+ * parse to the shared {@link oidcScopesFromScopeClaim} so there is no drift with `getOidcScopesFromRequest`.
45
+ *
46
+ * @param auth - The request auth data, or undefined for unauthenticated requests.
47
+ * @returns The granted scope set, or `undefined` when the request carries no OIDC `scope` claim.
48
+ */
49
+ export declare function oidcScopesFromModelApiAuth(auth: Maybe<FirebaseServerAuthData>): Maybe<Set<OidcScope>>;
50
+ /**
51
+ * Inputs to {@link assertModelApiOidcScope}.
52
+ *
53
+ * Standalone (not extending {@link ModelApiOidcScopeConfig}) because the group fields here receive the
54
+ * services' stored config values, which are {@link Maybe} (nullable) — matching the shipped
55
+ * `ResolveEffectiveOidcScopeTermsInput` — whereas the config surface exposes them as plain optionals.
56
+ */
57
+ export interface AssertModelApiOidcScopeInput {
58
+ /**
59
+ * The call verb being enforced (e.g. `create`, `read`). `/get` direct reads pass `'read'`.
60
+ */
61
+ readonly call: OnCallFunctionType;
62
+ /**
63
+ * The Firestore model type being targeted.
64
+ */
65
+ readonly modelType: FirestoreModelType;
66
+ /**
67
+ * The per-function `requiredScope` declared via `withApiDetails`, if resolvable (dispatch only — a
68
+ * plain `/get` read has no per-function handler). The finest (highest-precedence) group term.
69
+ */
70
+ readonly requiredScope?: Maybe<OidcScopeTerm>;
71
+ /**
72
+ * The module-level default group term (see {@link ModelApiOidcScopeConfig.defaultRequiredScope}).
73
+ */
74
+ readonly defaultRequiredScope?: Maybe<OidcScopeTerm>;
75
+ /**
76
+ * The per-model group-term overrides (see {@link ModelApiOidcScopeConfig.modelRequiredScopes}).
77
+ */
78
+ readonly modelRequiredScopes?: Maybe<Record<FirestoreModelType, OidcModelScopeRequirement>>;
79
+ /**
80
+ * The scopes the caller was granted, or `undefined` for a non-OIDC caller (bypasses enforcement).
81
+ */
82
+ readonly grantedScopes: Maybe<ReadonlySet<OidcScope>>;
83
+ }
84
+ /**
85
+ * Enforces the OIDC scope requirement for a single model-api op, throwing a `403`
86
+ * {@link CALL_MODEL_MISSING_OIDC_SCOPE_ERROR_CODE} error when the caller does not satisfy it.
87
+ *
88
+ * The single home of callModel OIDC scope enforcement. It reuses the shipped composition + evaluation
89
+ * (`resolveEffectiveOidcScopeTerms` / `oidcScopeTermsSatisfied`) so enforcement and the MCP
90
+ * tool-visibility filter never drift. Enforcement is AND-of-ORs across the per-verb `model.<call>`
91
+ * scope and the effective GROUP term (per-function `requiredScope` > per-model requirement >
92
+ * configured default).
93
+ *
94
+ * Bypasses (no-op) when `grantedScopes` is `undefined` — i.e. a non-OIDC caller — and short-circuits
95
+ * without any check when the op resolves no requirement at all (a custom, non-CRUD verb with no
96
+ * per-function/model/default term).
97
+ *
98
+ * @param input - The verb, model type, per-function scope, group config, and the caller's granted scopes.
99
+ * @throws A `403` forbidden error (code {@link CALL_MODEL_MISSING_OIDC_SCOPE_ERROR_CODE}) when an OIDC
100
+ * caller does not satisfy the effective requirement.
101
+ */
102
+ export declare function assertModelApiOidcScope(input: AssertModelApiOidcScopeInput): void;
@@ -1,5 +1,5 @@
1
1
  import { type AuthRole, type Maybe, type PromiseOrValue } from '@dereekb/util';
2
- import { type OnCallFunctionType, type OnCallTypedModelParams, type FirestoreModelType, type ModelFirebaseCrudFunctionSpecifier } from '@dereekb/firebase';
2
+ import { type OnCallFunctionType, type OnCallTypedModelParams, type FirestoreModelType, type ModelFirebaseCrudFunctionSpecifier, type OidcScopeTerm } from '@dereekb/firebase';
3
3
  import { type FirebaseServerAuthData } from '../controller/auth.context.server';
4
4
  import { type OnCallModelFunctionAnalyticsDetails } from './analytics.details';
5
5
  /**
@@ -74,7 +74,7 @@ export interface McpVisibilityContext {
74
74
  readonly auth?: FirebaseServerAuthData;
75
75
  /**
76
76
  * The caller's OIDC scopes, when the request was authenticated with a `scope`-bearing token.
77
- * `undefined` for non-OIDC callers — treated the same as `oidcCallModelScopePreAssert` bypass.
77
+ * `undefined` for non-OIDC callers — treated the same as the model-api scope gate's non-OIDC bypass.
78
78
  */
79
79
  readonly scopes?: ReadonlySet<string>;
80
80
  /**
@@ -302,6 +302,21 @@ export interface OnCallModelFunctionApiDetails<R = unknown, M = unknown> {
302
302
  * When provided, the dispatch chain will call lifecycle hooks around handler execution.
303
303
  */
304
304
  readonly analytics?: OnCallModelFunctionAnalyticsDetails;
305
+ /**
306
+ * Optional per-function OIDC scope TERM an OIDC-authenticated caller must additionally hold to
307
+ * invoke this handler, on top of the per-verb `model.<call>` scope.
308
+ *
309
+ * A single scope string requires that exact scope; a `readonly` array is an OR-group the caller
310
+ * satisfies by holding ANY member (see {@link OidcScopeTerm}). This term is the finest (highest
311
+ * precedence) source for the effective group requirement — it overrides any model-level or default
312
+ * requirement configured on the model-api layer (`ModelApiDispatchConfig`).
313
+ *
314
+ * Composes with the CRUD-verb scope enforced by the model-api scope gate (`assertModelApiOidcScope`) as AND-of-ORs: an
315
+ * OIDC caller still needs `model.<call>` AND this term. Non-OIDC callers (Firebase ID tokens)
316
+ * bypass scope enforcement entirely and are unaffected. Also folded into the MCP tool-list
317
+ * visibility filter, so a tool the caller cannot satisfy this term for is neither listed nor callable.
318
+ */
319
+ readonly requiredScope?: OidcScopeTerm;
305
320
  }
306
321
  /**
307
322
  * Ref interface for objects (functions) that carry handler-level _apiDetails.
@@ -564,6 +579,20 @@ export declare function getModelApiDetails(callModelFn: Maybe<OnCallApiDetailsRe
564
579
  * @returns The analytics details for the resolved handler, or undefined.
565
580
  */
566
581
  export declare function resolveAnalyticsFromApiDetails(apiDetails: OnCallModelApiDetails, call: OnCallFunctionType, modelType: FirestoreModelType, specifier?: ModelFirebaseCrudFunctionSpecifier): Maybe<OnCallModelFunctionAnalyticsDetails>;
582
+ /**
583
+ * Resolves the leaf-level per-function required OIDC scope from the aggregated _apiDetails tree.
584
+ *
585
+ * Walks: call -> modelType -> specifier (if specifier-level), then reads the `requiredScope`
586
+ * field from the handler-level {@link OnCallModelFunctionApiDetails}. Mirrors
587
+ * {@link resolveAnalyticsFromApiDetails}.
588
+ *
589
+ * @param apiDetails - The top-level aggregated API details.
590
+ * @param call - The CRUD operation type to look up.
591
+ * @param modelType - The Firestore model type to look up.
592
+ * @param specifier - Optional specifier key for variant handlers.
593
+ * @returns The per-function required scope for the resolved handler, or undefined.
594
+ */
595
+ export declare function resolveRequiredScopeFromApiDetails(apiDetails: OnCallModelApiDetails, call: OnCallFunctionType, modelType: FirestoreModelType, specifier?: ModelFirebaseCrudFunctionSpecifier): Maybe<OidcScopeTerm>;
567
596
  /**
568
597
  * @deprecated Use {@link OnCallModelTypeApiDetails} instead.
569
598
  */
@@ -1,6 +1,6 @@
1
1
  import { type Maybe } from '@dereekb/util';
2
2
  import { type NestContextCallableRequest } from '../function/nest';
3
- import { type OnCallFunctionType, type FirestoreModelType } from '@dereekb/firebase';
3
+ import { type OnCallFunctionType, type FirestoreModelType, type OidcScopeTerm } from '@dereekb/firebase';
4
4
  /**
5
5
  * Discriminator for the category of CRUD operation being asserted.
6
6
  *
@@ -34,6 +34,15 @@ export interface AssertModelCrudRequestFunctionContext<N, I = unknown> {
34
34
  * The optional sub-operation specifier (e.g., 'username', 'fromUpload').
35
35
  */
36
36
  readonly specifier: Maybe<string>;
37
+ /**
38
+ * The per-function required OIDC scope TERM declared via `withApiDetails({ requiredScope })`, when present.
39
+ *
40
+ * A single scope string, or a `readonly` array as an OR-group (see {@link OidcScopeTerm}). Resolved
41
+ * from the handler's `_apiDetails` at dispatch so the model-api scope gate (`assertModelApiOidcScope`)
42
+ * can enforce it as the finest group term (AND-ed with the per-verb `model.<call>` scope).
43
+ * `undefined` when the handler declares no extra scope.
44
+ */
45
+ readonly requiredScope?: Maybe<OidcScopeTerm>;
37
46
  }
38
47
  /**
39
48
  * Pre-assertion hook invoked before a model CRUD handler executes.
package/test/index.cjs.js CHANGED
@@ -4922,18 +4922,24 @@ function _ts_generator$1(thisArg, body) {
4922
4922
  }
4923
4923
  /**
4924
4924
  * Resolves the scopes string from config, or falls back to all registered scopes
4925
- * from the provider config — excluding any `adminOnlyScopes`.
4925
+ * from the provider config — excluding any `adminOnlyScopes` or provider-profile-gated scopes.
4926
4926
  *
4927
4927
  * Admin-only scopes (e.g. `token.service`) are dropped from the default "all scopes" request because
4928
4928
  * the provider hard-rejects them for non-admin users, and this default flow logs in an arbitrary
4929
4929
  * (often non-admin) user. Tests that need an admin-only scope pass it explicitly via `config.scopes`.
4930
4930
  *
4931
+ * Provider-profile-gated scopes (e.g. `lms`, `reports`) are dropped for the same reason: they are
4932
+ * unlocked only for a client an admin has assigned the corresponding profile to, and this flow creates
4933
+ * a fresh client with no profiles — so the consent unlock gate hard-rejects them (finishing the
4934
+ * interaction with `access_denied` and no `code`). Tests that need a gated scope create a client with
4935
+ * the profile and pass the scope explicitly via `config.scopes`.
4936
+ *
4931
4937
  * @param nestApp - Initialized NestJS application used to resolve {@link OidcAccountService} when no scopes override is given.
4932
4938
  * @param config - Optional flow config; when `config.scopes` is set, it is returned verbatim.
4933
4939
  * @returns The space-separated scope string to pass to the `/oidc/auth` endpoint.
4934
4940
  */ function resolveScopes(nestApp, config) {
4935
4941
  return _async_to_generator$1(function() {
4936
- var result, _providerConfig_adminOnlyScopes, accountService, providerConfig, adminOnlyScopes;
4942
+ var result, _providerConfig_adminOnlyScopes, _providerConfig_providerProfiles, accountService, providerConfig, adminOnlyScopes, profileGatedScopes;
4937
4943
  return _ts_generator$1(this, function(_state) {
4938
4944
  if (config === null || config === void 0 ? void 0 : config.scopes) {
4939
4945
  result = config.scopes;
@@ -4941,8 +4947,9 @@ function _ts_generator$1(thisArg, body) {
4941
4947
  accountService = nestApp.get(oidc.OidcAccountService);
4942
4948
  providerConfig = accountService.providerConfig;
4943
4949
  adminOnlyScopes = new Set((_providerConfig_adminOnlyScopes = providerConfig.adminOnlyScopes) !== null && _providerConfig_adminOnlyScopes !== void 0 ? _providerConfig_adminOnlyScopes : []);
4950
+ profileGatedScopes = firebase.scopesForOidcProviderProfiles((_providerConfig_providerProfiles = providerConfig.providerProfiles) !== null && _providerConfig_providerProfiles !== void 0 ? _providerConfig_providerProfiles : []);
4944
4951
  result = Object.keys(providerConfig.claims).filter(function(scope) {
4945
- return !adminOnlyScopes.has(scope);
4952
+ return !adminOnlyScopes.has(scope) && !profileGatedScopes.has(scope);
4946
4953
  }).join(' ');
4947
4954
  }
4948
4955
  return [
package/test/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { randomEmailFactory, randomPhoneNumberFactory, mapGetter, incrementingNumberFactory, asGetter, getValueFromGetter, cachedGetter, asArray, mapObjectMap, unixDateTimeSecondsNumberForNow } from '@dereekb/util';
2
2
  import { useTestContextFixture, AbstractChildTestContextFixture, testContextBuilder, AbstractTestContextFixture, useTestFunctionFixture, useTestFunctionMapFixture, ExpectedErrorOfSpecificTypeError } from '@dereekb/util/test';
3
3
  import { decode } from 'jsonwebtoken';
4
- import { flatFirestoreModelKey, twoWayFlatFirestoreModelKey, firestoreContextFactory, firebaseStorageContextFactory } from '@dereekb/firebase';
4
+ import { flatFirestoreModelKey, twoWayFlatFirestoreModelKey, firestoreContextFactory, firebaseStorageContextFactory, scopesForOidcProviderProfiles } from '@dereekb/firebase';
5
5
  import admin from 'firebase-admin';
6
6
  import functions from 'firebase-functions-test';
7
7
  import { makeTestingFirestoreDrivers, TestFirestoreInstance, TestFirestoreContextFixture, makeTestingFirebaseStorageDrivers, TestFirebaseStorageInstance, TestFirebaseStorageContextFixture, mockItemFirestoreCollection, testWithMockItemCollectionFixture, testWithMockItemStorageFixture } from '@dereekb/firebase/test';
@@ -4921,18 +4921,24 @@ function _ts_generator$1(thisArg, body) {
4921
4921
  }
4922
4922
  /**
4923
4923
  * Resolves the scopes string from config, or falls back to all registered scopes
4924
- * from the provider config — excluding any `adminOnlyScopes`.
4924
+ * from the provider config — excluding any `adminOnlyScopes` or provider-profile-gated scopes.
4925
4925
  *
4926
4926
  * Admin-only scopes (e.g. `token.service`) are dropped from the default "all scopes" request because
4927
4927
  * the provider hard-rejects them for non-admin users, and this default flow logs in an arbitrary
4928
4928
  * (often non-admin) user. Tests that need an admin-only scope pass it explicitly via `config.scopes`.
4929
4929
  *
4930
+ * Provider-profile-gated scopes (e.g. `lms`, `reports`) are dropped for the same reason: they are
4931
+ * unlocked only for a client an admin has assigned the corresponding profile to, and this flow creates
4932
+ * a fresh client with no profiles — so the consent unlock gate hard-rejects them (finishing the
4933
+ * interaction with `access_denied` and no `code`). Tests that need a gated scope create a client with
4934
+ * the profile and pass the scope explicitly via `config.scopes`.
4935
+ *
4930
4936
  * @param nestApp - Initialized NestJS application used to resolve {@link OidcAccountService} when no scopes override is given.
4931
4937
  * @param config - Optional flow config; when `config.scopes` is set, it is returned verbatim.
4932
4938
  * @returns The space-separated scope string to pass to the `/oidc/auth` endpoint.
4933
4939
  */ function resolveScopes(nestApp, config) {
4934
4940
  return _async_to_generator$1(function() {
4935
- var result, _providerConfig_adminOnlyScopes, accountService, providerConfig, adminOnlyScopes;
4941
+ var result, _providerConfig_adminOnlyScopes, _providerConfig_providerProfiles, accountService, providerConfig, adminOnlyScopes, profileGatedScopes;
4936
4942
  return _ts_generator$1(this, function(_state) {
4937
4943
  if (config === null || config === void 0 ? void 0 : config.scopes) {
4938
4944
  result = config.scopes;
@@ -4940,8 +4946,9 @@ function _ts_generator$1(thisArg, body) {
4940
4946
  accountService = nestApp.get(OidcAccountService);
4941
4947
  providerConfig = accountService.providerConfig;
4942
4948
  adminOnlyScopes = new Set((_providerConfig_adminOnlyScopes = providerConfig.adminOnlyScopes) !== null && _providerConfig_adminOnlyScopes !== void 0 ? _providerConfig_adminOnlyScopes : []);
4949
+ profileGatedScopes = scopesForOidcProviderProfiles((_providerConfig_providerProfiles = providerConfig.providerProfiles) !== null && _providerConfig_providerProfiles !== void 0 ? _providerConfig_providerProfiles : []);
4943
4950
  result = Object.keys(providerConfig.claims).filter(function(scope) {
4944
- return !adminOnlyScopes.has(scope);
4951
+ return !adminOnlyScopes.has(scope) && !profileGatedScopes.has(scope);
4945
4952
  }).join(' ');
4946
4953
  }
4947
4954
  return [
package/test/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/test",
3
- "version": "13.28.0",
3
+ "version": "13.30.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.28.0",
6
- "@dereekb/date": "13.28.0",
7
- "@dereekb/firebase": "13.28.0",
8
- "@dereekb/firebase-server": "13.28.0",
9
- "@dereekb/firebase-server/oidc": "13.28.0",
10
- "@dereekb/model": "13.28.0",
11
- "@dereekb/nestjs": "13.28.0",
12
- "@dereekb/rxjs": "13.28.0",
13
- "@dereekb/util": "13.28.0",
5
+ "@dereekb/analytics": "13.30.0",
6
+ "@dereekb/date": "13.30.0",
7
+ "@dereekb/firebase": "13.30.0",
8
+ "@dereekb/firebase-server": "13.30.0",
9
+ "@dereekb/firebase-server/oidc": "13.30.0",
10
+ "@dereekb/model": "13.30.0",
11
+ "@dereekb/nestjs": "13.30.0",
12
+ "@dereekb/rxjs": "13.30.0",
13
+ "@dereekb/util": "13.30.0",
14
14
  "@google-cloud/firestore": "^7.11.6",
15
15
  "@google-cloud/storage": "^7.19.0",
16
16
  "@nestjs/common": "^11.1.19",
@@ -23,7 +23,7 @@
23
23
  "supertest": "^7.2.2"
24
24
  },
25
25
  "devDependencies": {
26
- "@dereekb/nestjs": "13.28.0"
26
+ "@dereekb/nestjs": "13.30.0"
27
27
  },
28
28
  "exports": {
29
29
  "./package.json": "./package.json",
@@ -1,5 +1,5 @@
1
1
  import { type INestApplication } from '@nestjs/common';
2
- import type { OidcTokenEndpointAuthMethod } from '@dereekb/firebase';
2
+ import { type OidcTokenEndpointAuthMethod } from '@dereekb/firebase';
3
3
  import { OidcClientService } from '@dereekb/firebase-server/oidc';
4
4
  /**
5
5
  * Configuration for {@link performFullOAuthFlow}.
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/twilio",
3
- "version": "13.28.0",
3
+ "version": "13.30.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.28.0",
6
- "@dereekb/firebase": "13.28.0",
7
- "@dereekb/firebase-server": "13.28.0",
8
- "@dereekb/model": "13.28.0",
9
- "@dereekb/nestjs": "13.28.0",
10
- "@dereekb/rxjs": "13.28.0",
11
- "@dereekb/util": "13.28.0"
5
+ "@dereekb/date": "13.30.0",
6
+ "@dereekb/firebase": "13.30.0",
7
+ "@dereekb/firebase-server": "13.30.0",
8
+ "@dereekb/model": "13.30.0",
9
+ "@dereekb/nestjs": "13.30.0",
10
+ "@dereekb/rxjs": "13.30.0",
11
+ "@dereekb/util": "13.30.0"
12
12
  },
13
13
  "exports": {
14
14
  "./package.json": "./package.json",
package/zoho/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/zoho",
3
- "version": "13.28.0",
3
+ "version": "13.30.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.28.0",
6
- "@dereekb/date": "13.28.0",
7
- "@dereekb/model": "13.28.0",
8
- "@dereekb/nestjs": "13.28.0",
9
- "@dereekb/rxjs": "13.28.0",
10
- "@dereekb/firebase": "13.28.0",
11
- "@dereekb/util": "13.28.0",
12
- "@dereekb/zoho": "13.28.0"
5
+ "@dereekb/analytics": "13.30.0",
6
+ "@dereekb/date": "13.30.0",
7
+ "@dereekb/model": "13.30.0",
8
+ "@dereekb/nestjs": "13.30.0",
9
+ "@dereekb/rxjs": "13.30.0",
10
+ "@dereekb/firebase": "13.30.0",
11
+ "@dereekb/util": "13.30.0",
12
+ "@dereekb/zoho": "13.30.0"
13
13
  },
14
14
  "exports": {
15
15
  "./package.json": "./package.json",
@@ -1,19 +0,0 @@
1
- import { type OnCallTypedModelParams } from '@dereekb/firebase';
2
- import { type AssertModelCrudRequestFunction } from '@dereekb/firebase-server';
3
- /**
4
- * Builds a {@link AssertModelCrudRequestFunction} that rejects callModel requests
5
- * lacking the OIDC scope mapped from the call type.
6
- *
7
- * Bypasses the check (no-op) when the request is not OIDC-authenticated — i.e.
8
- * when {@link getOidcScopesFromRequest} returns `undefined` because there is no
9
- * `auth.token.scope` claim on the request. Regular Firebase ID-token callers are
10
- * unaffected and continue to be gated by auth roles.
11
- *
12
- * Bypasses the check for custom (non-CRUD) call types so app-specific verbs
13
- * remain unrestricted unless an app wires its own assertion.
14
- *
15
- * Wire as the `preAssert` of {@link onCallModel}.
16
- *
17
- * @returns The pre-assertion function ready to plug into `OnCallModelConfig.preAssert`.
18
- */
19
- export declare function oidcCallModelScopePreAssert(): AssertModelCrudRequestFunction<unknown, OnCallTypedModelParams>;