@dereekb/firebase-server 13.22.0 → 13.23.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,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/mailgun",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.22.0",
6
- "@dereekb/firebase": "13.22.0",
7
- "@dereekb/firebase-server": "13.22.0",
8
- "@dereekb/date": "13.22.0",
9
- "@dereekb/nestjs": "13.22.0",
10
- "@dereekb/model": "13.22.0",
11
- "@dereekb/rxjs": "13.22.0",
12
- "@dereekb/util": "13.22.0"
5
+ "@dereekb/analytics": "13.23.0",
6
+ "@dereekb/firebase": "13.23.0",
7
+ "@dereekb/firebase-server": "13.23.0",
8
+ "@dereekb/date": "13.23.0",
9
+ "@dereekb/nestjs": "13.23.0",
10
+ "@dereekb/model": "13.23.0",
11
+ "@dereekb/rxjs": "13.23.0",
12
+ "@dereekb/util": "13.23.0"
13
13
  },
14
14
  "exports": {
15
15
  "./package.json": "./package.json",
package/mcp/index.cjs.js CHANGED
@@ -4176,6 +4176,31 @@ function _ts_generator$4(thisArg, body) {
4176
4176
  * URL value is a whole two-way-flat FirestoreModelKey. Mirror of the build-time
4177
4177
  * `FLAT_KEY_TOKEN_RE` in `@dereekb/dbx-cli`'s route-model-tag parser.
4178
4178
  */ var FLAT_KEY_TEMPLATE_RE = RegExp("^\\{flatKey:([a-zA-Z_][a-zA-Z0-9_]*)\\}$", "u");
4179
+ /**
4180
+ * Reads the impersonation uid from a URL's `?imp=<uid>` query parameter, if present.
4181
+ *
4182
+ * Impersonation ("view as another user") is conveyed by the {@link IMPERSONATION_URL_QUERY_PARAM} query
4183
+ * param; when set, it overrides the uid used to fill `{authUid}` placeholders so a decoded URL reports the
4184
+ * models the impersonated user's page renders. Handles both a full URL and a bare path (mirroring
4185
+ * {@link parseUrlModelsPathname}, which discards the query when matching). Returns the trimmed non-empty
4186
+ * uid, or `undefined` when absent.
4187
+ *
4188
+ * @param url - A full URL or bare path, optionally carrying `?imp=<uid>`.
4189
+ * @returns The impersonated uid, or `undefined`.
4190
+ */ function readUrlModelsImpersonationUid(url) {
4191
+ var _get;
4192
+ var trimmed = url.trim();
4193
+ var search;
4194
+ if (RegExp("^[a-z][a-z0-9+.-]*:\\/\\/", "iu").test(trimmed)) {
4195
+ search = new URL(trimmed).search;
4196
+ } else {
4197
+ var hashStripped = trimmed.split('#', 1)[0];
4198
+ var queryIndex = hashStripped.indexOf('?');
4199
+ search = queryIndex >= 0 ? hashStripped.slice(queryIndex) : '';
4200
+ }
4201
+ var value = (_get = new URLSearchParams(search).get(util.IMPERSONATION_URL_QUERY_PARAM)) === null || _get === void 0 ? void 0 : _get.trim();
4202
+ return value ? value : undefined;
4203
+ }
4179
4204
  // MARK: Factory
4180
4205
  /**
4181
4206
  * Builds the built-in `url-models` MCP tool definition.
@@ -4196,7 +4221,7 @@ function _ts_generator$4(thisArg, body) {
4196
4221
  return urlModelsToolHandler(args, ctx, deps);
4197
4222
  };
4198
4223
  var name = URL_MODELS_TOOL_NAME;
4199
- var description = 'Decode an app URL (or path) into the Firestore models its page renders. Pass a URL like `https://app.example.co/worker/abc/timesheets/list`; the tool matches it against the build-time route manifest and returns each model type plus the concrete key (route params + `{authUid}` substituted). Use `models` to filter to specific types, `keysOnly` for just the resolved keys, or `load: true` to fetch the documents via the same permission-checked path as `model-get` (cannot combine `load` with `keysOnly`).';
4224
+ var description = 'Decode an app URL (or path) into the Firestore models its page renders. Pass a URL like `https://app.example.co/worker/abc/timesheets/list`; the tool matches it against the build-time route manifest and returns each model type plus the concrete key (route params + `{authUid}` substituted). A `?imp=<uid>` query param resolves `{authUid}` to that user (impersonation preview). Use `models` to filter to specific types, `keysOnly` for just the resolved keys, or `load: true` to fetch the documents via the same permission-checked path as `model-get` (cannot combine `load` with `keysOnly`).';
4200
4225
  return buildStaticToolDefinition({
4201
4226
  name: name,
4202
4227
  description: description,
@@ -4372,15 +4397,16 @@ function stateSummary(state) {
4372
4397
  }
4373
4398
  function buildMatchedPayload(args) {
4374
4399
  return _async_to_generator$4(function() {
4375
- var _input_currentUserUid, _ctx_auth, match, input, ctx, deps, uid, filtered, resolved, loaded, _tmp;
4400
+ var _ref, _readUrlModelsImpersonationUid, _ctx_auth, match, input, ctx, deps, uid, filtered, resolved, loaded, _tmp;
4376
4401
  return _ts_generator$4(this, function(_state) {
4377
4402
  switch(_state.label){
4378
4403
  case 0:
4379
4404
  match = args.match, input = args.input, ctx = args.ctx, deps = args.deps;
4380
- // `currentUserUid` (when supplied) overrides the uid used to fill `{authUid}` placeholders so a
4381
- // caller can preview another user's page-models. The document-load path still uses `ctx.auth`, so
4382
- // this is a key-substitution preview only — no privilege escalation on the actual reads.
4383
- uid = (_input_currentUserUid = input.currentUserUid) !== null && _input_currentUserUid !== void 0 ? _input_currentUserUid : (_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.uid;
4405
+ // A `?imp=<uid>` query param on the URL (impersonation), then an explicit `currentUserUid`, override the
4406
+ // uid used to fill `{authUid}` placeholders so a caller can preview another user's page-models. The
4407
+ // document-load path still uses `ctx.auth`, so this is a key-substitution preview only — no privilege
4408
+ // escalation on the actual reads.
4409
+ uid = (_ref = (_readUrlModelsImpersonationUid = readUrlModelsImpersonationUid(input.url)) !== null && _readUrlModelsImpersonationUid !== void 0 ? _readUrlModelsImpersonationUid : input.currentUserUid) !== null && _ref !== void 0 ? _ref : (_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.uid;
4384
4410
  filtered = input.models === undefined ? match.state.models : match.state.models.filter(function(m) {
4385
4411
  var _input_models;
4386
4412
  return (_input_models = input.models) === null || _input_models === void 0 ? void 0 : _input_models.includes(m.modelType);
@@ -4786,7 +4812,7 @@ var URL_MODELS_INPUT_SCHEMA = {
4786
4812
  url: {
4787
4813
  type: 'string',
4788
4814
  minLength: 1,
4789
- description: 'Full URL or pathname, e.g. "https://app.example.co/worker/abc/timesheets/list".'
4815
+ description: 'Full URL or pathname, e.g. "https://app.example.co/worker/abc/timesheets/list". A `?imp=<uid>` query resolves `{authUid}` to that user (impersonation preview).'
4790
4816
  },
4791
4817
  models: {
4792
4818
  type: 'array',
@@ -4806,7 +4832,7 @@ var URL_MODELS_INPUT_SCHEMA = {
4806
4832
  currentUserUid: {
4807
4833
  type: 'string',
4808
4834
  minLength: 1,
4809
- description: "Override the uid used to fill `{authUid}` placeholders when resolving model keys (defaults to the authenticated caller). Use to preview the models another user would see on a page. `load` still reads via the calling user's permissions."
4835
+ description: "Override the uid used to fill `{authUid}` placeholders when resolving model keys (defaults to the authenticated caller). Use to preview the models another user would see on a page. A `?imp=<uid>` query on the url takes precedence over this. `load` still reads via the calling user's permissions."
4810
4836
  }
4811
4837
  },
4812
4838
  additionalProperties: false
@@ -7899,6 +7925,7 @@ exports.mcpModuleMetadata = mcpModuleMetadata;
7899
7925
  exports.mcpSchemaDeclaresProperty = mcpSchemaDeclaresProperty;
7900
7926
  exports.noopMcpAnalyticsService = noopMcpAnalyticsService;
7901
7927
  exports.parseUrlModelsPathname = parseUrlModelsPathname;
7928
+ exports.readUrlModelsImpersonationUid = readUrlModelsImpersonationUid;
7902
7929
  exports.resolveEffectiveReadOnly = resolveEffectiveReadOnly;
7903
7930
  exports.resolveEnumInfoOutput = resolveEnumInfoOutput;
7904
7931
  exports.resolveMcpReasonParameterConfig = resolveMcpReasonParameterConfig;
package/mcp/index.esm.js CHANGED
@@ -3,7 +3,7 @@ import { existsSync, readFileSync } from 'node:fs';
3
3
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
5
  import { getOidcScopesFromRequest } from '@dereekb/firebase-server/oidc';
6
- import { makeValuesGroupMap, performAsyncTasks, authRolesSetHasRoles } from '@dereekb/util';
6
+ import { makeValuesGroupMap, IMPERSONATION_URL_QUERY_PARAM, performAsyncTasks, authRolesSetHasRoles } from '@dereekb/util';
7
7
  import { ModelApiCallModelDispatchService, ModelApiGetService, FirebaseServerStorageService, FirebaseServerEnvService, FirebaseServerAnalyticsService } from '@dereekb/firebase-server';
8
8
  import { inspect } from 'node:util';
9
9
  import { arktypeToJsonSchemaForExport } from '@dereekb/model';
@@ -4174,6 +4174,31 @@ function _ts_generator$4(thisArg, body) {
4174
4174
  * URL value is a whole two-way-flat FirestoreModelKey. Mirror of the build-time
4175
4175
  * `FLAT_KEY_TOKEN_RE` in `@dereekb/dbx-cli`'s route-model-tag parser.
4176
4176
  */ var FLAT_KEY_TEMPLATE_RE = RegExp("^\\{flatKey:([a-zA-Z_][a-zA-Z0-9_]*)\\}$", "u");
4177
+ /**
4178
+ * Reads the impersonation uid from a URL's `?imp=<uid>` query parameter, if present.
4179
+ *
4180
+ * Impersonation ("view as another user") is conveyed by the {@link IMPERSONATION_URL_QUERY_PARAM} query
4181
+ * param; when set, it overrides the uid used to fill `{authUid}` placeholders so a decoded URL reports the
4182
+ * models the impersonated user's page renders. Handles both a full URL and a bare path (mirroring
4183
+ * {@link parseUrlModelsPathname}, which discards the query when matching). Returns the trimmed non-empty
4184
+ * uid, or `undefined` when absent.
4185
+ *
4186
+ * @param url - A full URL or bare path, optionally carrying `?imp=<uid>`.
4187
+ * @returns The impersonated uid, or `undefined`.
4188
+ */ function readUrlModelsImpersonationUid(url) {
4189
+ var _get;
4190
+ var trimmed = url.trim();
4191
+ var search;
4192
+ if (RegExp("^[a-z][a-z0-9+.-]*:\\/\\/", "iu").test(trimmed)) {
4193
+ search = new URL(trimmed).search;
4194
+ } else {
4195
+ var hashStripped = trimmed.split('#', 1)[0];
4196
+ var queryIndex = hashStripped.indexOf('?');
4197
+ search = queryIndex >= 0 ? hashStripped.slice(queryIndex) : '';
4198
+ }
4199
+ var value = (_get = new URLSearchParams(search).get(IMPERSONATION_URL_QUERY_PARAM)) === null || _get === void 0 ? void 0 : _get.trim();
4200
+ return value ? value : undefined;
4201
+ }
4177
4202
  // MARK: Factory
4178
4203
  /**
4179
4204
  * Builds the built-in `url-models` MCP tool definition.
@@ -4194,7 +4219,7 @@ function _ts_generator$4(thisArg, body) {
4194
4219
  return urlModelsToolHandler(args, ctx, deps);
4195
4220
  };
4196
4221
  var name = URL_MODELS_TOOL_NAME;
4197
- var description = 'Decode an app URL (or path) into the Firestore models its page renders. Pass a URL like `https://app.example.co/worker/abc/timesheets/list`; the tool matches it against the build-time route manifest and returns each model type plus the concrete key (route params + `{authUid}` substituted). Use `models` to filter to specific types, `keysOnly` for just the resolved keys, or `load: true` to fetch the documents via the same permission-checked path as `model-get` (cannot combine `load` with `keysOnly`).';
4222
+ var description = 'Decode an app URL (or path) into the Firestore models its page renders. Pass a URL like `https://app.example.co/worker/abc/timesheets/list`; the tool matches it against the build-time route manifest and returns each model type plus the concrete key (route params + `{authUid}` substituted). A `?imp=<uid>` query param resolves `{authUid}` to that user (impersonation preview). Use `models` to filter to specific types, `keysOnly` for just the resolved keys, or `load: true` to fetch the documents via the same permission-checked path as `model-get` (cannot combine `load` with `keysOnly`).';
4198
4223
  return buildStaticToolDefinition({
4199
4224
  name: name,
4200
4225
  description: description,
@@ -4370,15 +4395,16 @@ function stateSummary(state) {
4370
4395
  }
4371
4396
  function buildMatchedPayload(args) {
4372
4397
  return _async_to_generator$4(function() {
4373
- var _input_currentUserUid, _ctx_auth, match, input, ctx, deps, uid, filtered, resolved, loaded, _tmp;
4398
+ var _ref, _readUrlModelsImpersonationUid, _ctx_auth, match, input, ctx, deps, uid, filtered, resolved, loaded, _tmp;
4374
4399
  return _ts_generator$4(this, function(_state) {
4375
4400
  switch(_state.label){
4376
4401
  case 0:
4377
4402
  match = args.match, input = args.input, ctx = args.ctx, deps = args.deps;
4378
- // `currentUserUid` (when supplied) overrides the uid used to fill `{authUid}` placeholders so a
4379
- // caller can preview another user's page-models. The document-load path still uses `ctx.auth`, so
4380
- // this is a key-substitution preview only — no privilege escalation on the actual reads.
4381
- uid = (_input_currentUserUid = input.currentUserUid) !== null && _input_currentUserUid !== void 0 ? _input_currentUserUid : (_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.uid;
4403
+ // A `?imp=<uid>` query param on the URL (impersonation), then an explicit `currentUserUid`, override the
4404
+ // uid used to fill `{authUid}` placeholders so a caller can preview another user's page-models. The
4405
+ // document-load path still uses `ctx.auth`, so this is a key-substitution preview only — no privilege
4406
+ // escalation on the actual reads.
4407
+ uid = (_ref = (_readUrlModelsImpersonationUid = readUrlModelsImpersonationUid(input.url)) !== null && _readUrlModelsImpersonationUid !== void 0 ? _readUrlModelsImpersonationUid : input.currentUserUid) !== null && _ref !== void 0 ? _ref : (_ctx_auth = ctx.auth) === null || _ctx_auth === void 0 ? void 0 : _ctx_auth.uid;
4382
4408
  filtered = input.models === undefined ? match.state.models : match.state.models.filter(function(m) {
4383
4409
  var _input_models;
4384
4410
  return (_input_models = input.models) === null || _input_models === void 0 ? void 0 : _input_models.includes(m.modelType);
@@ -4784,7 +4810,7 @@ var URL_MODELS_INPUT_SCHEMA = {
4784
4810
  url: {
4785
4811
  type: 'string',
4786
4812
  minLength: 1,
4787
- description: 'Full URL or pathname, e.g. "https://app.example.co/worker/abc/timesheets/list".'
4813
+ description: 'Full URL or pathname, e.g. "https://app.example.co/worker/abc/timesheets/list". A `?imp=<uid>` query resolves `{authUid}` to that user (impersonation preview).'
4788
4814
  },
4789
4815
  models: {
4790
4816
  type: 'array',
@@ -4804,7 +4830,7 @@ var URL_MODELS_INPUT_SCHEMA = {
4804
4830
  currentUserUid: {
4805
4831
  type: 'string',
4806
4832
  minLength: 1,
4807
- description: "Override the uid used to fill `{authUid}` placeholders when resolving model keys (defaults to the authenticated caller). Use to preview the models another user would see on a page. `load` still reads via the calling user's permissions."
4833
+ description: "Override the uid used to fill `{authUid}` placeholders when resolving model keys (defaults to the authenticated caller). Use to preview the models another user would see on a page. A `?imp=<uid>` query on the url takes precedence over this. `load` still reads via the calling user's permissions."
4808
4834
  }
4809
4835
  },
4810
4836
  additionalProperties: false
@@ -7819,4 +7845,4 @@ function _unsupported_iterable_to_array(o, minLen) {
7819
7845
  };
7820
7846
  }
7821
7847
 
7822
- export { BATCH_EXECUTE_DISPATCH_CALL, BATCH_EXECUTE_DISPATCH_MODEL_TYPE, BATCH_EXECUTE_TOOL_NAME, DEFAULT_BATCH_EXECUTE_MAX_PARALLEL, DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, DEFAULT_MCP_ANALYTICS_EVENT_NAME, DEFAULT_MCP_PATH, DEFAULT_MCP_REASON_PARAMETER_DESCRIPTION, DEFAULT_MCP_REASON_PARAMETER_MAX_LENGTH, DEFAULT_MCP_REASON_PARAMETER_NAME, DEFAULT_MCP_REASON_PARAMETER_REQUIRED, DEFAULT_MCP_SERVER_INSTRUCTIONS, DEFAULT_MCP_SERVER_NAME, DEFAULT_SPECIFIER_KEY, DEFAULT_VOID_MCP_SUCCESS_VALUE, ENUM_INFO_DISPATCH_CALL, ENUM_INFO_DISPATCH_MODEL_TYPE, ENUM_INFO_TOOL_NAME, ENUM_TABLE_SCHEMA, FIREBASE_SERVER_MCP_ANALYTICS_CONFIG, FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, FirebaseServerMcpAnalyticsService, MAX_BATCH_EXECUTE_FILE_BYTES, MAX_BATCH_EXECUTE_OPERATIONS, MCP_ANALYTICS_SERVICE, MCP_AUTH_ROLE_READER, MCP_CALL_TYPE_ABBREVIATIONS, MCP_MANIFEST_VERSION, MCP_MODEL_GET_BATCH_SIZE, MCP_TOOL_NAME_MAX_LENGTH, MCP_TOOL_NAME_WARN_LENGTH, MCP_WRITE_TOOL_DESCRIPTION_PREFIX, MODEL_DECODE_DISPATCH_CALL, MODEL_DECODE_DISPATCH_MODEL_TYPE, MODEL_DECODE_TOOL_NAME, MODEL_GET_DISPATCH_CALL, MODEL_GET_DISPATCH_MODEL_TYPE, MODEL_GET_TOOL_NAME, MODEL_INFO_DISPATCH_CALL, MODEL_INFO_DISPATCH_MODEL_TYPE, MODEL_INFO_GROUPS_HINT, MODEL_INFO_TOOL_NAME, MODEL_INFO_UNGROUPED_LABEL, McpAnalyticsService, McpController, McpModuleConfig, McpServerFactoryService, McpWellKnownController, ROUTE_MANIFEST_VERSION, URL_MODELS_DISPATCH_CALL, URL_MODELS_DISPATCH_MODEL_TYPE, URL_MODELS_TOOL_NAME, abbreviateMcpCallType, appMcpAnalyticsModuleMetadata, applyMcpReasonParameterToSchema, applyWriteMarker, batchOperationCoordKey, buildDefaultMcpToolDescription, buildDisambiguatedMcpToolName, buildMcpToolName, buildStaticToolDefinition, buildStaticWireEntry, classifyVisibility, createBatchExecuteTool, createEnumInfoTool, createModelDecodeTool, createModelGetTool, createModelInfoTool, createUrlModelsTool, decodeFirestoreModelKey, extractMcpReasonFromArgs, findModelEntry, formatMcpToolErrorResponse, formatMcpToolResponse, generateMcpToolDefinitions, handleStreamableHttpMcpRequest, matchRouteManifestUrl, mcpManifestKey, mcpModuleMetadata, mcpSchemaDeclaresProperty, noopMcpAnalyticsService, parseUrlModelsPathname, resolveEffectiveReadOnly, resolveEnumInfoOutput, resolveMcpReasonParameterConfig, resolveMcpToolAnnotations, resolveRequiredScope, validateMcpToolName };
7848
+ export { BATCH_EXECUTE_DISPATCH_CALL, BATCH_EXECUTE_DISPATCH_MODEL_TYPE, BATCH_EXECUTE_TOOL_NAME, DEFAULT_BATCH_EXECUTE_MAX_PARALLEL, DEFAULT_JSON_SCHEMA_GENERATION_OPTIONS, DEFAULT_MCP_ANALYTICS_EVENT_NAME, DEFAULT_MCP_PATH, DEFAULT_MCP_REASON_PARAMETER_DESCRIPTION, DEFAULT_MCP_REASON_PARAMETER_MAX_LENGTH, DEFAULT_MCP_REASON_PARAMETER_NAME, DEFAULT_MCP_REASON_PARAMETER_REQUIRED, DEFAULT_MCP_SERVER_INSTRUCTIONS, DEFAULT_MCP_SERVER_NAME, DEFAULT_SPECIFIER_KEY, DEFAULT_VOID_MCP_SUCCESS_VALUE, ENUM_INFO_DISPATCH_CALL, ENUM_INFO_DISPATCH_MODEL_TYPE, ENUM_INFO_TOOL_NAME, ENUM_TABLE_SCHEMA, FIREBASE_SERVER_MCP_ANALYTICS_CONFIG, FIREBASE_SERVER_MCP_ROUTES_FOR_GLOBAL_ROUTE_EXCLUDE, FirebaseServerMcpAnalyticsService, MAX_BATCH_EXECUTE_FILE_BYTES, MAX_BATCH_EXECUTE_OPERATIONS, MCP_ANALYTICS_SERVICE, MCP_AUTH_ROLE_READER, MCP_CALL_TYPE_ABBREVIATIONS, MCP_MANIFEST_VERSION, MCP_MODEL_GET_BATCH_SIZE, MCP_TOOL_NAME_MAX_LENGTH, MCP_TOOL_NAME_WARN_LENGTH, MCP_WRITE_TOOL_DESCRIPTION_PREFIX, MODEL_DECODE_DISPATCH_CALL, MODEL_DECODE_DISPATCH_MODEL_TYPE, MODEL_DECODE_TOOL_NAME, MODEL_GET_DISPATCH_CALL, MODEL_GET_DISPATCH_MODEL_TYPE, MODEL_GET_TOOL_NAME, MODEL_INFO_DISPATCH_CALL, MODEL_INFO_DISPATCH_MODEL_TYPE, MODEL_INFO_GROUPS_HINT, MODEL_INFO_TOOL_NAME, MODEL_INFO_UNGROUPED_LABEL, McpAnalyticsService, McpController, McpModuleConfig, McpServerFactoryService, McpWellKnownController, ROUTE_MANIFEST_VERSION, URL_MODELS_DISPATCH_CALL, URL_MODELS_DISPATCH_MODEL_TYPE, URL_MODELS_TOOL_NAME, abbreviateMcpCallType, appMcpAnalyticsModuleMetadata, applyMcpReasonParameterToSchema, applyWriteMarker, batchOperationCoordKey, buildDefaultMcpToolDescription, buildDisambiguatedMcpToolName, buildMcpToolName, buildStaticToolDefinition, buildStaticWireEntry, classifyVisibility, createBatchExecuteTool, createEnumInfoTool, createModelDecodeTool, createModelGetTool, createModelInfoTool, createUrlModelsTool, decodeFirestoreModelKey, extractMcpReasonFromArgs, findModelEntry, formatMcpToolErrorResponse, formatMcpToolResponse, generateMcpToolDefinitions, handleStreamableHttpMcpRequest, matchRouteManifestUrl, mcpManifestKey, mcpModuleMetadata, mcpSchemaDeclaresProperty, noopMcpAnalyticsService, parseUrlModelsPathname, readUrlModelsImpersonationUid, resolveEffectiveReadOnly, resolveEnumInfoOutput, resolveMcpReasonParameterConfig, resolveMcpToolAnnotations, resolveRequiredScope, validateMcpToolName };
package/mcp/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/mcp",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.22.0",
6
- "@dereekb/date": "13.22.0",
7
- "@dereekb/firebase": "13.22.0",
8
- "@dereekb/firebase-server": "13.22.0",
9
- "@dereekb/firebase-server/oidc": "13.22.0",
10
- "@dereekb/model": "13.22.0",
11
- "@dereekb/nestjs": "13.22.0",
12
- "@dereekb/rxjs": "13.22.0",
13
- "@dereekb/util": "13.22.0",
14
- "@dereekb/zoho": "13.22.0",
5
+ "@dereekb/analytics": "13.23.0",
6
+ "@dereekb/date": "13.23.0",
7
+ "@dereekb/firebase": "13.23.0",
8
+ "@dereekb/firebase-server": "13.23.0",
9
+ "@dereekb/firebase-server/oidc": "13.23.0",
10
+ "@dereekb/model": "13.23.0",
11
+ "@dereekb/nestjs": "13.23.0",
12
+ "@dereekb/rxjs": "13.23.0",
13
+ "@dereekb/util": "13.23.0",
14
+ "@dereekb/zoho": "13.23.0",
15
15
  "@modelcontextprotocol/sdk": "1.29.0",
16
16
  "@nestjs/common": "^11.1.19",
17
17
  "@nestjs/core": "^11.1.19",
@@ -1,3 +1,4 @@
1
+ import { type Maybe } from '@dereekb/util';
1
2
  import { type FirestoreModelKey } from '@dereekb/firebase';
2
3
  import { type ModelAccessMultiReadResult } from '@dereekb/firebase-server';
3
4
  import { type McpToolDefinition } from '../mcp.tool-generator';
@@ -16,6 +17,19 @@ export declare const URL_MODELS_DISPATCH_CALL = "url-models";
16
17
  * bound to a real model (the `url` is its input), so we use the literal "route".
17
18
  */
18
19
  export declare const URL_MODELS_DISPATCH_MODEL_TYPE = "route";
20
+ /**
21
+ * Reads the impersonation uid from a URL's `?imp=<uid>` query parameter, if present.
22
+ *
23
+ * Impersonation ("view as another user") is conveyed by the {@link IMPERSONATION_URL_QUERY_PARAM} query
24
+ * param; when set, it overrides the uid used to fill `{authUid}` placeholders so a decoded URL reports the
25
+ * models the impersonated user's page renders. Handles both a full URL and a bare path (mirroring
26
+ * {@link parseUrlModelsPathname}, which discards the query when matching). Returns the trimmed non-empty
27
+ * uid, or `undefined` when absent.
28
+ *
29
+ * @param url - A full URL or bare path, optionally carrying `?imp=<uid>`.
30
+ * @returns The impersonated uid, or `undefined`.
31
+ */
32
+ export declare function readUrlModelsImpersonationUid(url: string): Maybe<string>;
19
33
  /**
20
34
  * Why a model binding could not be resolved into a concrete key.
21
35
  */
@@ -78,8 +92,9 @@ export interface UrlModelsToolInput {
78
92
  /**
79
93
  * Overrides the uid used to fill `{authUid}` placeholders when resolving model
80
94
  * keys (defaults to the authenticated caller). Use to preview the models
81
- * another user would see on a page. Does not affect the document-load path —
82
- * `load` still reads via the calling user's permissions.
95
+ * another user would see on a page. A `?imp=<uid>` (impersonation) query param
96
+ * on the `url` takes precedence over this. Does not affect the document-load
97
+ * path — `load` still reads via the calling user's permissions.
83
98
  */
84
99
  readonly currentUserUid?: string;
85
100
  }
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/model",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.22.0",
6
- "@dereekb/date": "13.22.0",
7
- "@dereekb/firebase": "13.22.0",
8
- "@dereekb/firebase-server": "13.22.0",
9
- "@dereekb/model": "13.22.0",
10
- "@dereekb/nestjs": "13.22.0",
11
- "@dereekb/rxjs": "13.22.0",
12
- "@dereekb/util": "13.22.0",
5
+ "@dereekb/analytics": "13.23.0",
6
+ "@dereekb/date": "13.23.0",
7
+ "@dereekb/firebase": "13.23.0",
8
+ "@dereekb/firebase-server": "13.23.0",
9
+ "@dereekb/model": "13.23.0",
10
+ "@dereekb/nestjs": "13.23.0",
11
+ "@dereekb/rxjs": "13.23.0",
12
+ "@dereekb/util": "13.23.0",
13
13
  "@nestjs/common": "^11.1.19",
14
14
  "@nestjs/config": "^4.0.4",
15
15
  "archiver": "^7.0.1",
package/oidc/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/oidc",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.22.0",
6
- "@dereekb/date": "13.22.0",
7
- "@dereekb/firebase": "13.22.0",
8
- "@dereekb/firebase-server": "13.22.0",
9
- "@dereekb/model": "13.22.0",
10
- "@dereekb/nestjs": "13.22.0",
11
- "@dereekb/rxjs": "13.22.0",
12
- "@dereekb/util": "13.22.0",
13
- "@dereekb/zoho": "13.22.0",
5
+ "@dereekb/analytics": "13.23.0",
6
+ "@dereekb/date": "13.23.0",
7
+ "@dereekb/firebase": "13.23.0",
8
+ "@dereekb/firebase-server": "13.23.0",
9
+ "@dereekb/model": "13.23.0",
10
+ "@dereekb/nestjs": "13.23.0",
11
+ "@dereekb/rxjs": "13.23.0",
12
+ "@dereekb/util": "13.23.0",
13
+ "@dereekb/zoho": "13.23.0",
14
14
  "@nestjs/common": "^11.1.19",
15
15
  "@nestjs/config": "^4.0.4",
16
16
  "express": "^5.2.1",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "sideEffects": false,
5
5
  "exports": {
6
6
  "./test": {
@@ -57,15 +57,15 @@
57
57
  "types": "./src/index.d.ts",
58
58
  "peerDependencies": {
59
59
  "@cantoo/pdf-lib": "^2.6.5",
60
- "@dereekb/analytics": "13.22.0",
61
- "@dereekb/date": "13.22.0",
62
- "@dereekb/dbx-core": "13.22.0",
63
- "@dereekb/firebase": "13.22.0",
64
- "@dereekb/model": "13.22.0",
65
- "@dereekb/nestjs": "13.22.0",
66
- "@dereekb/rxjs": "13.22.0",
67
- "@dereekb/util": "13.22.0",
68
- "@dereekb/zoho": "13.22.0",
60
+ "@dereekb/analytics": "13.23.0",
61
+ "@dereekb/date": "13.23.0",
62
+ "@dereekb/dbx-core": "13.23.0",
63
+ "@dereekb/firebase": "13.23.0",
64
+ "@dereekb/model": "13.23.0",
65
+ "@dereekb/nestjs": "13.23.0",
66
+ "@dereekb/rxjs": "13.23.0",
67
+ "@dereekb/util": "13.23.0",
68
+ "@dereekb/zoho": "13.23.0",
69
69
  "@google-cloud/firestore": "^7.11.6",
70
70
  "@google-cloud/storage": "^7.19.0",
71
71
  "@modelcontextprotocol/sdk": "1.29.0",
package/test/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/test",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.22.0",
6
- "@dereekb/date": "13.22.0",
7
- "@dereekb/firebase": "13.22.0",
8
- "@dereekb/firebase-server": "13.22.0",
9
- "@dereekb/firebase-server/oidc": "13.22.0",
10
- "@dereekb/model": "13.22.0",
11
- "@dereekb/nestjs": "13.22.0",
12
- "@dereekb/rxjs": "13.22.0",
13
- "@dereekb/util": "13.22.0",
5
+ "@dereekb/analytics": "13.23.0",
6
+ "@dereekb/date": "13.23.0",
7
+ "@dereekb/firebase": "13.23.0",
8
+ "@dereekb/firebase-server": "13.23.0",
9
+ "@dereekb/firebase-server/oidc": "13.23.0",
10
+ "@dereekb/model": "13.23.0",
11
+ "@dereekb/nestjs": "13.23.0",
12
+ "@dereekb/rxjs": "13.23.0",
13
+ "@dereekb/util": "13.23.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.22.0"
26
+ "@dereekb/nestjs": "13.23.0"
27
27
  },
28
28
  "exports": {
29
29
  "./package.json": "./package.json",
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@dereekb/firebase-server/twilio",
3
- "version": "13.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/date": "13.22.0",
6
- "@dereekb/firebase": "13.22.0",
7
- "@dereekb/firebase-server": "13.22.0",
8
- "@dereekb/model": "13.22.0",
9
- "@dereekb/nestjs": "13.22.0",
10
- "@dereekb/rxjs": "13.22.0",
11
- "@dereekb/util": "13.22.0"
5
+ "@dereekb/date": "13.23.0",
6
+ "@dereekb/firebase": "13.23.0",
7
+ "@dereekb/firebase-server": "13.23.0",
8
+ "@dereekb/model": "13.23.0",
9
+ "@dereekb/nestjs": "13.23.0",
10
+ "@dereekb/rxjs": "13.23.0",
11
+ "@dereekb/util": "13.23.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.22.0",
3
+ "version": "13.23.0",
4
4
  "peerDependencies": {
5
- "@dereekb/analytics": "13.22.0",
6
- "@dereekb/date": "13.22.0",
7
- "@dereekb/model": "13.22.0",
8
- "@dereekb/nestjs": "13.22.0",
9
- "@dereekb/rxjs": "13.22.0",
10
- "@dereekb/firebase": "13.22.0",
11
- "@dereekb/util": "13.22.0",
12
- "@dereekb/zoho": "13.22.0"
5
+ "@dereekb/analytics": "13.23.0",
6
+ "@dereekb/date": "13.23.0",
7
+ "@dereekb/model": "13.23.0",
8
+ "@dereekb/nestjs": "13.23.0",
9
+ "@dereekb/rxjs": "13.23.0",
10
+ "@dereekb/firebase": "13.23.0",
11
+ "@dereekb/util": "13.23.0",
12
+ "@dereekb/zoho": "13.23.0"
13
13
  },
14
14
  "exports": {
15
15
  "./package.json": "./package.json",