@dereekb/firebase-server 13.37.0 → 13.38.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/mcp/index.cjs.js CHANGED
@@ -16,7 +16,7 @@ function _class_call_check$5(instance, Constructor) {
16
16
  throw new TypeError("Cannot call a class as a function");
17
17
  }
18
18
  }
19
- function _define_property$9(obj, key, value) {
19
+ function _define_property$a(obj, key, value) {
20
20
  if (key in obj) {
21
21
  Object.defineProperty(obj, key, {
22
22
  value: value,
@@ -87,7 +87,7 @@ function _define_property$9(obj, key, value) {
87
87
  * discovery document. Claude custom-connector reads this to discover the OIDC issuer.
88
88
  *
89
89
  * @example 'https://api.example.com/oidc'
90
- */ _define_property$9(this, "oidcIssuer", void 0);
90
+ */ _define_property$a(this, "oidcIssuer", void 0);
91
91
  /**
92
92
  * The canonical resource URL of the MCP endpoint.
93
93
  *
@@ -95,7 +95,7 @@ function _define_property$9(obj, key, value) {
95
95
  * and used as the audience the access token's `aud` claim should match.
96
96
  *
97
97
  * @example 'https://api.example.com/mcp'
98
- */ _define_property$9(this, "mcpUrl", void 0);
98
+ */ _define_property$a(this, "mcpUrl", void 0);
99
99
  /**
100
100
  * Optional filter applied to the OIDC provider's scope list when building the
101
101
  * protected-resource discovery document's `scopes_supported` (RFC 9728 §2).
@@ -114,19 +114,19 @@ function _define_property$9(obj, key, value) {
114
114
  * the OIDC provider nothing to grant and ending the interaction in `access_denied`.
115
115
  *
116
116
  * @example (allScopes) => allScopes.filter((scope) => scope === 'openid' || scope.startsWith('model.'))
117
- */ _define_property$9(this, "scopesSupported", void 0);
117
+ */ _define_property$a(this, "scopesSupported", void 0);
118
118
  /**
119
119
  * Optional name advertised on the MCP `initialize` handshake. Defaults to
120
120
  * {@link DEFAULT_MCP_SERVER_NAME}.
121
- */ _define_property$9(this, "serverName", void 0);
121
+ */ _define_property$a(this, "serverName", void 0);
122
122
  /**
123
123
  * Optional version advertised on the MCP `initialize` handshake.
124
- */ _define_property$9(this, "serverVersion", void 0);
124
+ */ _define_property$a(this, "serverVersion", void 0);
125
125
  /**
126
126
  * Optional override for the `instructions` string passed to `new McpServer(...)` and
127
127
  * advertised on the JSON-RPC `initialize` handshake. Defaults to
128
128
  * {@link DEFAULT_MCP_SERVER_INSTRUCTIONS}.
129
- */ _define_property$9(this, "serverInstructions", void 0);
129
+ */ _define_property$a(this, "serverInstructions", void 0);
130
130
  /**
131
131
  * Absolute path to a pre-rendered MCP manifest JSON file produced by
132
132
  * `dbx-cli-generate-mcp-manifest`. When set, the runtime reads it once at
@@ -136,7 +136,7 @@ function _define_property$9(obj, key, value) {
136
136
  * Optional. When unset or the file is missing, the runtime falls back to
137
137
  * today's behavior (auto-generated descriptions, ArkType-derived input
138
138
  * schemas, no output schemas) and emits a single boot warning.
139
- */ _define_property$9(this, "mcpManifestPath", void 0);
139
+ */ _define_property$a(this, "mcpManifestPath", void 0);
140
140
  /**
141
141
  * Absolute path to a pre-rendered route manifest JSON file produced by
142
142
  * `dbx-cli-generate-route-manifest`. When set, the runtime reads it once at
@@ -146,7 +146,7 @@ function _define_property$9(obj, key, value) {
146
146
  * Optional. When unset or the file is missing, the runtime skips registering
147
147
  * `url-models` and emits a single boot warning when the path was set but
148
148
  * unreadable.
149
- */ _define_property$9(this, "mcpRouteManifestPath", void 0);
149
+ */ _define_property$a(this, "mcpRouteManifestPath", void 0);
150
150
  /**
151
151
  * When `true`, the MCP server only advertises tools whose effective read-only classification is `true`.
152
152
  *
@@ -156,7 +156,7 @@ function _define_property$9(obj, key, value) {
156
156
  *
157
157
  * The advertised `serverName` on the JSON-RPC `initialize` handshake is suffixed with
158
158
  * ` (read-only)` so the client surface reflects the mode.
159
- */ _define_property$9(this, "readOnly", void 0);
159
+ */ _define_property$a(this, "readOnly", void 0);
160
160
  /**
161
161
  * Controls the auto-injected `reason` parameter added to every advertised tool's input schema.
162
162
  *
@@ -166,7 +166,7 @@ function _define_property$9(obj, key, value) {
166
166
  * When enabled, every advertised tool's `inputSchema` carries a required `reason` string the model
167
167
  * fills with a short justification for the call. The value is forwarded to analytics and stripped
168
168
  * from the dispatched handler body. See {@link McpReasonParameterConfig}.
169
- */ _define_property$9(this, "reasonParameter", void 0);
169
+ */ _define_property$a(this, "reasonParameter", void 0);
170
170
  /**
171
171
  * Default OIDC scope group term required on EVERY `callModel` op, mirrored into MCP tool-list
172
172
  * visibility, unless a finer term overrides it (a per-function `requiredScope`, then a
@@ -176,17 +176,20 @@ function _define_property$9(obj, key, value) {
176
176
  *
177
177
  * Set this to the SAME value passed to `ModelApiDispatchConfig.defaultRequiredScope` to
178
178
  * keep tool visibility and enforcement in lockstep.
179
- */ _define_property$9(this, "defaultRequiredScope", void 0);
179
+ */ _define_property$a(this, "defaultRequiredScope", void 0);
180
180
  /**
181
181
  * Per-model OIDC scope group-term overrides, keyed by {@link FirestoreModelType}, mirrored into MCP
182
182
  * tool-list visibility. Set this to the SAME value passed to
183
183
  * `ModelApiDispatchConfig.modelRequiredScopes` so per-model / verb-keyed restrictions that
184
184
  * confine a subset client apply identically to the advertised tool list.
185
- */ _define_property$9(this, "modelRequiredScopes", void 0);
185
+ */ _define_property$a(this, "modelRequiredScopes", void 0);
186
186
  };
187
187
  /**
188
188
  * NestJS injection token for the optional {@link McpAuthRoleReader} provider.
189
189
  */ var MCP_AUTH_ROLE_READER = 'MCP_AUTH_ROLE_READER';
190
+ /**
191
+ * NestJS injection token for the optional {@link McpModelRolesTargetUidPredicate} provider.
192
+ */ var MCP_MODEL_ROLES_TARGET_UID_PREDICATE = 'MCP_MODEL_ROLES_TARGET_UID_PREDICATE';
190
193
 
191
194
  function _type_of$5(obj) {
192
195
  "@swc/helpers - typeof";
@@ -216,7 +219,7 @@ function _array_like_to_array$b(arr, len) {
216
219
  function _array_without_holes$8(arr) {
217
220
  if (Array.isArray(arr)) return _array_like_to_array$b(arr);
218
221
  }
219
- function _define_property$8(obj, key, value) {
222
+ function _define_property$9(obj, key, value) {
220
223
  if (key in obj) {
221
224
  Object.defineProperty(obj, key, {
222
225
  value: value,
@@ -235,7 +238,7 @@ function _iterable_to_array$8(iter) {
235
238
  function _non_iterable_spread$8() {
236
239
  throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
237
240
  }
238
- function _object_spread$6(target) {
241
+ function _object_spread$7(target) {
239
242
  for(var i = 1; i < arguments.length; i++){
240
243
  var source = arguments[i] != null ? arguments[i] : {};
241
244
  var ownKeys = Object.keys(source);
@@ -245,7 +248,7 @@ function _object_spread$6(target) {
245
248
  }));
246
249
  }
247
250
  ownKeys.forEach(function(key) {
248
- _define_property$8(target, key, source[key]);
251
+ _define_property$9(target, key, source[key]);
249
252
  });
250
253
  }
251
254
  return target;
@@ -355,9 +358,9 @@ function _unsupported_iterable_to_array$b(o, minLen) {
355
358
  var _base_type;
356
359
  var base = (typeof inputSchema === "undefined" ? "undefined" : _type_of$4(inputSchema)) === 'object' && inputSchema != null ? inputSchema : {};
357
360
  var existingProperties = _type_of$4(base.properties) === 'object' && base.properties != null ? base.properties : {};
358
- var next = _object_spread_props$3(_object_spread$6({}, base), {
361
+ var next = _object_spread_props$3(_object_spread$7({}, base), {
359
362
  type: (_base_type = base.type) !== null && _base_type !== void 0 ? _base_type : 'object',
360
- properties: _object_spread_props$3(_object_spread$6({}, existingProperties), _define_property$8({}, resolved.parameterName, {
363
+ properties: _object_spread_props$3(_object_spread$7({}, existingProperties), _define_property$9({}, resolved.parameterName, {
361
364
  type: 'string',
362
365
  maxLength: resolved.maxLength,
363
366
  description: resolved.description
@@ -391,7 +394,7 @@ function _unsupported_iterable_to_array$b(o, minLen) {
391
394
  var result;
392
395
  if (resolved.enabled && !toolDeclaresOwnReason && Object.prototype.hasOwnProperty.call(args, resolved.parameterName)) {
393
396
  var rawValue = args[resolved.parameterName];
394
- var nextArgs = _object_spread$6({}, args);
397
+ var nextArgs = _object_spread$7({}, args);
395
398
  delete nextArgs[resolved.parameterName];
396
399
  var stringValue = rawValue == null ? '' : String(rawValue);
397
400
  var clamped = stringValue.length > resolved.maxLength ? stringValue.slice(0, resolved.maxLength) : stringValue;
@@ -746,7 +749,7 @@ function scoreCandidates(states, pathname) {
746
749
  });
747
750
  }
748
751
 
749
- function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
752
+ function asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, key, arg) {
750
753
  try {
751
754
  var info = gen[key](arg);
752
755
  var value = info.value;
@@ -760,16 +763,16 @@ function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
760
763
  Promise.resolve(value).then(_next, _throw);
761
764
  }
762
765
  }
763
- function _async_to_generator$6(fn) {
766
+ function _async_to_generator$7(fn) {
764
767
  return function() {
765
768
  var self = this, args = arguments;
766
769
  return new Promise(function(resolve, reject) {
767
770
  var gen = fn.apply(self, args);
768
771
  function _next(value) {
769
- asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "next", value);
772
+ asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "next", value);
770
773
  }
771
774
  function _throw(err) {
772
- asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "throw", err);
775
+ asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "throw", err);
773
776
  }
774
777
  _next(undefined);
775
778
  });
@@ -783,7 +786,7 @@ function _instanceof$1(left, right) {
783
786
  return left instanceof right;
784
787
  }
785
788
  }
786
- function _ts_generator$6(thisArg, body) {
789
+ function _ts_generator$7(thisArg, body) {
787
790
  var f, y, t, _ = {
788
791
  label: 0,
789
792
  sent: function() {
@@ -911,9 +914,9 @@ function _ts_generator$6(thisArg, body) {
911
914
  * @param details - The handler-level API details (carries the mapper + Tier 2/3 formatters).
912
915
  * @returns The MCP tool response content.
913
916
  */ function formatMcpToolResponse(result, params, details) {
914
- return _async_to_generator$6(function() {
917
+ return _async_to_generator$7(function() {
915
918
  var mcp, value, _tmp, context, response, summary;
916
- return _ts_generator$6(this, function(_state) {
919
+ return _ts_generator$7(this, function(_state) {
917
920
  switch(_state.label){
918
921
  case 0:
919
922
  mcp = details === null || details === void 0 ? void 0 : details.mcp;
@@ -1773,7 +1776,7 @@ function _array_like_to_array$8(arr, len) {
1773
1776
  function _array_without_holes$7(arr) {
1774
1777
  if (Array.isArray(arr)) return _array_like_to_array$8(arr);
1775
1778
  }
1776
- function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
1779
+ function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
1777
1780
  try {
1778
1781
  var info = gen[key](arg);
1779
1782
  var value = info.value;
@@ -1787,16 +1790,16 @@ function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
1787
1790
  Promise.resolve(value).then(_next, _throw);
1788
1791
  }
1789
1792
  }
1790
- function _async_to_generator$5(fn) {
1793
+ function _async_to_generator$6(fn) {
1791
1794
  return function() {
1792
1795
  var self = this, args = arguments;
1793
1796
  return new Promise(function(resolve, reject) {
1794
1797
  var gen = fn.apply(self, args);
1795
1798
  function _next(value) {
1796
- asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "next", value);
1799
+ asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "next", value);
1797
1800
  }
1798
1801
  function _throw(err) {
1799
- asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "throw", err);
1802
+ asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "throw", err);
1800
1803
  }
1801
1804
  _next(undefined);
1802
1805
  });
@@ -1819,7 +1822,7 @@ function _unsupported_iterable_to_array$8(o, minLen) {
1819
1822
  if (n === "Map" || n === "Set") return Array.from(n);
1820
1823
  if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$8(o, minLen);
1821
1824
  }
1822
- function _ts_generator$5(thisArg, body) {
1825
+ function _ts_generator$6(thisArg, body) {
1823
1826
  var f, y, t, _ = {
1824
1827
  label: 0,
1825
1828
  sent: function() {
@@ -1980,9 +1983,9 @@ function _ts_generator$5(thisArg, body) {
1980
1983
  }
1981
1984
  // MARK: Handler
1982
1985
  function modelGetToolHandler(args, ctx, deps) {
1983
- return _async_to_generator$5(function() {
1986
+ return _async_to_generator$6(function() {
1984
1987
  var result, input, identity, resolvedKeys, merged, error;
1985
- return _ts_generator$5(this, function(_state) {
1988
+ return _ts_generator$6(this, function(_state) {
1986
1989
  switch(_state.label){
1987
1990
  case 0:
1988
1991
  _state.trys.push([
@@ -1996,7 +1999,7 @@ function modelGetToolHandler(args, ctx, deps) {
1996
1999
  if (identity == null) {
1997
2000
  throw new Error("Unknown modelType: ".concat(input.modelType));
1998
2001
  }
1999
- resolvedKeys = resolveKeys(input.keys, identity);
2002
+ resolvedKeys = resolveKeys$1(input.keys, identity);
2000
2003
  return [
2001
2004
  4,
2002
2005
  readInChunks$1({
@@ -2057,7 +2060,7 @@ function parseModelGetInput(args) {
2057
2060
  keys: normalizedKeys
2058
2061
  };
2059
2062
  }
2060
- function resolveKeys(keys, identity) {
2063
+ function resolveKeys$1(keys, identity) {
2061
2064
  var isRoot = identity.type === 'root';
2062
2065
  var resolved = [];
2063
2066
  var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
@@ -2089,9 +2092,9 @@ function resolveKeys(keys, identity) {
2089
2092
  return resolved;
2090
2093
  }
2091
2094
  function readInChunks$1(input) {
2092
- return _async_to_generator$5(function() {
2095
+ return _async_to_generator$6(function() {
2093
2096
  var modelType, keys, auth, readDocuments, merged, offset, _merged_results, _merged_errors, batch, partial;
2094
- return _ts_generator$5(this, function(_state) {
2097
+ return _ts_generator$6(this, function(_state) {
2095
2098
  switch(_state.label){
2096
2099
  case 0:
2097
2100
  modelType = input.modelType, keys = input.keys, auth = input.auth, readDocuments = input.readDocuments;
@@ -2205,6 +2208,512 @@ var MODEL_GET_OUTPUT_SCHEMA = {
2205
2208
  }
2206
2209
  };
2207
2210
 
2211
+ function asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, key, arg) {
2212
+ try {
2213
+ var info = gen[key](arg);
2214
+ var value = info.value;
2215
+ } catch (error) {
2216
+ reject(error);
2217
+ return;
2218
+ }
2219
+ if (info.done) {
2220
+ resolve(value);
2221
+ } else {
2222
+ Promise.resolve(value).then(_next, _throw);
2223
+ }
2224
+ }
2225
+ function _async_to_generator$5(fn) {
2226
+ return function() {
2227
+ var self = this, args = arguments;
2228
+ return new Promise(function(resolve, reject) {
2229
+ var gen = fn.apply(self, args);
2230
+ function _next(value) {
2231
+ asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "next", value);
2232
+ }
2233
+ function _throw(err) {
2234
+ asyncGeneratorStep$5(gen, resolve, reject, _next, _throw, "throw", err);
2235
+ }
2236
+ _next(undefined);
2237
+ });
2238
+ };
2239
+ }
2240
+ function _define_property$8(obj, key, value) {
2241
+ if (key in obj) {
2242
+ Object.defineProperty(obj, key, {
2243
+ value: value,
2244
+ enumerable: true,
2245
+ configurable: true,
2246
+ writable: true
2247
+ });
2248
+ } else {
2249
+ obj[key] = value;
2250
+ }
2251
+ return obj;
2252
+ }
2253
+ function _object_spread$6(target) {
2254
+ for(var i = 1; i < arguments.length; i++){
2255
+ var source = arguments[i] != null ? arguments[i] : {};
2256
+ var ownKeys = Object.keys(source);
2257
+ if (typeof Object.getOwnPropertySymbols === "function") {
2258
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
2259
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
2260
+ }));
2261
+ }
2262
+ ownKeys.forEach(function(key) {
2263
+ _define_property$8(target, key, source[key]);
2264
+ });
2265
+ }
2266
+ return target;
2267
+ }
2268
+ function _ts_generator$5(thisArg, body) {
2269
+ var f, y, t, _ = {
2270
+ label: 0,
2271
+ sent: function() {
2272
+ if (t[0] & 1) throw t[1];
2273
+ return t[1];
2274
+ },
2275
+ trys: [],
2276
+ ops: []
2277
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
2278
+ return d(g, "next", {
2279
+ value: verb(0)
2280
+ }), d(g, "throw", {
2281
+ value: verb(1)
2282
+ }), d(g, "return", {
2283
+ value: verb(2)
2284
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
2285
+ value: function() {
2286
+ return this;
2287
+ }
2288
+ }), g;
2289
+ function verb(n) {
2290
+ return function(v) {
2291
+ return step([
2292
+ n,
2293
+ v
2294
+ ]);
2295
+ };
2296
+ }
2297
+ function step(op) {
2298
+ if (f) throw new TypeError("Generator is already executing.");
2299
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
2300
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
2301
+ if (y = 0, t) op = [
2302
+ op[0] & 2,
2303
+ t.value
2304
+ ];
2305
+ switch(op[0]){
2306
+ case 0:
2307
+ case 1:
2308
+ t = op;
2309
+ break;
2310
+ case 4:
2311
+ _.label++;
2312
+ return {
2313
+ value: op[1],
2314
+ done: false
2315
+ };
2316
+ case 5:
2317
+ _.label++;
2318
+ y = op[1];
2319
+ op = [
2320
+ 0
2321
+ ];
2322
+ continue;
2323
+ case 7:
2324
+ op = _.ops.pop();
2325
+ _.trys.pop();
2326
+ continue;
2327
+ default:
2328
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
2329
+ _ = 0;
2330
+ continue;
2331
+ }
2332
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
2333
+ _.label = op[1];
2334
+ break;
2335
+ }
2336
+ if (op[0] === 6 && _.label < t[1]) {
2337
+ _.label = t[1];
2338
+ t = op;
2339
+ break;
2340
+ }
2341
+ if (t && _.label < t[2]) {
2342
+ _.label = t[2];
2343
+ _.ops.push(op);
2344
+ break;
2345
+ }
2346
+ if (t[2]) _.ops.pop();
2347
+ _.trys.pop();
2348
+ continue;
2349
+ }
2350
+ op = body.call(thisArg, _);
2351
+ } catch (e) {
2352
+ op = [
2353
+ 6,
2354
+ e
2355
+ ];
2356
+ y = 0;
2357
+ } finally{
2358
+ f = t = 0;
2359
+ }
2360
+ if (op[0] & 5) throw op[1];
2361
+ return {
2362
+ value: op[0] ? op[1] : void 0,
2363
+ done: true
2364
+ };
2365
+ }
2366
+ }
2367
+ // MARK: Constants
2368
+ /**
2369
+ * Reserved tool name for the built-in `model-roles` static tool.
2370
+ */ var MODEL_ROLES_TOOL_NAME = 'model-roles';
2371
+ /**
2372
+ * Synthetic call type used in the tool's dispatch identity. Distinct from `model-get`'s `get` so
2373
+ * visibility predicates can target the two independently.
2374
+ */ var MODEL_ROLES_DISPATCH_CALL = 'roles';
2375
+ /**
2376
+ * Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE}
2377
+ * — the tool isn't bound to one model type, so the literal "model" stands in.
2378
+ */ var MODEL_ROLES_DISPATCH_MODEL_TYPE = 'model';
2379
+ /**
2380
+ * Maximum number of keys accepted per `model-roles` call. Role resolution runs the model's real
2381
+ * permission delegate per key (which may itself read parent documents), so this is deliberately
2382
+ * lower than the `model-get` batch size.
2383
+ */ var MCP_MODEL_ROLES_MAX_KEYS = 25;
2384
+ // MARK: Factory
2385
+ /**
2386
+ * Builds the built-in `model-roles` MCP tool definition.
2387
+ *
2388
+ * Answers "what is this user actually allowed to do with this document?" by running the same
2389
+ * `roleMapForModel()` delegate the permission-checked read/write paths use, and returning the
2390
+ * resolved roles instead of consuming them. Because the model's real delegate runs, derived and
2391
+ * cascading roles appear exactly as the API grants them — there is no second implementation of the
2392
+ * rules to drift.
2393
+ *
2394
+ * Two things it disambiguates that a plain read cannot:
2395
+ * - **Missing vs. forbidden.** A key that resolves to a missing document returns
2396
+ * `exists: false, roles: []` rather than an error, so "the document is not there" reads
2397
+ * differently from "it is there and you have no access" (`exists: true, roles: []`).
2398
+ * - **Full access.** Admin short-circuits that grant the full-access marker come back as
2399
+ * `fullAccess: true` rather than as an opaque enumerated set.
2400
+ *
2401
+ * By default roles are resolved for the calling user. Passing `uid` resolves them for another user
2402
+ * and is gated behind {@link CreateModelRolesToolDeps.canTargetOtherUids}.
2403
+ *
2404
+ * @param deps - Role-map reader, identity resolver, and the target-uid authorization predicate.
2405
+ * @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
2406
+ * server factory's tool registry.
2407
+ */ function createModelRolesTool(deps) {
2408
+ var handler = function handler(args, ctx) {
2409
+ return modelRolesToolHandler(args, ctx, deps);
2410
+ };
2411
+ var name = MODEL_ROLES_TOOL_NAME;
2412
+ var description = 'Resolve which roles the current user (or, with "uid", another user) is granted on one or more model keys — the same permission computation the API runs, returned instead of enforced. Use to answer "why was this forbidden?" and to tell a missing document (exists:false) apart from one you cannot access (exists:true, roles:[]). Admin full-access short-circuits report fullAccess:true. Targeting another uid requires elevated access.';
2413
+ return buildStaticToolDefinition({
2414
+ name: name,
2415
+ description: description,
2416
+ inputSchema: MODEL_ROLES_INPUT_SCHEMA,
2417
+ outputSchema: MODEL_ROLES_OUTPUT_SCHEMA,
2418
+ dispatch: {
2419
+ call: MODEL_ROLES_DISPATCH_CALL,
2420
+ modelType: MODEL_ROLES_DISPATCH_MODEL_TYPE
2421
+ },
2422
+ staticHandler: handler,
2423
+ effectiveReadOnly: true,
2424
+ rule: {
2425
+ requireAuthenticated: true
2426
+ }
2427
+ });
2428
+ }
2429
+ // MARK: Handler
2430
+ function modelRolesToolHandler(args, ctx, deps) {
2431
+ return _async_to_generator$5(function() {
2432
+ var result, input, identity, targetUid, keys, resolved, error;
2433
+ return _ts_generator$5(this, function(_state) {
2434
+ switch(_state.label){
2435
+ case 0:
2436
+ _state.trys.push([
2437
+ 0,
2438
+ 3,
2439
+ ,
2440
+ 4
2441
+ ]);
2442
+ input = parseModelRolesInput(args);
2443
+ identity = deps.resolveIdentity(input.modelType, ctx.auth);
2444
+ if (identity == null) {
2445
+ throw new Error("Unknown modelType: ".concat(input.modelType));
2446
+ }
2447
+ return [
2448
+ 4,
2449
+ resolveTargetUid({
2450
+ requestedUid: input.uid,
2451
+ auth: ctx.auth,
2452
+ canTargetOtherUids: deps.canTargetOtherUids
2453
+ })
2454
+ ];
2455
+ case 1:
2456
+ targetUid = _state.sent();
2457
+ keys = resolveKeys(input.keys, identity);
2458
+ return [
2459
+ 4,
2460
+ deps.readRoleMaps(_object_spread$6({
2461
+ modelType: input.modelType,
2462
+ keys: keys,
2463
+ auth: ctx.auth
2464
+ }, targetUid == null ? {} : {
2465
+ targetUid: targetUid
2466
+ }))
2467
+ ];
2468
+ case 2:
2469
+ resolved = _state.sent();
2470
+ result = {
2471
+ content: [
2472
+ {
2473
+ type: 'text',
2474
+ text: JSON.stringify(resolved)
2475
+ }
2476
+ ],
2477
+ structuredContent: resolved
2478
+ };
2479
+ return [
2480
+ 3,
2481
+ 4
2482
+ ];
2483
+ case 3:
2484
+ error = _state.sent();
2485
+ result = formatMcpToolErrorResponse(error);
2486
+ return [
2487
+ 3,
2488
+ 4
2489
+ ];
2490
+ case 4:
2491
+ return [
2492
+ 2,
2493
+ result
2494
+ ];
2495
+ }
2496
+ });
2497
+ })();
2498
+ }
2499
+ /**
2500
+ * Resolves the effective target uid for a call, enforcing the elevated-access gate.
2501
+ *
2502
+ * Requesting your own uid is always allowed and is treated as no target at all, so a caller that
2503
+ * passes their own uid never trips the predicate.
2504
+ *
2505
+ * @param input - The requested uid, the caller's auth, and the authorization predicate.
2506
+ * @returns The uid to resolve as, or `undefined` to resolve as the caller.
2507
+ * @throws {Error} When another user's uid is requested and the predicate denies (or is absent).
2508
+ */ function resolveTargetUid(input) {
2509
+ return _async_to_generator$5(function() {
2510
+ var requestedUid, auth, canTargetOtherUids, result, allowed, _tmp;
2511
+ return _ts_generator$5(this, function(_state) {
2512
+ switch(_state.label){
2513
+ case 0:
2514
+ requestedUid = input.requestedUid, auth = input.auth, canTargetOtherUids = input.canTargetOtherUids;
2515
+ if (!(requestedUid != null && requestedUid !== (auth === null || auth === void 0 ? void 0 : auth.uid))) return [
2516
+ 3,
2517
+ 4
2518
+ ];
2519
+ if (!(canTargetOtherUids == null)) return [
2520
+ 3,
2521
+ 1
2522
+ ];
2523
+ _tmp = false;
2524
+ return [
2525
+ 3,
2526
+ 3
2527
+ ];
2528
+ case 1:
2529
+ return [
2530
+ 4,
2531
+ canTargetOtherUids(auth)
2532
+ ];
2533
+ case 2:
2534
+ _tmp = _state.sent();
2535
+ _state.label = 3;
2536
+ case 3:
2537
+ allowed = _tmp;
2538
+ if (!allowed) {
2539
+ throw new Error("model-roles: resolving roles for another user's uid requires elevated access.");
2540
+ }
2541
+ result = requestedUid;
2542
+ _state.label = 4;
2543
+ case 4:
2544
+ return [
2545
+ 2,
2546
+ result
2547
+ ];
2548
+ }
2549
+ });
2550
+ })();
2551
+ }
2552
+ function parseModelRolesInput(args) {
2553
+ var modelType = args['modelType'];
2554
+ var keys = args['keys'];
2555
+ var uid = args['uid'];
2556
+ if (typeof modelType !== 'string' || modelType.length === 0) {
2557
+ throw new Error('model-roles: "modelType" is required and must be a non-empty string.');
2558
+ }
2559
+ if (!Array.isArray(keys) || keys.length === 0) {
2560
+ throw new Error('model-roles: "keys" is required and must be a non-empty array.');
2561
+ }
2562
+ if (keys.length > MCP_MODEL_ROLES_MAX_KEYS) {
2563
+ throw new Error("model-roles: at most ".concat(MCP_MODEL_ROLES_MAX_KEYS, " keys may be resolved per call (received ").concat(keys.length, ")."));
2564
+ }
2565
+ if (uid !== undefined && (typeof uid !== 'string' || uid.length === 0)) {
2566
+ throw new Error('model-roles: "uid" must be a non-empty string when provided.');
2567
+ }
2568
+ var normalizedKeys = keys.map(function(value, index) {
2569
+ if (typeof value !== 'string' || value.length === 0) {
2570
+ throw new Error("model-roles: keys[".concat(index, "] must be a non-empty string."));
2571
+ }
2572
+ return value;
2573
+ });
2574
+ return _object_spread$6({
2575
+ modelType: modelType,
2576
+ keys: normalizedKeys
2577
+ }, uid === undefined ? {} : {
2578
+ uid: uid
2579
+ });
2580
+ }
2581
+ function resolveKeys(keys, identity) {
2582
+ var isRoot = identity.type === 'root';
2583
+ var resolved = [];
2584
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
2585
+ try {
2586
+ for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
2587
+ var value = _step.value;
2588
+ if (value.includes('/')) {
2589
+ resolved.push(value);
2590
+ } else if (isRoot) {
2591
+ resolved.push("".concat(identity.collectionName, "/").concat(value));
2592
+ } else {
2593
+ throw new Error('model-roles: modelType "'.concat(identity.modelType, '" is a subcollection; bare ids are not allowed. Provide full keys (e.g. "parentPrefix/parentId/').concat(identity.collectionName, "/").concat(value, '").'));
2594
+ }
2595
+ }
2596
+ } catch (err) {
2597
+ _didIteratorError = true;
2598
+ _iteratorError = err;
2599
+ } finally{
2600
+ try {
2601
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
2602
+ _iterator.return();
2603
+ }
2604
+ } finally{
2605
+ if (_didIteratorError) {
2606
+ throw _iteratorError;
2607
+ }
2608
+ }
2609
+ }
2610
+ return resolved;
2611
+ }
2612
+ // MARK: Schemas
2613
+ var MODEL_ROLES_INPUT_SCHEMA = {
2614
+ type: 'object',
2615
+ required: [
2616
+ 'modelType',
2617
+ 'keys'
2618
+ ],
2619
+ properties: {
2620
+ modelType: {
2621
+ type: 'string',
2622
+ minLength: 1,
2623
+ description: 'Firestore model type to resolve roles on (e.g. "guestbook", "profile").'
2624
+ },
2625
+ keys: {
2626
+ type: 'array',
2627
+ minItems: 1,
2628
+ maxItems: MCP_MODEL_ROLES_MAX_KEYS,
2629
+ description: 'Full keys ("prefix/id") or bare ids (root models only).',
2630
+ items: {
2631
+ type: 'string',
2632
+ minLength: 1
2633
+ }
2634
+ },
2635
+ uid: {
2636
+ type: 'string',
2637
+ minLength: 1,
2638
+ description: 'Resolve roles as this user instead of the caller. Requires elevated access; passing your own uid is always allowed.'
2639
+ }
2640
+ },
2641
+ additionalProperties: false
2642
+ };
2643
+ var MODEL_ROLES_OUTPUT_SCHEMA = {
2644
+ type: 'object',
2645
+ required: [
2646
+ 'targeted',
2647
+ 'results',
2648
+ 'errors'
2649
+ ],
2650
+ properties: {
2651
+ uid: {
2652
+ type: 'string',
2653
+ description: 'The uid the roles were resolved for.'
2654
+ },
2655
+ targeted: {
2656
+ type: 'boolean',
2657
+ description: 'True when the roles were resolved for a user other than the caller.'
2658
+ },
2659
+ results: {
2660
+ type: 'array',
2661
+ description: 'Per-key resolved permission state.',
2662
+ items: {
2663
+ type: 'object',
2664
+ required: [
2665
+ 'key',
2666
+ 'exists',
2667
+ 'fullAccess',
2668
+ 'roles'
2669
+ ],
2670
+ properties: {
2671
+ key: {
2672
+ type: 'string'
2673
+ },
2674
+ exists: {
2675
+ type: 'boolean',
2676
+ description: 'Whether the document exists. Roles are only computed for documents that exist.'
2677
+ },
2678
+ fullAccess: {
2679
+ type: 'boolean',
2680
+ description: 'True when the full-access marker was granted; every role is implicitly held and "roles" is empty.'
2681
+ },
2682
+ roles: {
2683
+ type: 'array',
2684
+ items: {
2685
+ type: 'string'
2686
+ },
2687
+ description: 'Granted role names, sorted.'
2688
+ }
2689
+ }
2690
+ }
2691
+ },
2692
+ errors: {
2693
+ type: 'array',
2694
+ description: 'Per-key failures. A missing document is NOT an error — it appears in results with exists:false.',
2695
+ items: {
2696
+ type: 'object',
2697
+ required: [
2698
+ 'key',
2699
+ 'message'
2700
+ ],
2701
+ properties: {
2702
+ key: {
2703
+ type: 'string'
2704
+ },
2705
+ message: {
2706
+ type: 'string'
2707
+ },
2708
+ code: {
2709
+ type: 'string'
2710
+ }
2711
+ }
2712
+ }
2713
+ }
2714
+ }
2715
+ };
2716
+
2208
2717
  function _array_like_to_array$7(arr, len) {
2209
2718
  if (len == null || len > arr.length) len = arr.length;
2210
2719
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
@@ -6060,13 +6569,14 @@ var McpServerFactoryService_1;
6060
6569
  * per request and has no session concept at all — and it is equally what the SDK
6061
6570
  * recommends for stateless 2025-era serving, so one factory backs both eras.
6062
6571
  */ exports.McpServerFactoryService = McpServerFactoryService_1 = /*#__PURE__*/ function() {
6063
- function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService, storageService) {
6572
+ function McpServerFactoryService(mcpConfig, dispatchService, modelApiGetService, roleReader, analyticsService, storageService, modelRolesTargetUidPredicate) {
6064
6573
  _class_call_check$3(this, McpServerFactoryService);
6065
6574
  _define_property$3(this, "mcpConfig", void 0);
6066
6575
  _define_property$3(this, "dispatchService", void 0);
6067
6576
  _define_property$3(this, "modelApiGetService", void 0);
6068
6577
  _define_property$3(this, "roleReader", void 0);
6069
6578
  _define_property$3(this, "storageService", void 0);
6579
+ _define_property$3(this, "modelRolesTargetUidPredicate", void 0);
6070
6580
  _define_property$3(this, "_logger", new common.Logger(McpServerFactoryService_1.name));
6071
6581
  _define_property$3(this, "_cachedTools", void 0);
6072
6582
  _define_property$3(this, "_cachedStaticTools", void 0);
@@ -6086,6 +6596,7 @@ var McpServerFactoryService_1;
6086
6596
  this.modelApiGetService = modelApiGetService;
6087
6597
  this.roleReader = roleReader;
6088
6598
  this.storageService = storageService;
6599
+ this.modelRolesTargetUidPredicate = modelRolesTargetUidPredicate;
6089
6600
  this._analyticsService = analyticsService !== null && analyticsService !== void 0 ? analyticsService : noopMcpAnalyticsService();
6090
6601
  }
6091
6602
  _create_class$3(McpServerFactoryService, [
@@ -6356,6 +6867,14 @@ var McpServerFactoryService_1;
6356
6867
  resolveIdentity: function resolveIdentity(modelType, auth) {
6357
6868
  return getService.getModelIdentity(modelType, auth);
6358
6869
  }
6870
+ }), createModelRolesTool({
6871
+ readRoleMaps: function readRoleMaps(params) {
6872
+ return getService.readRoleMaps(params);
6873
+ },
6874
+ resolveIdentity: function resolveIdentity(modelType, auth) {
6875
+ return getService.getModelIdentity(modelType, auth);
6876
+ },
6877
+ canTargetOtherUids: this.modelRolesTargetUidPredicate
6359
6878
  }));
6360
6879
  // `url-models` reuses the model-get read/identity path, so it is only offered when the get
6361
6880
  // service is wired AND a route manifest with at least one state was loaded.
@@ -7109,7 +7628,9 @@ exports.McpServerFactoryService = McpServerFactoryService_1 = __decorate([
7109
7628
  __param(4, common.Optional()),
7110
7629
  __param(4, common.Inject(MCP_ANALYTICS_SERVICE)),
7111
7630
  __param(5, common.Optional()),
7112
- __param(5, common.Inject(firebaseServer.FirebaseServerStorageService))
7631
+ __param(5, common.Inject(firebaseServer.FirebaseServerStorageService)),
7632
+ __param(6, common.Optional()),
7633
+ __param(6, common.Inject(MCP_MODEL_ROLES_TARGET_UID_PREDICATE))
7113
7634
  ], exports.McpServerFactoryService);
7114
7635
 
7115
7636
  function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
@@ -8195,6 +8716,8 @@ exports.MCP_AUTH_ROLE_READER = MCP_AUTH_ROLE_READER;
8195
8716
  exports.MCP_CALL_TYPE_ABBREVIATIONS = MCP_CALL_TYPE_ABBREVIATIONS;
8196
8717
  exports.MCP_MANIFEST_VERSION = MCP_MANIFEST_VERSION;
8197
8718
  exports.MCP_MODEL_GET_BATCH_SIZE = MCP_MODEL_GET_BATCH_SIZE;
8719
+ exports.MCP_MODEL_ROLES_MAX_KEYS = MCP_MODEL_ROLES_MAX_KEYS;
8720
+ exports.MCP_MODEL_ROLES_TARGET_UID_PREDICATE = MCP_MODEL_ROLES_TARGET_UID_PREDICATE;
8198
8721
  exports.MCP_TOOL_NAME_MAX_LENGTH = MCP_TOOL_NAME_MAX_LENGTH;
8199
8722
  exports.MCP_TOOL_NAME_WARN_LENGTH = MCP_TOOL_NAME_WARN_LENGTH;
8200
8723
  exports.MCP_WRITE_TOOL_DESCRIPTION_PREFIX = MCP_WRITE_TOOL_DESCRIPTION_PREFIX;
@@ -8209,6 +8732,9 @@ exports.MODEL_INFO_DISPATCH_MODEL_TYPE = MODEL_INFO_DISPATCH_MODEL_TYPE;
8209
8732
  exports.MODEL_INFO_GROUPS_HINT = MODEL_INFO_GROUPS_HINT;
8210
8733
  exports.MODEL_INFO_TOOL_NAME = MODEL_INFO_TOOL_NAME;
8211
8734
  exports.MODEL_INFO_UNGROUPED_LABEL = MODEL_INFO_UNGROUPED_LABEL;
8735
+ exports.MODEL_ROLES_DISPATCH_CALL = MODEL_ROLES_DISPATCH_CALL;
8736
+ exports.MODEL_ROLES_DISPATCH_MODEL_TYPE = MODEL_ROLES_DISPATCH_MODEL_TYPE;
8737
+ exports.MODEL_ROLES_TOOL_NAME = MODEL_ROLES_TOOL_NAME;
8212
8738
  exports.McpAnalyticsService = McpAnalyticsService;
8213
8739
  exports.McpModuleConfig = McpModuleConfig;
8214
8740
  exports.ROUTE_MANIFEST_VERSION = ROUTE_MANIFEST_VERSION;
@@ -8231,6 +8757,7 @@ exports.createEnumInfoTool = createEnumInfoTool;
8231
8757
  exports.createModelDecodeTool = createModelDecodeTool;
8232
8758
  exports.createModelGetTool = createModelGetTool;
8233
8759
  exports.createModelInfoTool = createModelInfoTool;
8760
+ exports.createModelRolesTool = createModelRolesTool;
8234
8761
  exports.createUrlModelsTool = createUrlModelsTool;
8235
8762
  exports.decodeFirestoreModelKey = decodeFirestoreModelKey;
8236
8763
  exports.extractMcpReasonFromArgs = extractMcpReasonFromArgs;