@dereekb/firebase-server 13.29.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.
- package/index.cjs.js +129 -1
- package/index.esm.js +129 -3
- package/mailgun/package.json +9 -9
- package/mcp/index.cjs.js +42 -17
- package/mcp/index.esm.js +43 -18
- package/mcp/package.json +11 -11
- package/mcp/src/lib/mcp.config.d.ts +19 -1
- package/mcp/src/lib/service/mcp.server.factory.d.ts +1 -1
- package/mcp/src/lib/service/mcp.tool-generator.d.ts +12 -1
- package/mcp/src/lib/service/mcp.visibility.d.ts +9 -6
- package/model/package.json +9 -9
- package/oidc/index.cjs.js +2 -53
- package/oidc/index.esm.js +6 -56
- package/oidc/package.json +10 -10
- package/oidc/src/lib/index.d.ts +0 -1
- package/oidc/src/lib/service/oidc.auth.d.ts +1 -1
- package/package.json +10 -10
- package/src/lib/nest/controller/model/index.d.ts +1 -0
- package/src/lib/nest/controller/model/model.api.dispatch.d.ts +14 -2
- package/src/lib/nest/controller/model/model.api.get.service.d.ts +14 -0
- package/src/lib/nest/controller/model/model.api.scope.d.ts +102 -0
- package/src/lib/nest/model/api.details.d.ts +13 -8
- package/src/lib/nest/model/crud.assert.function.d.ts +7 -6
- package/test/package.json +11 -11
- package/twilio/package.json +8 -8
- package/zoho/package.json +9 -9
- package/oidc/src/lib/scope.d.ts +0 -24
|
@@ -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, type
|
|
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
|
|
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
|
/**
|
|
@@ -303,15 +303,20 @@ export interface OnCallModelFunctionApiDetails<R = unknown, M = unknown> {
|
|
|
303
303
|
*/
|
|
304
304
|
readonly analytics?: OnCallModelFunctionAnalyticsDetails;
|
|
305
305
|
/**
|
|
306
|
-
* Optional per-function OIDC scope an OIDC-authenticated caller must additionally hold to
|
|
306
|
+
* Optional per-function OIDC scope TERM an OIDC-authenticated caller must additionally hold to
|
|
307
307
|
* invoke this handler, on top of the per-verb `model.<call>` scope.
|
|
308
308
|
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
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)
|
|
311
316
|
* bypass scope enforcement entirely and are unaffected. Also folded into the MCP tool-list
|
|
312
|
-
* visibility filter, so a tool the caller
|
|
317
|
+
* visibility filter, so a tool the caller cannot satisfy this term for is neither listed nor callable.
|
|
313
318
|
*/
|
|
314
|
-
readonly requiredScope?:
|
|
319
|
+
readonly requiredScope?: OidcScopeTerm;
|
|
315
320
|
}
|
|
316
321
|
/**
|
|
317
322
|
* Ref interface for objects (functions) that carry handler-level _apiDetails.
|
|
@@ -587,7 +592,7 @@ export declare function resolveAnalyticsFromApiDetails(apiDetails: OnCallModelAp
|
|
|
587
592
|
* @param specifier - Optional specifier key for variant handlers.
|
|
588
593
|
* @returns The per-function required scope for the resolved handler, or undefined.
|
|
589
594
|
*/
|
|
590
|
-
export declare function resolveRequiredScopeFromApiDetails(apiDetails: OnCallModelApiDetails, call: OnCallFunctionType, modelType: FirestoreModelType, specifier?: ModelFirebaseCrudFunctionSpecifier): Maybe<
|
|
595
|
+
export declare function resolveRequiredScopeFromApiDetails(apiDetails: OnCallModelApiDetails, call: OnCallFunctionType, modelType: FirestoreModelType, specifier?: ModelFirebaseCrudFunctionSpecifier): Maybe<OidcScopeTerm>;
|
|
591
596
|
/**
|
|
592
597
|
* @deprecated Use {@link OnCallModelTypeApiDetails} instead.
|
|
593
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, type
|
|
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
|
*
|
|
@@ -35,13 +35,14 @@ export interface AssertModelCrudRequestFunctionContext<N, I = unknown> {
|
|
|
35
35
|
*/
|
|
36
36
|
readonly specifier: Maybe<string>;
|
|
37
37
|
/**
|
|
38
|
-
* The per-function required OIDC scope declared via `withApiDetails({ requiredScope })`, when present.
|
|
38
|
+
* The per-function required OIDC scope TERM declared via `withApiDetails({ requiredScope })`, when present.
|
|
39
39
|
*
|
|
40
|
-
*
|
|
41
|
-
* `
|
|
42
|
-
*
|
|
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.
|
|
43
44
|
*/
|
|
44
|
-
readonly requiredScope?: Maybe<
|
|
45
|
+
readonly requiredScope?: Maybe<OidcScopeTerm>;
|
|
45
46
|
}
|
|
46
47
|
/**
|
|
47
48
|
* Pre-assertion hook invoked before a model CRUD handler executes.
|
package/test/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/test",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.30.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/analytics": "13.
|
|
6
|
-
"@dereekb/date": "13.
|
|
7
|
-
"@dereekb/firebase": "13.
|
|
8
|
-
"@dereekb/firebase-server": "13.
|
|
9
|
-
"@dereekb/firebase-server/oidc": "13.
|
|
10
|
-
"@dereekb/model": "13.
|
|
11
|
-
"@dereekb/nestjs": "13.
|
|
12
|
-
"@dereekb/rxjs": "13.
|
|
13
|
-
"@dereekb/util": "13.
|
|
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.
|
|
26
|
+
"@dereekb/nestjs": "13.30.0"
|
|
27
27
|
},
|
|
28
28
|
"exports": {
|
|
29
29
|
"./package.json": "./package.json",
|
package/twilio/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/firebase-server/twilio",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.30.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/date": "13.
|
|
6
|
-
"@dereekb/firebase": "13.
|
|
7
|
-
"@dereekb/firebase-server": "13.
|
|
8
|
-
"@dereekb/model": "13.
|
|
9
|
-
"@dereekb/nestjs": "13.
|
|
10
|
-
"@dereekb/rxjs": "13.
|
|
11
|
-
"@dereekb/util": "13.
|
|
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.
|
|
3
|
+
"version": "13.30.0",
|
|
4
4
|
"peerDependencies": {
|
|
5
|
-
"@dereekb/analytics": "13.
|
|
6
|
-
"@dereekb/date": "13.
|
|
7
|
-
"@dereekb/model": "13.
|
|
8
|
-
"@dereekb/nestjs": "13.
|
|
9
|
-
"@dereekb/rxjs": "13.
|
|
10
|
-
"@dereekb/firebase": "13.
|
|
11
|
-
"@dereekb/util": "13.
|
|
12
|
-
"@dereekb/zoho": "13.
|
|
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",
|
package/oidc/src/lib/scope.d.ts
DELETED
|
@@ -1,24 +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 required OIDC scope(s) for the call.
|
|
6
|
-
*
|
|
7
|
-
* Enforcement is additive: an OIDC caller must hold BOTH the per-verb scope mapped
|
|
8
|
-
* from the call type (`model.<call>`) AND any per-function scope a handler declared
|
|
9
|
-
* via `withApiDetails({ requiredScope })` — surfaced on `context.requiredScope`.
|
|
10
|
-
*
|
|
11
|
-
* Bypasses the check (no-op) when the request is not OIDC-authenticated — i.e.
|
|
12
|
-
* when {@link getOidcScopesFromRequest} returns `undefined` because there is no
|
|
13
|
-
* `auth.token.scope` claim on the request. Regular Firebase ID-token callers are
|
|
14
|
-
* unaffected and continue to be gated by auth roles.
|
|
15
|
-
*
|
|
16
|
-
* Bypasses the check for custom (non-CRUD) call types that declare no per-function
|
|
17
|
-
* scope, so app-specific verbs remain unrestricted unless an app wires its own
|
|
18
|
-
* assertion or declares a `requiredScope`.
|
|
19
|
-
*
|
|
20
|
-
* Wire as the `preAssert` of {@link onCallModel}.
|
|
21
|
-
*
|
|
22
|
-
* @returns The pre-assertion function ready to plug into `OnCallModelConfig.preAssert`.
|
|
23
|
-
*/
|
|
24
|
-
export declare function oidcCallModelScopePreAssert(): AssertModelCrudRequestFunction<unknown, OnCallTypedModelParams>;
|