@dereekb/firebase-server 14.5.1 → 14.6.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/calcom/package.json +10 -10
- package/discord/package.json +10 -10
- package/mailgun/package.json +9 -9
- package/mcp/index.esm.js +1537 -1329
- package/mcp/package.json +12 -12
- package/mcp/src/lib/mcp.config.d.ts +12 -0
- package/mcp/src/lib/service/mcp.manifest.d.ts +49 -0
- package/mcp/src/lib/service/tools/mcp.tool.cli-token.d.ts +4 -0
- package/mcp/src/lib/service/tools/mcp.tool.model-decode.d.ts +52 -6
- package/mcp/src/lib/service/tools/mcp.tool.model-get.d.ts +10 -0
- package/model/package.json +9 -9
- package/oidc/index.esm.js +7 -3
- package/oidc/package.json +11 -11
- package/oidc/src/lib/controller/oidc.cli-token.config.d.ts +12 -0
- package/package.json +13 -13
- package/test/package.json +12 -12
- package/twilio/package.json +8 -8
- package/zoho/package.json +10 -10
package/mcp/index.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Injectable, Inject, Optional, Logger, Post, Req, Res, Get, Delete, Controller, HttpStatus } from '@nestjs/common';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { McpServer, isLegacyRequest, isJsonContentType, createMcpHandler } from '@modelcontextprotocol/server';
|
|
4
|
-
import { callModelOidcScopeForCallType, resolveEffectiveOidcScopeTerms,
|
|
4
|
+
import { callModelOidcScopeForCallType, resolveEffectiveOidcScopeTerms, twoWayFlatFirestoreModelKey, flatFirestoreModelKey, inferKeyFromTwoWayFlatFirestoreModelKey, CLI_TOKEN_OIDC_SCOPE, oidcScopeTermsSatisfied } from '@dereekb/firebase';
|
|
5
5
|
import { getOidcScopesFromRequest, OidcProviderConfigService } from '@dereekb/firebase-server/oidc';
|
|
6
6
|
import { makeValuesGroupMap, AUTH_ADMIN_ROLE, IMPERSONATION_URL_QUERY_PARAM, performAsyncTasks, authRolesSetHasRoles } from '@dereekb/util';
|
|
7
7
|
import { requestClientIp, ModelApiCallModelDispatchService, ModelApiGetService, FirebaseServerStorageService, FirebaseServerEnvService, FirebaseServerAnalyticsService } from '@dereekb/firebase-server';
|
|
@@ -252,7 +252,7 @@ function _object_spread$9(target) {
|
|
|
252
252
|
}
|
|
253
253
|
return target;
|
|
254
254
|
}
|
|
255
|
-
function ownKeys$
|
|
255
|
+
function ownKeys$4(object, enumerableOnly) {
|
|
256
256
|
var keys = Object.keys(object);
|
|
257
257
|
if (Object.getOwnPropertySymbols) {
|
|
258
258
|
var symbols = Object.getOwnPropertySymbols(object);
|
|
@@ -260,11 +260,11 @@ function ownKeys$3(object, enumerableOnly) {
|
|
|
260
260
|
}
|
|
261
261
|
return keys;
|
|
262
262
|
}
|
|
263
|
-
function _object_spread_props$
|
|
263
|
+
function _object_spread_props$4(target, source) {
|
|
264
264
|
source = source != null ? source : {};
|
|
265
265
|
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
266
266
|
else {
|
|
267
|
-
ownKeys$
|
|
267
|
+
ownKeys$4(Object(source)).forEach(function(key) {
|
|
268
268
|
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
269
269
|
});
|
|
270
270
|
}
|
|
@@ -356,9 +356,9 @@ function _unsupported_iterable_to_array$b(o, minLen) {
|
|
|
356
356
|
var _base_type;
|
|
357
357
|
var base = (typeof inputSchema === "undefined" ? "undefined" : _type_of$4(inputSchema)) === 'object' && inputSchema != null ? inputSchema : {};
|
|
358
358
|
var existingProperties = _type_of$4(base.properties) === 'object' && base.properties != null ? base.properties : {};
|
|
359
|
-
var next = _object_spread_props$
|
|
359
|
+
var next = _object_spread_props$4(_object_spread$9({}, base), {
|
|
360
360
|
type: (_base_type = base.type) !== null && _base_type !== void 0 ? _base_type : 'object',
|
|
361
|
-
properties: _object_spread_props$
|
|
361
|
+
properties: _object_spread_props$4(_object_spread$9({}, existingProperties), _define_property$b({}, resolved.parameterName, {
|
|
362
362
|
type: 'string',
|
|
363
363
|
maxLength: resolved.maxLength,
|
|
364
364
|
description: resolved.description
|
|
@@ -447,6 +447,34 @@ function _class_call_check$4(instance, Constructor) {
|
|
|
447
447
|
* Mirrors {@link MCP_MANIFEST_VERSION} in `@dereekb/dbx-cli` — both packages
|
|
448
448
|
* version-bump together when the manifest shape changes.
|
|
449
449
|
*/ var MCP_MANIFEST_VERSION = 1;
|
|
450
|
+
/**
|
|
451
|
+
* Resolves the manifest entries whose `compositeKey.from` names `source` — the models whose document
|
|
452
|
+
* id is derived from a `source` document's key. A wildcard `from=*` matches every model except
|
|
453
|
+
* `source` itself (a model's id is never derived from its own key).
|
|
454
|
+
*
|
|
455
|
+
* @param source - The manifest entry of the decoded key's leaf model.
|
|
456
|
+
* @param manifest - The full model manifest.
|
|
457
|
+
* @returns The composite-key entries derived from `source`, in manifest order.
|
|
458
|
+
*/ function findCompositeKeyModelsDerivedFrom(source, manifest) {
|
|
459
|
+
return manifest.filter(function(entry) {
|
|
460
|
+
return isCompositeKeyModelDerivedFrom(source, entry);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Whether `candidate` is a composite-key model whose document id is derived from a `source`
|
|
465
|
+
* document's key — `candidate.compositeKey.from` names `source` (by interface name, identity const,
|
|
466
|
+
* or modelType) or is the wildcard `*`. A model is never derived from its own key.
|
|
467
|
+
*
|
|
468
|
+
* @param source - The manifest entry of the source model.
|
|
469
|
+
* @param candidate - The manifest entry to test.
|
|
470
|
+
* @returns `true` when `candidate`'s id is a flattened `source` key.
|
|
471
|
+
*/ function isCompositeKeyModelDerivedFrom(source, candidate) {
|
|
472
|
+
var _candidate_compositeKey;
|
|
473
|
+
var from = (_candidate_compositeKey = candidate.compositeKey) === null || _candidate_compositeKey === void 0 ? void 0 : _candidate_compositeKey.from;
|
|
474
|
+
return from != null && candidate.modelType !== source.modelType && (from === '*' || from.some(function(name) {
|
|
475
|
+
return name === source.modelName || name === source.identityConst || name === source.modelType;
|
|
476
|
+
}));
|
|
477
|
+
}
|
|
450
478
|
/**
|
|
451
479
|
* Builds the canonical MCP manifest key for a (modelType, callType, specifier) triple.
|
|
452
480
|
*
|
|
@@ -1795,31 +1823,16 @@ function _array_like_to_array$8(arr, len) {
|
|
|
1795
1823
|
function _array_without_holes$6(arr) {
|
|
1796
1824
|
if (Array.isArray(arr)) return _array_like_to_array$8(arr);
|
|
1797
1825
|
}
|
|
1798
|
-
function
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
}
|
|
1806
|
-
if (info.done) resolve(value);
|
|
1807
|
-
else Promise.resolve(value).then(_next, _throw);
|
|
1808
|
-
}
|
|
1809
|
-
function _async_to_generator$7(fn) {
|
|
1810
|
-
return function() {
|
|
1811
|
-
var self = this, args = arguments;
|
|
1812
|
-
return new Promise(function(resolve, reject) {
|
|
1813
|
-
var gen = fn.apply(self, args);
|
|
1814
|
-
function _next(value) {
|
|
1815
|
-
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "next", value);
|
|
1816
|
-
}
|
|
1817
|
-
function _throw(err) {
|
|
1818
|
-
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "throw", err);
|
|
1819
|
-
}
|
|
1820
|
-
_next(undefined);
|
|
1826
|
+
function _define_property$9(obj, key, value) {
|
|
1827
|
+
if (key in obj) {
|
|
1828
|
+
Object.defineProperty(obj, key, {
|
|
1829
|
+
value: value,
|
|
1830
|
+
enumerable: true,
|
|
1831
|
+
configurable: true,
|
|
1832
|
+
writable: true
|
|
1821
1833
|
});
|
|
1822
|
-
};
|
|
1834
|
+
} else obj[key] = value;
|
|
1835
|
+
return obj;
|
|
1823
1836
|
}
|
|
1824
1837
|
function _iterable_to_array$6(iter) {
|
|
1825
1838
|
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
@@ -1829,107 +1842,41 @@ function _iterable_to_array$6(iter) {
|
|
|
1829
1842
|
function _non_iterable_spread$6() {
|
|
1830
1843
|
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
1831
1844
|
}
|
|
1832
|
-
function
|
|
1833
|
-
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
return t[1];
|
|
1841
|
-
},
|
|
1842
|
-
trys: [],
|
|
1843
|
-
ops: []
|
|
1844
|
-
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
1845
|
-
return d(g, "next", {
|
|
1846
|
-
value: verb(0)
|
|
1847
|
-
}), d(g, "throw", {
|
|
1848
|
-
value: verb(1)
|
|
1849
|
-
}), d(g, "return", {
|
|
1850
|
-
value: verb(2)
|
|
1851
|
-
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
1852
|
-
value: function() {
|
|
1853
|
-
return this;
|
|
1845
|
+
function _object_spread$7(target) {
|
|
1846
|
+
for(var i = 1; i < arguments.length; i++){
|
|
1847
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
1848
|
+
var ownKeys = Object.keys(source);
|
|
1849
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
1850
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
1851
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
1852
|
+
}));
|
|
1854
1853
|
}
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
return step([
|
|
1859
|
-
n,
|
|
1860
|
-
v
|
|
1861
|
-
]);
|
|
1862
|
-
};
|
|
1854
|
+
ownKeys.forEach(function(key) {
|
|
1855
|
+
_define_property$9(target, key, source[key]);
|
|
1856
|
+
});
|
|
1863
1857
|
}
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
done: false
|
|
1882
|
-
};
|
|
1883
|
-
case 5:
|
|
1884
|
-
_.label++;
|
|
1885
|
-
y = op[1];
|
|
1886
|
-
op = [
|
|
1887
|
-
0
|
|
1888
|
-
];
|
|
1889
|
-
continue;
|
|
1890
|
-
case 7:
|
|
1891
|
-
op = _.ops.pop();
|
|
1892
|
-
_.trys.pop();
|
|
1893
|
-
continue;
|
|
1894
|
-
default:
|
|
1895
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
1896
|
-
_ = 0;
|
|
1897
|
-
continue;
|
|
1898
|
-
}
|
|
1899
|
-
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
1900
|
-
_.label = op[1];
|
|
1901
|
-
break;
|
|
1902
|
-
}
|
|
1903
|
-
if (op[0] === 6 && _.label < t[1]) {
|
|
1904
|
-
_.label = t[1];
|
|
1905
|
-
t = op;
|
|
1906
|
-
break;
|
|
1907
|
-
}
|
|
1908
|
-
if (t && _.label < t[2]) {
|
|
1909
|
-
_.label = t[2];
|
|
1910
|
-
_.ops.push(op);
|
|
1911
|
-
break;
|
|
1912
|
-
}
|
|
1913
|
-
if (t[2]) _.ops.pop();
|
|
1914
|
-
_.trys.pop();
|
|
1915
|
-
continue;
|
|
1916
|
-
}
|
|
1917
|
-
op = body.call(thisArg, _);
|
|
1918
|
-
} catch (e) {
|
|
1919
|
-
op = [
|
|
1920
|
-
6,
|
|
1921
|
-
e
|
|
1922
|
-
];
|
|
1923
|
-
y = 0;
|
|
1924
|
-
} finally{
|
|
1925
|
-
f = t = 0;
|
|
1926
|
-
}
|
|
1927
|
-
if (op[0] & 5) throw op[1];
|
|
1928
|
-
return {
|
|
1929
|
-
value: op[0] ? op[1] : void 0,
|
|
1930
|
-
done: true
|
|
1931
|
-
};
|
|
1858
|
+
return target;
|
|
1859
|
+
}
|
|
1860
|
+
function ownKeys$3(object, enumerableOnly) {
|
|
1861
|
+
var keys = Object.keys(object);
|
|
1862
|
+
if (Object.getOwnPropertySymbols) {
|
|
1863
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
1864
|
+
keys.push.apply(keys, symbols);
|
|
1865
|
+
}
|
|
1866
|
+
return keys;
|
|
1867
|
+
}
|
|
1868
|
+
function _object_spread_props$3(target, source) {
|
|
1869
|
+
source = source != null ? source : {};
|
|
1870
|
+
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
1871
|
+
else {
|
|
1872
|
+
ownKeys$3(Object(source)).forEach(function(key) {
|
|
1873
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
1874
|
+
});
|
|
1932
1875
|
}
|
|
1876
|
+
return target;
|
|
1877
|
+
}
|
|
1878
|
+
function _to_consumable_array$6(arr) {
|
|
1879
|
+
return _array_without_holes$6(arr) || _iterable_to_array$6(arr) || _unsupported_iterable_to_array$8(arr) || _non_iterable_spread$6();
|
|
1933
1880
|
}
|
|
1934
1881
|
function _unsupported_iterable_to_array$8(o, minLen) {
|
|
1935
1882
|
if (!o) return;
|
|
@@ -1941,56 +1888,59 @@ function _unsupported_iterable_to_array$8(o, minLen) {
|
|
|
1941
1888
|
}
|
|
1942
1889
|
// MARK: Constants
|
|
1943
1890
|
/**
|
|
1944
|
-
* Reserved tool name for the built-in `model-
|
|
1945
|
-
*/ var
|
|
1891
|
+
* Reserved tool name for the built-in `model-info` static tool.
|
|
1892
|
+
*/ var MODEL_INFO_TOOL_NAME = 'model-info';
|
|
1946
1893
|
/**
|
|
1947
|
-
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `
|
|
1948
|
-
* command
|
|
1949
|
-
*/ var
|
|
1894
|
+
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `model-info`
|
|
1895
|
+
* command.
|
|
1896
|
+
*/ var MODEL_INFO_DISPATCH_CALL = 'info';
|
|
1950
1897
|
/**
|
|
1951
|
-
* Synthetic model type used in the tool's dispatch identity.
|
|
1952
|
-
*
|
|
1953
|
-
|
|
1954
|
-
* "model".
|
|
1955
|
-
*/ var MODEL_GET_DISPATCH_MODEL_TYPE = 'model';
|
|
1898
|
+
* Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE};
|
|
1899
|
+
* apps avoiding collisions should not register a real model literally named "model".
|
|
1900
|
+
*/ var MODEL_INFO_DISPATCH_MODEL_TYPE = 'model';
|
|
1956
1901
|
/**
|
|
1957
|
-
*
|
|
1958
|
-
*
|
|
1959
|
-
|
|
1960
|
-
|
|
1902
|
+
* Group label applied to manifest entries that declare no `modelGroup`. Keeps the `groups` mode
|
|
1903
|
+
* total reconcilable with the catalog size (sum of group counts always equals `totalModels`).
|
|
1904
|
+
*/ var MODEL_INFO_UNGROUPED_LABEL = '(ungrouped)';
|
|
1905
|
+
/**
|
|
1906
|
+
* Hint string surfaced alongside the default `groups` response so callers know how to drill in.
|
|
1907
|
+
*/ var MODEL_INFO_GROUPS_HINT = 'Pass `model` for one/many models, `modelGroup` for a group, or `all:true` for the full catalog.';
|
|
1961
1908
|
// MARK: Factory
|
|
1962
1909
|
/**
|
|
1963
|
-
* Builds the built-in `model-
|
|
1910
|
+
* Builds the built-in `model-info` MCP tool definition.
|
|
1964
1911
|
*
|
|
1965
|
-
*
|
|
1966
|
-
* -
|
|
1967
|
-
*
|
|
1968
|
-
* -
|
|
1969
|
-
* -
|
|
1970
|
-
*
|
|
1912
|
+
* Modes (selected by input):
|
|
1913
|
+
* - No args: returns model groups + counts (`mode: 'groups'`) — the cheap default for browsing.
|
|
1914
|
+
* - `model` (string): returns the full entry for one model (`mode: 'single'`).
|
|
1915
|
+
* - `model` (string array): returns full detail per match (`mode: 'multiple'`); misses land in `notFound`.
|
|
1916
|
+
* - `modelGroup`: returns the summary list of that group's models (`mode: 'list'`).
|
|
1917
|
+
* - `all: true`: returns the full catalog summary (`mode: 'list'`).
|
|
1918
|
+
* - `fields`: forces (`true`) or suppresses (`false`) full persisted-field detail in list/multiple modes.
|
|
1971
1919
|
*
|
|
1972
|
-
*
|
|
1973
|
-
* `
|
|
1974
|
-
* `structuredContent` so MCP clients can consume either form.
|
|
1920
|
+
* Each `model` query matches by `modelType`, `identityConst`, or `collectionPrefix`. When several
|
|
1921
|
+
* params are supplied, precedence is `model` > `modelGroup` > `all` > the default `groups` view.
|
|
1975
1922
|
*
|
|
1976
|
-
*
|
|
1977
|
-
*
|
|
1923
|
+
* Output is delivered as both stringified JSON in `content[0].text` and `structuredContent`
|
|
1924
|
+
* so MCP clients can consume either form.
|
|
1925
|
+
*
|
|
1926
|
+
* @param deps - The frozen model manifest loaded at boot from the MCP manifest JSON.
|
|
1978
1927
|
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
1979
1928
|
* server factory's tool registry.
|
|
1980
|
-
*/ function
|
|
1929
|
+
*/ function createModelInfoTool(deps) {
|
|
1981
1930
|
var handler = function handler(args, ctx) {
|
|
1982
|
-
return
|
|
1931
|
+
return Promise.resolve(modelInfoToolHandler(args, ctx, deps));
|
|
1983
1932
|
};
|
|
1984
|
-
var name =
|
|
1985
|
-
var
|
|
1933
|
+
var name = MODEL_INFO_TOOL_NAME;
|
|
1934
|
+
var count = deps.manifest.length;
|
|
1935
|
+
var description = "Browse the Firestore model catalog (".concat(count, " model").concat(count === 1 ? '' : 's', "). No args returns model groups + counts (start here). ") + '`model` (a modelType/identityConst/collectionPrefix string, or an array of them) returns full detail per match — misses are reported in `notFound`. ' + '`modelGroup` returns the summary list for that group. `all:true` returns the full catalog summary. ' + '`fields` (boolean) forces or suppresses persisted-field detail in list/multiple modes.';
|
|
1986
1936
|
return buildStaticToolDefinition({
|
|
1987
1937
|
name: name,
|
|
1988
1938
|
description: description,
|
|
1989
|
-
inputSchema:
|
|
1990
|
-
outputSchema:
|
|
1939
|
+
inputSchema: MODEL_INFO_INPUT_SCHEMA,
|
|
1940
|
+
outputSchema: MODEL_INFO_OUTPUT_SCHEMA,
|
|
1991
1941
|
dispatch: {
|
|
1992
|
-
call:
|
|
1993
|
-
modelType:
|
|
1942
|
+
call: MODEL_INFO_DISPATCH_CALL,
|
|
1943
|
+
modelType: MODEL_INFO_DISPATCH_MODEL_TYPE
|
|
1994
1944
|
},
|
|
1995
1945
|
staticHandler: handler,
|
|
1996
1946
|
effectiveReadOnly: true,
|
|
@@ -2000,98 +1950,139 @@ function _unsupported_iterable_to_array$8(o, minLen) {
|
|
|
2000
1950
|
});
|
|
2001
1951
|
}
|
|
2002
1952
|
// MARK: Handler
|
|
2003
|
-
function
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
merged = _state.sent();
|
|
2032
|
-
result = {
|
|
2033
|
-
content: [
|
|
2034
|
-
{
|
|
2035
|
-
type: 'text',
|
|
2036
|
-
text: JSON.stringify(merged)
|
|
2037
|
-
}
|
|
2038
|
-
],
|
|
2039
|
-
structuredContent: merged
|
|
2040
|
-
};
|
|
2041
|
-
return [
|
|
2042
|
-
3,
|
|
2043
|
-
3
|
|
2044
|
-
];
|
|
2045
|
-
case 2:
|
|
2046
|
-
error = _state.sent();
|
|
2047
|
-
result = formatMcpToolErrorResponse(error);
|
|
2048
|
-
return [
|
|
2049
|
-
3,
|
|
2050
|
-
3
|
|
2051
|
-
];
|
|
2052
|
-
case 3:
|
|
2053
|
-
return [
|
|
2054
|
-
2,
|
|
2055
|
-
result
|
|
2056
|
-
];
|
|
2057
|
-
}
|
|
1953
|
+
function modelInfoToolHandler(args, _ctx, deps) {
|
|
1954
|
+
var result;
|
|
1955
|
+
try {
|
|
1956
|
+
var input = parseModelInfoInput(args);
|
|
1957
|
+
var resolved = resolveModelInfoOutput(input, deps.manifest);
|
|
1958
|
+
var output = attachReferencedEnums(resolved, deps.enums);
|
|
1959
|
+
result = {
|
|
1960
|
+
content: [
|
|
1961
|
+
{
|
|
1962
|
+
type: 'text',
|
|
1963
|
+
text: JSON.stringify(output)
|
|
1964
|
+
}
|
|
1965
|
+
],
|
|
1966
|
+
structuredContent: output
|
|
1967
|
+
};
|
|
1968
|
+
} catch (error) {
|
|
1969
|
+
result = formatMcpToolErrorResponse(error);
|
|
1970
|
+
}
|
|
1971
|
+
return result;
|
|
1972
|
+
}
|
|
1973
|
+
function resolveModelInfoOutput(input, manifest) {
|
|
1974
|
+
var output;
|
|
1975
|
+
if (input.modelQueries != null) {
|
|
1976
|
+
output = buildModelLookupOutput({
|
|
1977
|
+
queries: input.modelQueries,
|
|
1978
|
+
isArray: input.modelIsArray,
|
|
1979
|
+
manifest: manifest,
|
|
1980
|
+
fields: input.fields
|
|
2058
1981
|
});
|
|
2059
|
-
}
|
|
1982
|
+
} else if (input.modelGroup != null) {
|
|
1983
|
+
output = buildGroupFilterOutput({
|
|
1984
|
+
group: input.modelGroup,
|
|
1985
|
+
manifest: manifest,
|
|
1986
|
+
fields: input.fields
|
|
1987
|
+
});
|
|
1988
|
+
} else if (input.all) {
|
|
1989
|
+
output = buildAllOutput(manifest, input.fields);
|
|
1990
|
+
} else {
|
|
1991
|
+
output = buildGroupsOutput(manifest);
|
|
1992
|
+
}
|
|
1993
|
+
return output;
|
|
2060
1994
|
}
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
1995
|
+
// MARK: Enum attachment
|
|
1996
|
+
/**
|
|
1997
|
+
* Attaches the value→label tables for every enum referenced (by `enumRef`) on the returned models'
|
|
1998
|
+
* fields — recursively through `nestedFields` — as a top-level `enums` section.
|
|
1999
|
+
*
|
|
2000
|
+
* Gated behind full field detail: only `single` / `multiple` rows and `list` rows that opted into
|
|
2001
|
+
* `fields:true` carry the persisted `fields` array, so the compact default modes are untouched.
|
|
2002
|
+
* Returns the input unchanged when no enum map is wired or no referenced enum resolves.
|
|
2003
|
+
*
|
|
2004
|
+
* @param output - The resolved model-info output.
|
|
2005
|
+
* @param enums - The optional enum value tables keyed by name.
|
|
2006
|
+
* @returns The output, with an `enums` section attached when detailed rows reference known enums.
|
|
2007
|
+
*/ function attachReferencedEnums(output, enums) {
|
|
2008
|
+
var result = output;
|
|
2009
|
+
if (enums != null) {
|
|
2010
|
+
var referenced = new Set();
|
|
2011
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2012
|
+
try {
|
|
2013
|
+
for(var _iterator = collectDetailedEntries(output)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2014
|
+
var entry = _step.value;
|
|
2015
|
+
collectFieldEnumRefs(entry.fields, referenced);
|
|
2016
|
+
}
|
|
2017
|
+
} catch (err) {
|
|
2018
|
+
_didIteratorError = true;
|
|
2019
|
+
_iteratorError = err;
|
|
2020
|
+
} finally{
|
|
2021
|
+
try {
|
|
2022
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2023
|
+
_iterator.return();
|
|
2024
|
+
}
|
|
2025
|
+
} finally{
|
|
2026
|
+
if (_didIteratorError) {
|
|
2027
|
+
throw _iteratorError;
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
var tables = [];
|
|
2032
|
+
var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
|
|
2033
|
+
try {
|
|
2034
|
+
for(var _iterator1 = referenced[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
2035
|
+
var name = _step1.value;
|
|
2036
|
+
var table = enums[name];
|
|
2037
|
+
if (table != null) tables.push(table);
|
|
2038
|
+
}
|
|
2039
|
+
} catch (err) {
|
|
2040
|
+
_didIteratorError1 = true;
|
|
2041
|
+
_iteratorError1 = err;
|
|
2042
|
+
} finally{
|
|
2043
|
+
try {
|
|
2044
|
+
if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
|
|
2045
|
+
_iterator1.return();
|
|
2046
|
+
}
|
|
2047
|
+
} finally{
|
|
2048
|
+
if (_didIteratorError1) {
|
|
2049
|
+
throw _iteratorError1;
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
}
|
|
2053
|
+
if (tables.length > 0) {
|
|
2054
|
+
result = _object_spread_props$3(_object_spread$7({}, output), {
|
|
2055
|
+
enums: tables
|
|
2056
|
+
});
|
|
2057
|
+
}
|
|
2066
2058
|
}
|
|
2067
|
-
|
|
2068
|
-
|
|
2059
|
+
return result;
|
|
2060
|
+
}
|
|
2061
|
+
/**
|
|
2062
|
+
* Collects the full {@link McpManifestModelEntry} rows (those carrying a persisted `fields` array)
|
|
2063
|
+
* from a model-info output. Summary rows (which expose `fieldCount`, not `fields`) are skipped.
|
|
2064
|
+
*
|
|
2065
|
+
* @param output - The resolved model-info output.
|
|
2066
|
+
* @returns The detailed model entries present in the output.
|
|
2067
|
+
*/ function collectDetailedEntries(output) {
|
|
2068
|
+
var rows = [];
|
|
2069
|
+
if (output.mode === 'single') {
|
|
2070
|
+
rows.push(output.model);
|
|
2071
|
+
} else if (output.mode === 'list' || output.mode === 'multiple') {
|
|
2072
|
+
var _rows;
|
|
2073
|
+
(_rows = rows).push.apply(_rows, _to_consumable_array$6(output.models));
|
|
2069
2074
|
}
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
throw new Error("model-get: keys[".concat(index, "] must be a non-empty string."));
|
|
2073
|
-
}
|
|
2074
|
-
return value;
|
|
2075
|
+
return rows.filter(function(row) {
|
|
2076
|
+
return Array.isArray(row.fields);
|
|
2075
2077
|
});
|
|
2076
|
-
return {
|
|
2077
|
-
modelType: modelType,
|
|
2078
|
-
keys: normalizedKeys
|
|
2079
|
-
};
|
|
2080
2078
|
}
|
|
2081
|
-
function
|
|
2082
|
-
var isRoot = identity.type === 'root';
|
|
2083
|
-
var resolved = [];
|
|
2079
|
+
function collectFieldEnumRefs(fields, into) {
|
|
2084
2080
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2085
2081
|
try {
|
|
2086
|
-
for(var _iterator =
|
|
2087
|
-
var
|
|
2088
|
-
if (
|
|
2089
|
-
|
|
2090
|
-
} else if (isRoot) {
|
|
2091
|
-
resolved.push("".concat(identity.collectionName, "/").concat(value));
|
|
2092
|
-
} else {
|
|
2093
|
-
throw new Error('model-get: modelType "'.concat(identity.modelType, '" is a subcollection; bare ids are not allowed. Provide full keys (e.g. "parentPrefix/parentId/').concat(identity.collectionName, "/").concat(value, '").'));
|
|
2094
|
-
}
|
|
2082
|
+
for(var _iterator = fields[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2083
|
+
var field = _step.value;
|
|
2084
|
+
if (field.enumRef) into.add(field.enumRef);
|
|
2085
|
+
if (field.nestedFields) collectFieldEnumRefs(field.nestedFields, into);
|
|
2095
2086
|
}
|
|
2096
2087
|
} catch (err) {
|
|
2097
2088
|
_didIteratorError = true;
|
|
@@ -2107,126 +2098,593 @@ function resolveKeys$1(keys, identity) {
|
|
|
2107
2098
|
}
|
|
2108
2099
|
}
|
|
2109
2100
|
}
|
|
2110
|
-
return resolved;
|
|
2111
2101
|
}
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
];
|
|
2130
|
-
batch = keys.slice(offset, offset + MCP_MODEL_GET_BATCH_SIZE);
|
|
2131
|
-
return [
|
|
2132
|
-
4,
|
|
2133
|
-
readDocuments(modelType, batch, auth)
|
|
2134
|
-
];
|
|
2135
|
-
case 2:
|
|
2136
|
-
partial = _state.sent();
|
|
2137
|
-
(_merged_results = merged.results).push.apply(_merged_results, _to_consumable_array$6(partial.results));
|
|
2138
|
-
(_merged_errors = merged.errors).push.apply(_merged_errors, _to_consumable_array$6(partial.errors));
|
|
2139
|
-
_state.label = 3;
|
|
2140
|
-
case 3:
|
|
2141
|
-
offset += MCP_MODEL_GET_BATCH_SIZE;
|
|
2142
|
-
return [
|
|
2143
|
-
3,
|
|
2144
|
-
1
|
|
2145
|
-
];
|
|
2146
|
-
case 4:
|
|
2147
|
-
return [
|
|
2148
|
-
2,
|
|
2149
|
-
merged
|
|
2150
|
-
];
|
|
2151
|
-
}
|
|
2152
|
-
});
|
|
2153
|
-
})();
|
|
2102
|
+
// MARK: Input parsing
|
|
2103
|
+
function parseModelInfoInput(args) {
|
|
2104
|
+
var modelQueries = parseModelArg(args['model']);
|
|
2105
|
+
var modelGroup = parseModelGroupArg(args['modelGroup']);
|
|
2106
|
+
var all = parseBooleanArg(args['all'], 'all');
|
|
2107
|
+
var fields = parseBooleanArg(args['fields'], 'fields');
|
|
2108
|
+
return _object_spread$7(_object_spread_props$3(_object_spread$7(_object_spread_props$3(_object_spread$7({}, modelQueries == null ? {} : {
|
|
2109
|
+
modelQueries: modelQueries
|
|
2110
|
+
}), {
|
|
2111
|
+
modelIsArray: Array.isArray(args['model'])
|
|
2112
|
+
}), modelGroup == null ? {} : {
|
|
2113
|
+
modelGroup: modelGroup
|
|
2114
|
+
}), {
|
|
2115
|
+
all: all !== null && all !== void 0 ? all : false
|
|
2116
|
+
}), fields == null ? {} : {
|
|
2117
|
+
fields: fields
|
|
2118
|
+
});
|
|
2154
2119
|
}
|
|
2155
|
-
|
|
2156
|
-
var
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2120
|
+
function parseModelArg(raw) {
|
|
2121
|
+
var result;
|
|
2122
|
+
if (raw == null) {
|
|
2123
|
+
result = undefined;
|
|
2124
|
+
} else if (typeof raw === 'string') {
|
|
2125
|
+
result = [
|
|
2126
|
+
requireNonEmptyString$1(raw, 'model')
|
|
2127
|
+
];
|
|
2128
|
+
} else if (Array.isArray(raw)) {
|
|
2129
|
+
if (raw.length === 0) {
|
|
2130
|
+
throw new Error('model-info: "model" array must contain at least one entry.');
|
|
2131
|
+
}
|
|
2132
|
+
result = raw.map(function(value, index) {
|
|
2133
|
+
return requireNonEmptyString$1(value, "model[".concat(index, "]"));
|
|
2134
|
+
});
|
|
2135
|
+
} else {
|
|
2136
|
+
throw new TypeError('model-info: "model" must be a string or an array of strings when provided.');
|
|
2137
|
+
}
|
|
2138
|
+
return result;
|
|
2139
|
+
}
|
|
2140
|
+
function parseModelGroupArg(raw) {
|
|
2141
|
+
var result;
|
|
2142
|
+
if (raw == null) {
|
|
2143
|
+
result = undefined;
|
|
2144
|
+
} else if (typeof raw === 'string') {
|
|
2145
|
+
result = requireNonEmptyString$1(raw, 'modelGroup');
|
|
2146
|
+
} else {
|
|
2147
|
+
throw new TypeError('model-info: "modelGroup" must be a string when provided.');
|
|
2148
|
+
}
|
|
2149
|
+
return result;
|
|
2150
|
+
}
|
|
2151
|
+
function parseBooleanArg(raw, label) {
|
|
2152
|
+
var result;
|
|
2153
|
+
if (raw == null) {
|
|
2154
|
+
result = undefined;
|
|
2155
|
+
} else if (typeof raw === 'boolean') {
|
|
2156
|
+
result = raw;
|
|
2157
|
+
} else {
|
|
2158
|
+
throw new TypeError('model-info: "'.concat(label, '" must be a boolean when provided.'));
|
|
2159
|
+
}
|
|
2160
|
+
return result;
|
|
2161
|
+
}
|
|
2162
|
+
function requireNonEmptyString$1(value, label) {
|
|
2163
|
+
if (typeof value !== 'string') {
|
|
2164
|
+
throw new TypeError('model-info: "'.concat(label, '" must be a string.'));
|
|
2165
|
+
}
|
|
2166
|
+
var trimmed = value.trim();
|
|
2167
|
+
if (trimmed.length === 0) {
|
|
2168
|
+
throw new Error('model-info: "'.concat(label, '" must be a non-empty string.'));
|
|
2169
|
+
}
|
|
2170
|
+
return trimmed;
|
|
2171
|
+
}
|
|
2172
|
+
// MARK: Output builders
|
|
2173
|
+
function buildGroupsOutput(manifest) {
|
|
2174
|
+
return {
|
|
2175
|
+
mode: 'groups',
|
|
2176
|
+
groups: computeGroupCounts(manifest),
|
|
2177
|
+
totalModels: manifest.length,
|
|
2178
|
+
hint: MODEL_INFO_GROUPS_HINT
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
function buildGroupFilterOutput(config) {
|
|
2182
|
+
var group = config.group, manifest = config.manifest, fields = config.fields;
|
|
2183
|
+
var detailed = fields !== null && fields !== void 0 ? fields : false;
|
|
2184
|
+
var lower = group.toLowerCase();
|
|
2185
|
+
var matches = manifest.filter(function(entry) {
|
|
2186
|
+
var _entry_modelGroup;
|
|
2187
|
+
return ((_entry_modelGroup = entry.modelGroup) === null || _entry_modelGroup === void 0 ? void 0 : _entry_modelGroup.toLowerCase()) === lower;
|
|
2188
|
+
});
|
|
2189
|
+
var result;
|
|
2190
|
+
if (matches.length === 0) {
|
|
2191
|
+
throw new Error(buildUnknownGroupMessage(group, manifest));
|
|
2192
|
+
} else {
|
|
2193
|
+
var canonical = matches[0].modelGroup;
|
|
2194
|
+
result = {
|
|
2195
|
+
mode: 'list',
|
|
2196
|
+
modelGroup: canonical,
|
|
2197
|
+
models: matches.map(function(entry) {
|
|
2198
|
+
return toModelRow(entry, detailed);
|
|
2199
|
+
})
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
return result;
|
|
2203
|
+
}
|
|
2204
|
+
function buildAllOutput(manifest) {
|
|
2205
|
+
var fields = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
|
|
2206
|
+
return {
|
|
2207
|
+
mode: 'list',
|
|
2208
|
+
models: manifest.map(function(entry) {
|
|
2209
|
+
return toModelRow(entry, fields);
|
|
2210
|
+
})
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
function buildModelLookupOutput(config) {
|
|
2214
|
+
var queries = config.queries, isArray = config.isArray, manifest = config.manifest, fields = config.fields;
|
|
2215
|
+
var detailed = fields !== null && fields !== void 0 ? fields : true;
|
|
2216
|
+
var matched = [];
|
|
2217
|
+
var notFound = [];
|
|
2218
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2219
|
+
try {
|
|
2220
|
+
for(var _iterator = queries[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2221
|
+
var query = _step.value;
|
|
2222
|
+
var entry = findModelEntry(query, manifest);
|
|
2223
|
+
if (entry == null) {
|
|
2224
|
+
notFound.push({
|
|
2225
|
+
query: query,
|
|
2226
|
+
message: buildModelNotFoundMessage(query, manifest)
|
|
2227
|
+
});
|
|
2228
|
+
} else {
|
|
2229
|
+
matched.push(toModelRow(entry, detailed));
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
} catch (err) {
|
|
2233
|
+
_didIteratorError = true;
|
|
2234
|
+
_iteratorError = err;
|
|
2235
|
+
} finally{
|
|
2236
|
+
try {
|
|
2237
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2238
|
+
_iterator.return();
|
|
2239
|
+
}
|
|
2240
|
+
} finally{
|
|
2241
|
+
if (_didIteratorError) {
|
|
2242
|
+
throw _iteratorError;
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
var result;
|
|
2247
|
+
if (isArray) {
|
|
2248
|
+
result = notFound.length > 0 ? {
|
|
2249
|
+
mode: 'multiple',
|
|
2250
|
+
models: matched,
|
|
2251
|
+
notFound: notFound
|
|
2252
|
+
} : {
|
|
2253
|
+
mode: 'multiple',
|
|
2254
|
+
models: matched
|
|
2255
|
+
};
|
|
2256
|
+
} else if (matched.length > 0) {
|
|
2257
|
+
result = {
|
|
2258
|
+
mode: 'single',
|
|
2259
|
+
model: matched[0]
|
|
2260
|
+
};
|
|
2261
|
+
} else {
|
|
2262
|
+
throw new Error(notFound[0].message);
|
|
2263
|
+
}
|
|
2264
|
+
return result;
|
|
2265
|
+
}
|
|
2266
|
+
// MARK: Row + group helpers
|
|
2267
|
+
function toModelRow(entry, detailed) {
|
|
2268
|
+
return detailed ? entry : toSummaryRow(entry);
|
|
2269
|
+
}
|
|
2270
|
+
function toSummaryRow(entry) {
|
|
2271
|
+
return _object_spread$7({
|
|
2272
|
+
modelType: entry.modelType,
|
|
2273
|
+
modelName: entry.modelName,
|
|
2274
|
+
identityConst: entry.identityConst,
|
|
2275
|
+
collectionPrefix: entry.collectionPrefix,
|
|
2276
|
+
sourcePackage: entry.sourcePackage,
|
|
2277
|
+
fieldCount: entry.fields.length
|
|
2278
|
+
}, entry.modelGroup == null ? {} : {
|
|
2279
|
+
modelGroup: entry.modelGroup
|
|
2280
|
+
}, entry.parentIdentityConst == null ? {} : {
|
|
2281
|
+
parentIdentityConst: entry.parentIdentityConst
|
|
2282
|
+
}, entry.description == null ? {} : {
|
|
2283
|
+
description: entry.description
|
|
2284
|
+
}, entry.read == null ? {} : {
|
|
2285
|
+
read: entry.read
|
|
2286
|
+
}, entry.serviceFactory == null ? {} : {
|
|
2287
|
+
serviceFactoryExport: entry.serviceFactory.exportName
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Counts models per `modelGroup`, bucketing entries without a group under
|
|
2292
|
+
* {@link MODEL_INFO_UNGROUPED_LABEL}. Sorted by count descending, then group name ascending.
|
|
2293
|
+
*
|
|
2294
|
+
* @param manifest - Model manifest to summarize.
|
|
2295
|
+
* @returns One {@link ModelInfoGroupCount} per group, ordered most-populous-first.
|
|
2296
|
+
*
|
|
2297
|
+
* @__NO_SIDE_EFFECTS__
|
|
2298
|
+
*/ function computeGroupCounts(manifest) {
|
|
2299
|
+
var grouped = makeValuesGroupMap(_to_consumable_array$6(manifest), function(entry) {
|
|
2300
|
+
var _entry_modelGroup;
|
|
2301
|
+
return (_entry_modelGroup = entry.modelGroup) !== null && _entry_modelGroup !== void 0 ? _entry_modelGroup : MODEL_INFO_UNGROUPED_LABEL;
|
|
2302
|
+
});
|
|
2303
|
+
var counts = [];
|
|
2304
|
+
grouped.forEach(function(entries, group) {
|
|
2305
|
+
counts.push({
|
|
2306
|
+
modelGroup: group,
|
|
2307
|
+
modelCount: entries.length
|
|
2308
|
+
});
|
|
2309
|
+
});
|
|
2310
|
+
counts.sort(function(a, b) {
|
|
2311
|
+
return b.modelCount - a.modelCount || a.modelGroup.localeCompare(b.modelGroup);
|
|
2312
|
+
});
|
|
2313
|
+
return counts;
|
|
2314
|
+
}
|
|
2315
|
+
function findGroupCount(query, manifest) {
|
|
2316
|
+
var lower = query.toLowerCase();
|
|
2317
|
+
var result;
|
|
2318
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2319
|
+
try {
|
|
2320
|
+
for(var _iterator = computeGroupCounts(manifest)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2321
|
+
var count = _step.value;
|
|
2322
|
+
if (count.modelGroup.toLowerCase() === lower) {
|
|
2323
|
+
result = count;
|
|
2324
|
+
break;
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
} catch (err) {
|
|
2328
|
+
_didIteratorError = true;
|
|
2329
|
+
_iteratorError = err;
|
|
2330
|
+
} finally{
|
|
2331
|
+
try {
|
|
2332
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2333
|
+
_iterator.return();
|
|
2334
|
+
}
|
|
2335
|
+
} finally{
|
|
2336
|
+
if (_didIteratorError) {
|
|
2337
|
+
throw _iteratorError;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
return result;
|
|
2342
|
+
}
|
|
2343
|
+
function buildModelNotFoundMessage(query, manifest) {
|
|
2344
|
+
var groupMatch = findGroupCount(query, manifest);
|
|
2345
|
+
var message;
|
|
2346
|
+
if (groupMatch == null) {
|
|
2347
|
+
message = 'model-info: no exact match for "'.concat(query, '". Call `model-info` with no arguments to list groups, or pass all:true for the full catalog.');
|
|
2348
|
+
} else {
|
|
2349
|
+
var plural = groupMatch.modelCount === 1 ? '' : 's';
|
|
2350
|
+
message = 'model-info: no exact match for "'.concat(query, '" — did you mean group:"').concat(groupMatch.modelGroup, '" (').concat(groupMatch.modelCount, " model").concat(plural, ')? Use modelGroup:"').concat(groupMatch.modelGroup, '", or all:true for everything.');
|
|
2351
|
+
}
|
|
2352
|
+
return message;
|
|
2353
|
+
}
|
|
2354
|
+
function buildUnknownGroupMessage(group, manifest) {
|
|
2355
|
+
var available = computeGroupCounts(manifest).map(function(count) {
|
|
2356
|
+
return "".concat(count.modelGroup, " (").concat(count.modelCount, ")");
|
|
2357
|
+
}).join(', ');
|
|
2358
|
+
return 'model-info: no model group matches "'.concat(group, '". Available groups: ').concat(available || '(none)', ". Call `model-info` with no arguments to list groups.");
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Resolves a manifest entry by `modelType`, `identityConst`, or `collectionPrefix`.
|
|
2362
|
+
*
|
|
2363
|
+
* @param query - Identifier to look up.
|
|
2364
|
+
* @param manifest - Model manifest to search.
|
|
2365
|
+
* @returns The matching entry or `undefined`.
|
|
2366
|
+
*
|
|
2367
|
+
* @__NO_SIDE_EFFECTS__
|
|
2368
|
+
*/ function findModelEntry(query, manifest) {
|
|
2369
|
+
var result;
|
|
2370
|
+
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2371
|
+
try {
|
|
2372
|
+
for(var _iterator = manifest[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2373
|
+
var entry = _step.value;
|
|
2374
|
+
if (entry.modelType === query || entry.identityConst === query || entry.collectionPrefix === query) {
|
|
2375
|
+
result = entry;
|
|
2376
|
+
break;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
} catch (err) {
|
|
2380
|
+
_didIteratorError = true;
|
|
2381
|
+
_iteratorError = err;
|
|
2382
|
+
} finally{
|
|
2383
|
+
try {
|
|
2384
|
+
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2385
|
+
_iterator.return();
|
|
2386
|
+
}
|
|
2387
|
+
} finally{
|
|
2388
|
+
if (_didIteratorError) {
|
|
2389
|
+
throw _iteratorError;
|
|
2390
|
+
}
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return result;
|
|
2394
|
+
}
|
|
2395
|
+
// MARK: Schemas
|
|
2396
|
+
var MODEL_INFO_INPUT_SCHEMA = {
|
|
2397
|
+
type: 'object',
|
|
2398
|
+
properties: {
|
|
2399
|
+
model: {
|
|
2400
|
+
description: 'One model (string) or many (string array), each matched by modelType, identityConst, or collectionPrefix. A string → `mode:"single"`; an array → `mode:"multiple"`. Misses are reported in `notFound`.',
|
|
2401
|
+
oneOf: [
|
|
2402
|
+
{
|
|
2403
|
+
type: 'string',
|
|
2404
|
+
minLength: 1
|
|
2405
|
+
},
|
|
2406
|
+
{
|
|
2407
|
+
type: 'array',
|
|
2408
|
+
minItems: 1,
|
|
2409
|
+
items: {
|
|
2410
|
+
type: 'string',
|
|
2411
|
+
minLength: 1
|
|
2412
|
+
}
|
|
2413
|
+
}
|
|
2414
|
+
]
|
|
2415
|
+
},
|
|
2416
|
+
modelGroup: {
|
|
2164
2417
|
type: 'string',
|
|
2165
2418
|
minLength: 1,
|
|
2166
|
-
description: '
|
|
2419
|
+
description: 'Return the summary list of models in this group (`mode:"list"`). Matched case-insensitively.'
|
|
2420
|
+
},
|
|
2421
|
+
all: {
|
|
2422
|
+
type: 'boolean',
|
|
2423
|
+
description: 'Opt in to the full catalog summary (every model). Never the default — omit to get groups instead.'
|
|
2424
|
+
},
|
|
2425
|
+
fields: {
|
|
2426
|
+
type: 'boolean',
|
|
2427
|
+
description: 'Force (true) or suppress (false) full persisted-field detail. Defaults to summary rows for list mode and full entries for single/multiple modes.'
|
|
2428
|
+
}
|
|
2429
|
+
},
|
|
2430
|
+
additionalProperties: false
|
|
2431
|
+
};
|
|
2432
|
+
// Shared item schema for model-bearing rows. Required props cover the summary form; full entries
|
|
2433
|
+
// add `fields`, `sourceFile`, and `serviceFactory` (allowed as additional properties).
|
|
2434
|
+
var MODEL_ROW_SCHEMA = {
|
|
2435
|
+
type: 'object',
|
|
2436
|
+
required: [
|
|
2437
|
+
'modelType',
|
|
2438
|
+
'modelName',
|
|
2439
|
+
'identityConst',
|
|
2440
|
+
'collectionPrefix',
|
|
2441
|
+
'sourcePackage'
|
|
2442
|
+
],
|
|
2443
|
+
properties: {
|
|
2444
|
+
modelType: {
|
|
2445
|
+
type: 'string'
|
|
2446
|
+
},
|
|
2447
|
+
modelName: {
|
|
2448
|
+
type: 'string'
|
|
2449
|
+
},
|
|
2450
|
+
modelGroup: {
|
|
2451
|
+
type: 'string'
|
|
2452
|
+
},
|
|
2453
|
+
identityConst: {
|
|
2454
|
+
type: 'string'
|
|
2455
|
+
},
|
|
2456
|
+
collectionPrefix: {
|
|
2457
|
+
type: 'string'
|
|
2458
|
+
},
|
|
2459
|
+
parentIdentityConst: {
|
|
2460
|
+
type: 'string'
|
|
2461
|
+
},
|
|
2462
|
+
sourcePackage: {
|
|
2463
|
+
type: 'string'
|
|
2464
|
+
},
|
|
2465
|
+
sourceFile: {
|
|
2466
|
+
type: 'string'
|
|
2467
|
+
},
|
|
2468
|
+
fieldCount: {
|
|
2469
|
+
type: 'integer'
|
|
2470
|
+
},
|
|
2471
|
+
description: {
|
|
2472
|
+
type: 'string'
|
|
2473
|
+
},
|
|
2474
|
+
read: {
|
|
2475
|
+
type: 'string',
|
|
2476
|
+
enum: [
|
|
2477
|
+
'system',
|
|
2478
|
+
'owner',
|
|
2479
|
+
'admin-only',
|
|
2480
|
+
'permissions'
|
|
2481
|
+
]
|
|
2482
|
+
},
|
|
2483
|
+
serviceFactoryExport: {
|
|
2484
|
+
type: 'string'
|
|
2485
|
+
},
|
|
2486
|
+
fields: {
|
|
2487
|
+
type: 'array',
|
|
2488
|
+
items: {
|
|
2489
|
+
type: 'object'
|
|
2490
|
+
}
|
|
2491
|
+
},
|
|
2492
|
+
serviceFactory: {
|
|
2493
|
+
type: 'object',
|
|
2494
|
+
required: [
|
|
2495
|
+
'exportName',
|
|
2496
|
+
'sourceFile'
|
|
2497
|
+
],
|
|
2498
|
+
properties: {
|
|
2499
|
+
exportName: {
|
|
2500
|
+
type: 'string'
|
|
2501
|
+
},
|
|
2502
|
+
sourceFile: {
|
|
2503
|
+
type: 'string'
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
};
|
|
2509
|
+
/**
|
|
2510
|
+
* JSON-schema for one enum value→label table. Shared with the `enum-info` tool so both advertise the
|
|
2511
|
+
* identical enum shape.
|
|
2512
|
+
*/ var ENUM_TABLE_SCHEMA = {
|
|
2513
|
+
type: 'object',
|
|
2514
|
+
required: [
|
|
2515
|
+
'name',
|
|
2516
|
+
'values'
|
|
2517
|
+
],
|
|
2518
|
+
properties: {
|
|
2519
|
+
name: {
|
|
2520
|
+
type: 'string'
|
|
2167
2521
|
},
|
|
2168
|
-
|
|
2522
|
+
description: {
|
|
2523
|
+
type: 'string'
|
|
2524
|
+
},
|
|
2525
|
+
values: {
|
|
2169
2526
|
type: 'array',
|
|
2170
|
-
minItems: 1,
|
|
2171
|
-
description: 'Full keys ("prefix/id") or bare ids (root models only).',
|
|
2172
2527
|
items: {
|
|
2173
|
-
type: '
|
|
2174
|
-
|
|
2528
|
+
type: 'object',
|
|
2529
|
+
required: [
|
|
2530
|
+
'name',
|
|
2531
|
+
'value'
|
|
2532
|
+
],
|
|
2533
|
+
properties: {
|
|
2534
|
+
name: {
|
|
2535
|
+
type: 'string'
|
|
2536
|
+
},
|
|
2537
|
+
value: {
|
|
2538
|
+
type: [
|
|
2539
|
+
'string',
|
|
2540
|
+
'number'
|
|
2541
|
+
]
|
|
2542
|
+
},
|
|
2543
|
+
description: {
|
|
2544
|
+
type: 'string'
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2175
2547
|
}
|
|
2176
2548
|
}
|
|
2177
|
-
}
|
|
2178
|
-
additionalProperties: false
|
|
2549
|
+
}
|
|
2179
2550
|
};
|
|
2180
|
-
|
|
2551
|
+
// MCP's `tools/list` validator requires `outputSchema.type === 'object'` at the root
|
|
2552
|
+
// (see the MCP SDK's `ToolSchema`), so the variants are expressed via a top-level
|
|
2553
|
+
// object whose nested `oneOf` discriminates by the `mode` literal.
|
|
2554
|
+
var MODEL_INFO_OUTPUT_SCHEMA = {
|
|
2181
2555
|
type: 'object',
|
|
2182
2556
|
required: [
|
|
2183
|
-
'
|
|
2184
|
-
'errors'
|
|
2557
|
+
'mode'
|
|
2185
2558
|
],
|
|
2559
|
+
description: 'Discriminated by `mode`: `groups` (default model groups + counts), `list` (summary/full list for `modelGroup` or `all`), `single` (one `model`), or `multiple` (a `model` array, with misses in `notFound`).',
|
|
2186
2560
|
properties: {
|
|
2187
|
-
|
|
2561
|
+
mode: {
|
|
2562
|
+
type: 'string',
|
|
2563
|
+
enum: [
|
|
2564
|
+
'groups',
|
|
2565
|
+
'list',
|
|
2566
|
+
'single',
|
|
2567
|
+
'multiple'
|
|
2568
|
+
]
|
|
2569
|
+
},
|
|
2570
|
+
groups: {
|
|
2188
2571
|
type: 'array',
|
|
2189
|
-
description: '
|
|
2572
|
+
description: 'Present when `mode` is `"groups"`. One entry per model group.',
|
|
2190
2573
|
items: {
|
|
2191
2574
|
type: 'object',
|
|
2192
2575
|
required: [
|
|
2193
|
-
'
|
|
2194
|
-
'
|
|
2576
|
+
'modelGroup',
|
|
2577
|
+
'modelCount'
|
|
2195
2578
|
],
|
|
2196
2579
|
properties: {
|
|
2197
|
-
|
|
2580
|
+
modelGroup: {
|
|
2198
2581
|
type: 'string'
|
|
2199
2582
|
},
|
|
2200
|
-
|
|
2583
|
+
modelCount: {
|
|
2584
|
+
type: 'integer'
|
|
2585
|
+
}
|
|
2201
2586
|
}
|
|
2202
2587
|
}
|
|
2203
2588
|
},
|
|
2204
|
-
|
|
2589
|
+
totalModels: {
|
|
2590
|
+
type: 'integer',
|
|
2591
|
+
description: 'Present when `mode` is `"groups"`. Total models across all groups.'
|
|
2592
|
+
},
|
|
2593
|
+
hint: {
|
|
2594
|
+
type: 'string',
|
|
2595
|
+
description: 'Present when `mode` is `"groups"`. Guidance on how to drill into the catalog.'
|
|
2596
|
+
},
|
|
2597
|
+
models: {
|
|
2205
2598
|
type: 'array',
|
|
2206
|
-
description: '
|
|
2599
|
+
description: 'Present when `mode` is `"list"` or `"multiple"`. Summary rows by default; full entries when `fields` requests detail.',
|
|
2600
|
+
items: MODEL_ROW_SCHEMA
|
|
2601
|
+
},
|
|
2602
|
+
modelGroup: {
|
|
2603
|
+
type: 'string',
|
|
2604
|
+
description: 'Present when `mode` is `"list"` from a `modelGroup` filter. The canonical group name.'
|
|
2605
|
+
},
|
|
2606
|
+
model: _object_spread_props$3(_object_spread$7({}, MODEL_ROW_SCHEMA), {
|
|
2607
|
+
description: 'Present when `mode` is `"single"`. The matched model entry (full detail unless `fields:false`).'
|
|
2608
|
+
}),
|
|
2609
|
+
notFound: {
|
|
2610
|
+
type: 'array',
|
|
2611
|
+
description: 'Present when `mode` is `"multiple"` and one or more queries matched nothing.',
|
|
2207
2612
|
items: {
|
|
2208
2613
|
type: 'object',
|
|
2209
2614
|
required: [
|
|
2210
|
-
'
|
|
2615
|
+
'query',
|
|
2211
2616
|
'message'
|
|
2212
2617
|
],
|
|
2213
2618
|
properties: {
|
|
2214
|
-
|
|
2619
|
+
query: {
|
|
2215
2620
|
type: 'string'
|
|
2216
2621
|
},
|
|
2217
2622
|
message: {
|
|
2218
2623
|
type: 'string'
|
|
2219
|
-
},
|
|
2220
|
-
code: {
|
|
2221
|
-
type: 'string'
|
|
2222
2624
|
}
|
|
2223
2625
|
}
|
|
2224
2626
|
}
|
|
2627
|
+
},
|
|
2628
|
+
enums: {
|
|
2629
|
+
type: 'array',
|
|
2630
|
+
description: 'Value→label tables for the enums referenced by the returned models’ fields. Present only when full field detail is returned (single/multiple modes, or list/all with `fields:true`) and at least one referenced enum is registered.',
|
|
2631
|
+
items: ENUM_TABLE_SCHEMA
|
|
2225
2632
|
}
|
|
2226
|
-
}
|
|
2633
|
+
},
|
|
2634
|
+
oneOf: [
|
|
2635
|
+
{
|
|
2636
|
+
required: [
|
|
2637
|
+
'groups',
|
|
2638
|
+
'totalModels'
|
|
2639
|
+
],
|
|
2640
|
+
properties: {
|
|
2641
|
+
mode: {
|
|
2642
|
+
const: 'groups'
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
},
|
|
2646
|
+
{
|
|
2647
|
+
required: [
|
|
2648
|
+
'models'
|
|
2649
|
+
],
|
|
2650
|
+
properties: {
|
|
2651
|
+
mode: {
|
|
2652
|
+
const: 'list'
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
},
|
|
2656
|
+
{
|
|
2657
|
+
required: [
|
|
2658
|
+
'model'
|
|
2659
|
+
],
|
|
2660
|
+
properties: {
|
|
2661
|
+
mode: {
|
|
2662
|
+
const: 'single'
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
},
|
|
2666
|
+
{
|
|
2667
|
+
required: [
|
|
2668
|
+
'models'
|
|
2669
|
+
],
|
|
2670
|
+
properties: {
|
|
2671
|
+
mode: {
|
|
2672
|
+
const: 'multiple'
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
]
|
|
2227
2677
|
};
|
|
2228
2678
|
|
|
2229
|
-
function
|
|
2679
|
+
function _array_like_to_array$7(arr, len) {
|
|
2680
|
+
if (len == null || len > arr.length) len = arr.length;
|
|
2681
|
+
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
2682
|
+
return arr2;
|
|
2683
|
+
}
|
|
2684
|
+
function _array_without_holes$5(arr) {
|
|
2685
|
+
if (Array.isArray(arr)) return _array_like_to_array$7(arr);
|
|
2686
|
+
}
|
|
2687
|
+
function asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, key, arg) {
|
|
2230
2688
|
try {
|
|
2231
2689
|
var info = gen[key](arg);
|
|
2232
2690
|
var value = info.value;
|
|
@@ -2237,48 +2695,33 @@ function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
|
|
|
2237
2695
|
if (info.done) resolve(value);
|
|
2238
2696
|
else Promise.resolve(value).then(_next, _throw);
|
|
2239
2697
|
}
|
|
2240
|
-
function _async_to_generator$
|
|
2698
|
+
function _async_to_generator$7(fn) {
|
|
2241
2699
|
return function() {
|
|
2242
2700
|
var self = this, args = arguments;
|
|
2243
2701
|
return new Promise(function(resolve, reject) {
|
|
2244
2702
|
var gen = fn.apply(self, args);
|
|
2245
2703
|
function _next(value) {
|
|
2246
|
-
asyncGeneratorStep$
|
|
2704
|
+
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "next", value);
|
|
2247
2705
|
}
|
|
2248
2706
|
function _throw(err) {
|
|
2249
|
-
asyncGeneratorStep$
|
|
2707
|
+
asyncGeneratorStep$7(gen, resolve, reject, _next, _throw, "throw", err);
|
|
2250
2708
|
}
|
|
2251
2709
|
_next(undefined);
|
|
2252
2710
|
});
|
|
2253
2711
|
};
|
|
2254
2712
|
}
|
|
2255
|
-
function
|
|
2256
|
-
if (
|
|
2257
|
-
|
|
2258
|
-
value: value,
|
|
2259
|
-
enumerable: true,
|
|
2260
|
-
configurable: true,
|
|
2261
|
-
writable: true
|
|
2262
|
-
});
|
|
2263
|
-
} else obj[key] = value;
|
|
2264
|
-
return obj;
|
|
2265
|
-
}
|
|
2266
|
-
function _object_spread$7(target) {
|
|
2267
|
-
for(var i = 1; i < arguments.length; i++){
|
|
2268
|
-
var source = arguments[i] != null ? arguments[i] : {};
|
|
2269
|
-
var ownKeys = Object.keys(source);
|
|
2270
|
-
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
2271
|
-
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
2272
|
-
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
2273
|
-
}));
|
|
2274
|
-
}
|
|
2275
|
-
ownKeys.forEach(function(key) {
|
|
2276
|
-
_define_property$9(target, key, source[key]);
|
|
2277
|
-
});
|
|
2713
|
+
function _iterable_to_array$5(iter) {
|
|
2714
|
+
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
2715
|
+
return Array.from(iter);
|
|
2278
2716
|
}
|
|
2279
|
-
return target;
|
|
2280
2717
|
}
|
|
2281
|
-
function
|
|
2718
|
+
function _non_iterable_spread$5() {
|
|
2719
|
+
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
2720
|
+
}
|
|
2721
|
+
function _to_consumable_array$5(arr) {
|
|
2722
|
+
return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$7(arr) || _non_iterable_spread$5();
|
|
2723
|
+
}
|
|
2724
|
+
function _ts_generator$7(thisArg, body) {
|
|
2282
2725
|
var f, y, t, _ = {
|
|
2283
2726
|
label: 0,
|
|
2284
2727
|
sent: function() {
|
|
@@ -2377,60 +2820,68 @@ function _ts_generator$6(thisArg, body) {
|
|
|
2377
2820
|
};
|
|
2378
2821
|
}
|
|
2379
2822
|
}
|
|
2823
|
+
function _unsupported_iterable_to_array$7(o, minLen) {
|
|
2824
|
+
if (!o) return;
|
|
2825
|
+
if (typeof o === "string") return _array_like_to_array$7(o, minLen);
|
|
2826
|
+
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
2827
|
+
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
2828
|
+
if (n === "Map" || n === "Set") return Array.from(n);
|
|
2829
|
+
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
|
|
2830
|
+
}
|
|
2380
2831
|
// MARK: Constants
|
|
2381
2832
|
/**
|
|
2382
|
-
* Reserved tool name for the built-in `model-
|
|
2383
|
-
*/ var
|
|
2384
|
-
/**
|
|
2385
|
-
* Synthetic call type used in the tool's dispatch identity. Distinct from `model-get`'s `get` so
|
|
2386
|
-
* visibility predicates can target the two independently.
|
|
2387
|
-
*/ var MODEL_ROLES_DISPATCH_CALL = 'roles';
|
|
2833
|
+
* Reserved tool name for the built-in `model-get` static tool.
|
|
2834
|
+
*/ var MODEL_GET_TOOL_NAME = 'model-get';
|
|
2388
2835
|
/**
|
|
2389
|
-
* Synthetic
|
|
2390
|
-
*
|
|
2391
|
-
*/ var
|
|
2836
|
+
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `get`
|
|
2837
|
+
* command and the `/api/model/:modelType/get` HTTP endpoint that backs it.
|
|
2838
|
+
*/ var MODEL_GET_DISPATCH_CALL = 'get';
|
|
2392
2839
|
/**
|
|
2393
|
-
*
|
|
2394
|
-
*
|
|
2395
|
-
*
|
|
2396
|
-
|
|
2397
|
-
|
|
2840
|
+
* Synthetic model type used in the tool's dispatch identity. The tool itself isn't bound to a
|
|
2841
|
+
* specific model type (the `modelType` is part of its input), so we use the literal "model" as
|
|
2842
|
+
* the identity. Apps avoiding collision should not register a real model literally named
|
|
2843
|
+
* "model".
|
|
2844
|
+
*/ var MODEL_GET_DISPATCH_MODEL_TYPE = 'model';
|
|
2398
2845
|
/**
|
|
2399
|
-
*
|
|
2400
|
-
*
|
|
2401
|
-
*
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
*
|
|
2846
|
+
* Maximum number of keys per backend multi-read request. Matches
|
|
2847
|
+
* `MAX_MODEL_ACCESS_MULTI_READ_KEYS` exported from `@dereekb/firebase-server`; mirrored as a
|
|
2848
|
+
* local constant so the bundler doesn't have to follow the import chain just for one number.
|
|
2849
|
+
*/ var MCP_MODEL_GET_BATCH_SIZE = 50;
|
|
2850
|
+
// MARK: Factory
|
|
2851
|
+
/**
|
|
2852
|
+
* Builds the built-in `model-get` MCP tool definition.
|
|
2406
2853
|
*
|
|
2407
|
-
*
|
|
2408
|
-
* -
|
|
2409
|
-
*
|
|
2410
|
-
*
|
|
2411
|
-
* -
|
|
2412
|
-
*
|
|
2854
|
+
* Mirrors dbx-cli's `get` / `get-many` behavior:
|
|
2855
|
+
* - Accepts an array of keys; values containing `/` are treated as full keys and passed verbatim
|
|
2856
|
+
* while bare ids are promoted to `${collectionName}/${id}` for root models.
|
|
2857
|
+
* - Nested (subcollection) models reject bare ids since a parent path is required.
|
|
2858
|
+
* - When a manifest is supplied, a root composite-key model also accepts its declared source
|
|
2859
|
+
* model's key and flattens it into the document id (see {@link CreateModelGetToolDeps.manifest}).
|
|
2860
|
+
* - Auto-chunks at {@link MCP_MODEL_GET_BATCH_SIZE} keys per backend call, mirroring
|
|
2861
|
+
* `getMultipleModelsOverHttpChunked` on the CLI side.
|
|
2413
2862
|
*
|
|
2414
|
-
*
|
|
2415
|
-
*
|
|
2863
|
+
* The handler returns the same `{ results, errors }` shape produced by
|
|
2864
|
+
* `ModelApiGetService.readDocuments`, exposed via both the text content block and
|
|
2865
|
+
* `structuredContent` so MCP clients can consume either form.
|
|
2416
2866
|
*
|
|
2417
|
-
* @param deps -
|
|
2867
|
+
* @param deps - Read-documents and identity-resolver callbacks (typically wired to
|
|
2868
|
+
* `ModelApiGetService`).
|
|
2418
2869
|
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
2419
2870
|
* server factory's tool registry.
|
|
2420
|
-
*/ function
|
|
2871
|
+
*/ function createModelGetTool(deps) {
|
|
2421
2872
|
var handler = function handler(args, ctx) {
|
|
2422
|
-
return
|
|
2873
|
+
return modelGetToolHandler(args, ctx, deps);
|
|
2423
2874
|
};
|
|
2424
|
-
var name =
|
|
2425
|
-
var description =
|
|
2875
|
+
var name = MODEL_GET_TOOL_NAME;
|
|
2876
|
+
var description = "Fetch one or more Firestore model documents by key or bare id. Values containing `/` are treated as full keys; bare ids are auto-promoted to `<collectionName>/<id>` for root models. Subcollection models require full keys.".concat(deps.manifest == null ? '' : ' For a root composite-key model (`@dbxModelCompositeKey`), a source model key is accepted in place of the flattened id and rewritten automatically.');
|
|
2426
2877
|
return buildStaticToolDefinition({
|
|
2427
2878
|
name: name,
|
|
2428
2879
|
description: description,
|
|
2429
|
-
inputSchema:
|
|
2430
|
-
outputSchema:
|
|
2880
|
+
inputSchema: MODEL_GET_INPUT_SCHEMA,
|
|
2881
|
+
outputSchema: MODEL_GET_OUTPUT_SCHEMA,
|
|
2431
2882
|
dispatch: {
|
|
2432
|
-
call:
|
|
2433
|
-
modelType:
|
|
2883
|
+
call: MODEL_GET_DISPATCH_CALL,
|
|
2884
|
+
modelType: MODEL_GET_DISPATCH_MODEL_TYPE
|
|
2434
2885
|
},
|
|
2435
2886
|
staticHandler: handler,
|
|
2436
2887
|
effectiveReadOnly: true,
|
|
@@ -2440,120 +2891,56 @@ function _ts_generator$6(thisArg, body) {
|
|
|
2440
2891
|
});
|
|
2441
2892
|
}
|
|
2442
2893
|
// MARK: Handler
|
|
2443
|
-
function
|
|
2444
|
-
return _async_to_generator$
|
|
2445
|
-
var result, input, identity,
|
|
2446
|
-
return _ts_generator$
|
|
2894
|
+
function modelGetToolHandler(args, ctx, deps) {
|
|
2895
|
+
return _async_to_generator$7(function() {
|
|
2896
|
+
var result, input, identity, resolvedKeys, merged, error;
|
|
2897
|
+
return _ts_generator$7(this, function(_state) {
|
|
2447
2898
|
switch(_state.label){
|
|
2448
2899
|
case 0:
|
|
2449
2900
|
_state.trys.push([
|
|
2450
2901
|
0,
|
|
2451
|
-
|
|
2902
|
+
2,
|
|
2452
2903
|
,
|
|
2453
|
-
|
|
2904
|
+
3
|
|
2454
2905
|
]);
|
|
2455
|
-
input =
|
|
2906
|
+
input = parseModelGetInput(args);
|
|
2456
2907
|
identity = deps.resolveIdentity(input.modelType, ctx.auth);
|
|
2457
2908
|
if (identity == null) {
|
|
2458
2909
|
throw new Error("Unknown modelType: ".concat(input.modelType));
|
|
2459
2910
|
}
|
|
2911
|
+
resolvedKeys = resolveKeys$1(input.keys, identity, deps.manifest);
|
|
2460
2912
|
return [
|
|
2461
2913
|
4,
|
|
2462
|
-
|
|
2463
|
-
|
|
2914
|
+
readInChunks$1({
|
|
2915
|
+
modelType: input.modelType,
|
|
2916
|
+
keys: resolvedKeys,
|
|
2464
2917
|
auth: ctx.auth,
|
|
2465
|
-
|
|
2918
|
+
readDocuments: deps.readDocuments
|
|
2466
2919
|
})
|
|
2467
2920
|
];
|
|
2468
2921
|
case 1:
|
|
2469
|
-
|
|
2470
|
-
keys = resolveKeys(input.keys, identity);
|
|
2471
|
-
return [
|
|
2472
|
-
4,
|
|
2473
|
-
deps.readRoleMaps(_object_spread$7({
|
|
2474
|
-
modelType: input.modelType,
|
|
2475
|
-
keys: keys,
|
|
2476
|
-
auth: ctx.auth
|
|
2477
|
-
}, targetUid == null ? {} : {
|
|
2478
|
-
targetUid: targetUid
|
|
2479
|
-
}))
|
|
2480
|
-
];
|
|
2481
|
-
case 2:
|
|
2482
|
-
resolved = _state.sent();
|
|
2922
|
+
merged = _state.sent();
|
|
2483
2923
|
result = {
|
|
2484
2924
|
content: [
|
|
2485
2925
|
{
|
|
2486
2926
|
type: 'text',
|
|
2487
|
-
text: JSON.stringify(
|
|
2927
|
+
text: JSON.stringify(merged)
|
|
2488
2928
|
}
|
|
2489
2929
|
],
|
|
2490
|
-
structuredContent:
|
|
2930
|
+
structuredContent: merged
|
|
2491
2931
|
};
|
|
2492
2932
|
return [
|
|
2493
2933
|
3,
|
|
2494
|
-
|
|
2934
|
+
3
|
|
2495
2935
|
];
|
|
2496
|
-
case
|
|
2936
|
+
case 2:
|
|
2497
2937
|
error = _state.sent();
|
|
2498
2938
|
result = formatMcpToolErrorResponse(error);
|
|
2499
|
-
return [
|
|
2500
|
-
3,
|
|
2501
|
-
4
|
|
2502
|
-
];
|
|
2503
|
-
case 4:
|
|
2504
|
-
return [
|
|
2505
|
-
2,
|
|
2506
|
-
result
|
|
2507
|
-
];
|
|
2508
|
-
}
|
|
2509
|
-
});
|
|
2510
|
-
})();
|
|
2511
|
-
}
|
|
2512
|
-
/**
|
|
2513
|
-
* Resolves the effective target uid for a call, enforcing the elevated-access gate.
|
|
2514
|
-
*
|
|
2515
|
-
* Requesting your own uid is always allowed and is treated as no target at all, so a caller that
|
|
2516
|
-
* passes their own uid never trips the predicate.
|
|
2517
|
-
*
|
|
2518
|
-
* @param input - The requested uid, the caller's auth, and the authorization predicate.
|
|
2519
|
-
* @returns The uid to resolve as, or `undefined` to resolve as the caller.
|
|
2520
|
-
* @throws {Error} When another user's uid is requested and the predicate denies (or is absent).
|
|
2521
|
-
*/ function resolveTargetUid(input) {
|
|
2522
|
-
return _async_to_generator$6(function() {
|
|
2523
|
-
var requestedUid, auth, canTargetOtherUids, result, allowed, _tmp;
|
|
2524
|
-
return _ts_generator$6(this, function(_state) {
|
|
2525
|
-
switch(_state.label){
|
|
2526
|
-
case 0:
|
|
2527
|
-
requestedUid = input.requestedUid, auth = input.auth, canTargetOtherUids = input.canTargetOtherUids;
|
|
2528
|
-
if (!(requestedUid != null && requestedUid !== (auth === null || auth === void 0 ? void 0 : auth.uid))) return [
|
|
2529
|
-
3,
|
|
2530
|
-
4
|
|
2531
|
-
];
|
|
2532
|
-
if (!(canTargetOtherUids == null)) return [
|
|
2533
|
-
3,
|
|
2534
|
-
1
|
|
2535
|
-
];
|
|
2536
|
-
_tmp = false;
|
|
2537
2939
|
return [
|
|
2538
2940
|
3,
|
|
2539
2941
|
3
|
|
2540
2942
|
];
|
|
2541
|
-
case 1:
|
|
2542
|
-
return [
|
|
2543
|
-
4,
|
|
2544
|
-
canTargetOtherUids(auth)
|
|
2545
|
-
];
|
|
2546
|
-
case 2:
|
|
2547
|
-
_tmp = _state.sent();
|
|
2548
|
-
_state.label = 3;
|
|
2549
2943
|
case 3:
|
|
2550
|
-
allowed = _tmp;
|
|
2551
|
-
if (!allowed) {
|
|
2552
|
-
throw new Error("model-roles: resolving roles for another user's uid requires elevated access.");
|
|
2553
|
-
}
|
|
2554
|
-
result = requestedUid;
|
|
2555
|
-
_state.label = 4;
|
|
2556
|
-
case 4:
|
|
2557
2944
|
return [
|
|
2558
2945
|
2,
|
|
2559
2946
|
result
|
|
@@ -2562,36 +2949,27 @@ function modelRolesToolHandler(args, ctx, deps) {
|
|
|
2562
2949
|
});
|
|
2563
2950
|
})();
|
|
2564
2951
|
}
|
|
2565
|
-
function
|
|
2952
|
+
function parseModelGetInput(args) {
|
|
2566
2953
|
var modelType = args['modelType'];
|
|
2567
2954
|
var keys = args['keys'];
|
|
2568
|
-
var uid = args['uid'];
|
|
2569
2955
|
if (typeof modelType !== 'string' || modelType.length === 0) {
|
|
2570
|
-
throw new Error('model-
|
|
2956
|
+
throw new Error('model-get: "modelType" is required and must be a non-empty string.');
|
|
2571
2957
|
}
|
|
2572
2958
|
if (!Array.isArray(keys) || keys.length === 0) {
|
|
2573
|
-
throw new Error('model-
|
|
2574
|
-
}
|
|
2575
|
-
if (keys.length > MCP_MODEL_ROLES_MAX_KEYS) {
|
|
2576
|
-
throw new Error("model-roles: at most ".concat(MCP_MODEL_ROLES_MAX_KEYS, " keys may be resolved per call (received ").concat(keys.length, ")."));
|
|
2577
|
-
}
|
|
2578
|
-
if (uid !== undefined && (typeof uid !== 'string' || uid.length === 0)) {
|
|
2579
|
-
throw new Error('model-roles: "uid" must be a non-empty string when provided.');
|
|
2959
|
+
throw new Error('model-get: "keys" is required and must be a non-empty array.');
|
|
2580
2960
|
}
|
|
2581
2961
|
var normalizedKeys = keys.map(function(value, index) {
|
|
2582
2962
|
if (typeof value !== 'string' || value.length === 0) {
|
|
2583
|
-
throw new Error("model-
|
|
2963
|
+
throw new Error("model-get: keys[".concat(index, "] must be a non-empty string."));
|
|
2584
2964
|
}
|
|
2585
2965
|
return value;
|
|
2586
2966
|
});
|
|
2587
|
-
return
|
|
2967
|
+
return {
|
|
2588
2968
|
modelType: modelType,
|
|
2589
2969
|
keys: normalizedKeys
|
|
2590
|
-
}
|
|
2591
|
-
uid: uid
|
|
2592
|
-
});
|
|
2970
|
+
};
|
|
2593
2971
|
}
|
|
2594
|
-
function resolveKeys(keys, identity) {
|
|
2972
|
+
function resolveKeys$1(keys, identity, manifest) {
|
|
2595
2973
|
var isRoot = identity.type === 'root';
|
|
2596
2974
|
var resolved = [];
|
|
2597
2975
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
@@ -2599,11 +2977,12 @@ function resolveKeys(keys, identity) {
|
|
|
2599
2977
|
for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2600
2978
|
var value = _step.value;
|
|
2601
2979
|
if (value.includes('/')) {
|
|
2602
|
-
|
|
2980
|
+
var _ref;
|
|
2981
|
+
resolved.push((_ref = isRoot ? flattenCompositeSourceKey(value, identity, manifest) : undefined) !== null && _ref !== void 0 ? _ref : value);
|
|
2603
2982
|
} else if (isRoot) {
|
|
2604
2983
|
resolved.push("".concat(identity.collectionName, "/").concat(value));
|
|
2605
2984
|
} else {
|
|
2606
|
-
throw new Error('model-
|
|
2985
|
+
throw new Error('model-get: modelType "'.concat(identity.modelType, '" is a subcollection; bare ids are not allowed. Provide full keys (e.g. "parentPrefix/parentId/').concat(identity.collectionName, "/").concat(value, '").'));
|
|
2607
2986
|
}
|
|
2608
2987
|
}
|
|
2609
2988
|
} catch (err) {
|
|
@@ -2622,8 +3001,80 @@ function resolveKeys(keys, identity) {
|
|
|
2622
3001
|
}
|
|
2623
3002
|
return resolved;
|
|
2624
3003
|
}
|
|
3004
|
+
/**
|
|
3005
|
+
* Rewrites `key` into the requested composite-key model's document key when `key`'s leaf model is one
|
|
3006
|
+
* of that model's declared sources.
|
|
3007
|
+
*
|
|
3008
|
+
* @param key - A full `prefix/id` key supplied by the caller.
|
|
3009
|
+
* @param identity - The identity of the requested (root) model.
|
|
3010
|
+
* @param manifest - The model catalog, when wired.
|
|
3011
|
+
* @returns The rewritten `<collectionName>/<flattened key>`, or `undefined` — leave the key alone — when
|
|
3012
|
+
* the manifest is absent, the key already belongs to the requested collection, the requested model
|
|
3013
|
+
* declares no composite key, or the key's leaf model is not one of its sources.
|
|
3014
|
+
*/ function flattenCompositeSourceKey(key, identity, manifest) {
|
|
3015
|
+
var result;
|
|
3016
|
+
var target = manifest == null ? undefined : manifest.find(function(entry) {
|
|
3017
|
+
return entry.modelType === identity.modelType;
|
|
3018
|
+
});
|
|
3019
|
+
if (manifest != null && (target === null || target === void 0 ? void 0 : target.compositeKey) != null && !key.startsWith("".concat(identity.collectionName, "/"))) {
|
|
3020
|
+
var segments = key.split('/').filter(function(s) {
|
|
3021
|
+
return s.length > 0;
|
|
3022
|
+
});
|
|
3023
|
+
var leafPrefix = segments.length >= 2 && segments.length % 2 === 0 ? segments[segments.length - 2] : undefined;
|
|
3024
|
+
var sourceEntry = leafPrefix == null ? undefined : findModelEntry(leafPrefix, manifest);
|
|
3025
|
+
var isSource = sourceEntry != null && isCompositeKeyModelDerivedFrom(sourceEntry, target);
|
|
3026
|
+
if (isSource) {
|
|
3027
|
+
var flatId = target.compositeKey.encoding === 'two-way' ? twoWayFlatFirestoreModelKey(key) : flatFirestoreModelKey(key);
|
|
3028
|
+
result = "".concat(identity.collectionName, "/").concat(flatId);
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
return result;
|
|
3032
|
+
}
|
|
3033
|
+
function readInChunks$1(input) {
|
|
3034
|
+
return _async_to_generator$7(function() {
|
|
3035
|
+
var modelType, keys, auth, readDocuments, merged, offset, _merged_results, _merged_errors, batch, partial;
|
|
3036
|
+
return _ts_generator$7(this, function(_state) {
|
|
3037
|
+
switch(_state.label){
|
|
3038
|
+
case 0:
|
|
3039
|
+
modelType = input.modelType, keys = input.keys, auth = input.auth, readDocuments = input.readDocuments;
|
|
3040
|
+
merged = {
|
|
3041
|
+
results: [],
|
|
3042
|
+
errors: []
|
|
3043
|
+
};
|
|
3044
|
+
offset = 0;
|
|
3045
|
+
_state.label = 1;
|
|
3046
|
+
case 1:
|
|
3047
|
+
if (!(offset < keys.length)) return [
|
|
3048
|
+
3,
|
|
3049
|
+
4
|
|
3050
|
+
];
|
|
3051
|
+
batch = keys.slice(offset, offset + MCP_MODEL_GET_BATCH_SIZE);
|
|
3052
|
+
return [
|
|
3053
|
+
4,
|
|
3054
|
+
readDocuments(modelType, batch, auth)
|
|
3055
|
+
];
|
|
3056
|
+
case 2:
|
|
3057
|
+
partial = _state.sent();
|
|
3058
|
+
(_merged_results = merged.results).push.apply(_merged_results, _to_consumable_array$5(partial.results));
|
|
3059
|
+
(_merged_errors = merged.errors).push.apply(_merged_errors, _to_consumable_array$5(partial.errors));
|
|
3060
|
+
_state.label = 3;
|
|
3061
|
+
case 3:
|
|
3062
|
+
offset += MCP_MODEL_GET_BATCH_SIZE;
|
|
3063
|
+
return [
|
|
3064
|
+
3,
|
|
3065
|
+
1
|
|
3066
|
+
];
|
|
3067
|
+
case 4:
|
|
3068
|
+
return [
|
|
3069
|
+
2,
|
|
3070
|
+
merged
|
|
3071
|
+
];
|
|
3072
|
+
}
|
|
3073
|
+
});
|
|
3074
|
+
})();
|
|
3075
|
+
}
|
|
2625
3076
|
// MARK: Schemas
|
|
2626
|
-
var
|
|
3077
|
+
var MODEL_GET_INPUT_SCHEMA = {
|
|
2627
3078
|
type: 'object',
|
|
2628
3079
|
required: [
|
|
2629
3080
|
'modelType',
|
|
@@ -2633,78 +3084,47 @@ var MODEL_ROLES_INPUT_SCHEMA = {
|
|
|
2633
3084
|
modelType: {
|
|
2634
3085
|
type: 'string',
|
|
2635
3086
|
minLength: 1,
|
|
2636
|
-
description: 'Firestore model type to
|
|
3087
|
+
description: 'Firestore model type to fetch (e.g. "guestbook", "profile").'
|
|
2637
3088
|
},
|
|
2638
3089
|
keys: {
|
|
2639
3090
|
type: 'array',
|
|
2640
3091
|
minItems: 1,
|
|
2641
|
-
|
|
2642
|
-
description: 'Full keys ("prefix/id") or bare ids (root models only).',
|
|
3092
|
+
description: 'Full keys ("prefix/id") or bare ids (root models only). For a root composite-key model, the source model key (e.g. a District key for jobDistrict) is also accepted and flattened into the document id.',
|
|
2643
3093
|
items: {
|
|
2644
3094
|
type: 'string',
|
|
2645
3095
|
minLength: 1
|
|
2646
3096
|
}
|
|
2647
|
-
},
|
|
2648
|
-
uid: {
|
|
2649
|
-
type: 'string',
|
|
2650
|
-
minLength: 1,
|
|
2651
|
-
description: 'Resolve roles as this user instead of the caller. Requires elevated access; passing your own uid is always allowed.'
|
|
2652
3097
|
}
|
|
2653
3098
|
},
|
|
2654
3099
|
additionalProperties: false
|
|
2655
3100
|
};
|
|
2656
|
-
var
|
|
3101
|
+
var MODEL_GET_OUTPUT_SCHEMA = {
|
|
2657
3102
|
type: 'object',
|
|
2658
3103
|
required: [
|
|
2659
|
-
'targeted',
|
|
2660
3104
|
'results',
|
|
2661
3105
|
'errors'
|
|
2662
3106
|
],
|
|
2663
3107
|
properties: {
|
|
2664
|
-
uid: {
|
|
2665
|
-
type: 'string',
|
|
2666
|
-
description: 'The uid the roles were resolved for.'
|
|
2667
|
-
},
|
|
2668
|
-
targeted: {
|
|
2669
|
-
type: 'boolean',
|
|
2670
|
-
description: 'True when the roles were resolved for a user other than the caller.'
|
|
2671
|
-
},
|
|
2672
3108
|
results: {
|
|
2673
3109
|
type: 'array',
|
|
2674
|
-
description: 'Per-key
|
|
3110
|
+
description: 'Per-key successful reads.',
|
|
2675
3111
|
items: {
|
|
2676
3112
|
type: 'object',
|
|
2677
3113
|
required: [
|
|
2678
3114
|
'key',
|
|
2679
|
-
'
|
|
2680
|
-
'fullAccess',
|
|
2681
|
-
'roles'
|
|
3115
|
+
'data'
|
|
2682
3116
|
],
|
|
2683
3117
|
properties: {
|
|
2684
3118
|
key: {
|
|
2685
3119
|
type: 'string'
|
|
2686
3120
|
},
|
|
2687
|
-
|
|
2688
|
-
type: 'boolean',
|
|
2689
|
-
description: 'Whether the document exists. Roles are only computed for documents that exist.'
|
|
2690
|
-
},
|
|
2691
|
-
fullAccess: {
|
|
2692
|
-
type: 'boolean',
|
|
2693
|
-
description: 'True when the full-access marker was granted; every role is implicitly held and "roles" is empty.'
|
|
2694
|
-
},
|
|
2695
|
-
roles: {
|
|
2696
|
-
type: 'array',
|
|
2697
|
-
items: {
|
|
2698
|
-
type: 'string'
|
|
2699
|
-
},
|
|
2700
|
-
description: 'Granted role names, sorted.'
|
|
2701
|
-
}
|
|
3121
|
+
data: {}
|
|
2702
3122
|
}
|
|
2703
3123
|
}
|
|
2704
3124
|
},
|
|
2705
3125
|
errors: {
|
|
2706
3126
|
type: 'array',
|
|
2707
|
-
description: 'Per-key failures
|
|
3127
|
+
description: 'Per-key failures (not-found, forbidden, etc.).',
|
|
2708
3128
|
items: {
|
|
2709
3129
|
type: 'object',
|
|
2710
3130
|
required: [
|
|
@@ -2727,565 +3147,384 @@ var MODEL_ROLES_OUTPUT_SCHEMA = {
|
|
|
2727
3147
|
}
|
|
2728
3148
|
};
|
|
2729
3149
|
|
|
2730
|
-
function
|
|
2731
|
-
if (len == null || len > arr.length) len = arr.length;
|
|
2732
|
-
for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
|
|
2733
|
-
return arr2;
|
|
2734
|
-
}
|
|
2735
|
-
function _array_without_holes$5(arr) {
|
|
2736
|
-
if (Array.isArray(arr)) return _array_like_to_array$7(arr);
|
|
2737
|
-
}
|
|
2738
|
-
function _define_property$8(obj, key, value) {
|
|
2739
|
-
if (key in obj) {
|
|
2740
|
-
Object.defineProperty(obj, key, {
|
|
2741
|
-
value: value,
|
|
2742
|
-
enumerable: true,
|
|
2743
|
-
configurable: true,
|
|
2744
|
-
writable: true
|
|
2745
|
-
});
|
|
2746
|
-
} else obj[key] = value;
|
|
2747
|
-
return obj;
|
|
2748
|
-
}
|
|
2749
|
-
function _iterable_to_array$5(iter) {
|
|
2750
|
-
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
|
|
2751
|
-
return Array.from(iter);
|
|
2752
|
-
}
|
|
2753
|
-
}
|
|
2754
|
-
function _non_iterable_spread$5() {
|
|
2755
|
-
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
|
|
2756
|
-
}
|
|
2757
|
-
function _object_spread$6(target) {
|
|
2758
|
-
for(var i = 1; i < arguments.length; i++){
|
|
2759
|
-
var source = arguments[i] != null ? arguments[i] : {};
|
|
2760
|
-
var ownKeys = Object.keys(source);
|
|
2761
|
-
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
2762
|
-
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
2763
|
-
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
2764
|
-
}));
|
|
2765
|
-
}
|
|
2766
|
-
ownKeys.forEach(function(key) {
|
|
2767
|
-
_define_property$8(target, key, source[key]);
|
|
2768
|
-
});
|
|
2769
|
-
}
|
|
2770
|
-
return target;
|
|
2771
|
-
}
|
|
2772
|
-
function ownKeys$2(object, enumerableOnly) {
|
|
2773
|
-
var keys = Object.keys(object);
|
|
2774
|
-
if (Object.getOwnPropertySymbols) {
|
|
2775
|
-
var symbols = Object.getOwnPropertySymbols(object);
|
|
2776
|
-
keys.push.apply(keys, symbols);
|
|
2777
|
-
}
|
|
2778
|
-
return keys;
|
|
2779
|
-
}
|
|
2780
|
-
function _object_spread_props$2(target, source) {
|
|
2781
|
-
source = source != null ? source : {};
|
|
2782
|
-
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
2783
|
-
else {
|
|
2784
|
-
ownKeys$2(Object(source)).forEach(function(key) {
|
|
2785
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
2786
|
-
});
|
|
2787
|
-
}
|
|
2788
|
-
return target;
|
|
2789
|
-
}
|
|
2790
|
-
function _to_consumable_array$5(arr) {
|
|
2791
|
-
return _array_without_holes$5(arr) || _iterable_to_array$5(arr) || _unsupported_iterable_to_array$7(arr) || _non_iterable_spread$5();
|
|
2792
|
-
}
|
|
2793
|
-
function _unsupported_iterable_to_array$7(o, minLen) {
|
|
2794
|
-
if (!o) return;
|
|
2795
|
-
if (typeof o === "string") return _array_like_to_array$7(o, minLen);
|
|
2796
|
-
var n = Object.prototype.toString.call(o).slice(8, -1);
|
|
2797
|
-
if (n === "Object" && o.constructor) n = o.constructor.name;
|
|
2798
|
-
if (n === "Map" || n === "Set") return Array.from(n);
|
|
2799
|
-
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$7(o, minLen);
|
|
2800
|
-
}
|
|
2801
|
-
// MARK: Constants
|
|
2802
|
-
/**
|
|
2803
|
-
* Reserved tool name for the built-in `model-info` static tool.
|
|
2804
|
-
*/ var MODEL_INFO_TOOL_NAME = 'model-info';
|
|
2805
|
-
/**
|
|
2806
|
-
* Synthetic call type used in the tool's dispatch identity. Aligns with the dbx-cli `model-info`
|
|
2807
|
-
* command.
|
|
2808
|
-
*/ var MODEL_INFO_DISPATCH_CALL = 'info';
|
|
2809
|
-
/**
|
|
2810
|
-
* Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE};
|
|
2811
|
-
* apps avoiding collisions should not register a real model literally named "model".
|
|
2812
|
-
*/ var MODEL_INFO_DISPATCH_MODEL_TYPE = 'model';
|
|
2813
|
-
/**
|
|
2814
|
-
* Group label applied to manifest entries that declare no `modelGroup`. Keeps the `groups` mode
|
|
2815
|
-
* total reconcilable with the catalog size (sum of group counts always equals `totalModels`).
|
|
2816
|
-
*/ var MODEL_INFO_UNGROUPED_LABEL = '(ungrouped)';
|
|
2817
|
-
/**
|
|
2818
|
-
* Hint string surfaced alongside the default `groups` response so callers know how to drill in.
|
|
2819
|
-
*/ var MODEL_INFO_GROUPS_HINT = 'Pass `model` for one/many models, `modelGroup` for a group, or `all:true` for the full catalog.';
|
|
2820
|
-
// MARK: Factory
|
|
2821
|
-
/**
|
|
2822
|
-
* Builds the built-in `model-info` MCP tool definition.
|
|
2823
|
-
*
|
|
2824
|
-
* Modes (selected by input):
|
|
2825
|
-
* - No args: returns model groups + counts (`mode: 'groups'`) — the cheap default for browsing.
|
|
2826
|
-
* - `model` (string): returns the full entry for one model (`mode: 'single'`).
|
|
2827
|
-
* - `model` (string array): returns full detail per match (`mode: 'multiple'`); misses land in `notFound`.
|
|
2828
|
-
* - `modelGroup`: returns the summary list of that group's models (`mode: 'list'`).
|
|
2829
|
-
* - `all: true`: returns the full catalog summary (`mode: 'list'`).
|
|
2830
|
-
* - `fields`: forces (`true`) or suppresses (`false`) full persisted-field detail in list/multiple modes.
|
|
2831
|
-
*
|
|
2832
|
-
* Each `model` query matches by `modelType`, `identityConst`, or `collectionPrefix`. When several
|
|
2833
|
-
* params are supplied, precedence is `model` > `modelGroup` > `all` > the default `groups` view.
|
|
2834
|
-
*
|
|
2835
|
-
* Output is delivered as both stringified JSON in `content[0].text` and `structuredContent`
|
|
2836
|
-
* so MCP clients can consume either form.
|
|
2837
|
-
*
|
|
2838
|
-
* @param deps - The frozen model manifest loaded at boot from the MCP manifest JSON.
|
|
2839
|
-
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
2840
|
-
* server factory's tool registry.
|
|
2841
|
-
*/ function createModelInfoTool(deps) {
|
|
2842
|
-
var handler = function handler(args, ctx) {
|
|
2843
|
-
return Promise.resolve(modelInfoToolHandler(args, ctx, deps));
|
|
2844
|
-
};
|
|
2845
|
-
var name = MODEL_INFO_TOOL_NAME;
|
|
2846
|
-
var count = deps.manifest.length;
|
|
2847
|
-
var description = "Browse the Firestore model catalog (".concat(count, " model").concat(count === 1 ? '' : 's', "). No args returns model groups + counts (start here). ") + '`model` (a modelType/identityConst/collectionPrefix string, or an array of them) returns full detail per match — misses are reported in `notFound`. ' + '`modelGroup` returns the summary list for that group. `all:true` returns the full catalog summary. ' + '`fields` (boolean) forces or suppresses persisted-field detail in list/multiple modes.';
|
|
2848
|
-
return buildStaticToolDefinition({
|
|
2849
|
-
name: name,
|
|
2850
|
-
description: description,
|
|
2851
|
-
inputSchema: MODEL_INFO_INPUT_SCHEMA,
|
|
2852
|
-
outputSchema: MODEL_INFO_OUTPUT_SCHEMA,
|
|
2853
|
-
dispatch: {
|
|
2854
|
-
call: MODEL_INFO_DISPATCH_CALL,
|
|
2855
|
-
modelType: MODEL_INFO_DISPATCH_MODEL_TYPE
|
|
2856
|
-
},
|
|
2857
|
-
staticHandler: handler,
|
|
2858
|
-
effectiveReadOnly: true,
|
|
2859
|
-
rule: {
|
|
2860
|
-
requireAuthenticated: true
|
|
2861
|
-
}
|
|
2862
|
-
});
|
|
2863
|
-
}
|
|
2864
|
-
// MARK: Handler
|
|
2865
|
-
function modelInfoToolHandler(args, _ctx, deps) {
|
|
2866
|
-
var result;
|
|
3150
|
+
function asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, key, arg) {
|
|
2867
3151
|
try {
|
|
2868
|
-
var
|
|
2869
|
-
var
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
{
|
|
2874
|
-
type: 'text',
|
|
2875
|
-
text: JSON.stringify(output)
|
|
2876
|
-
}
|
|
2877
|
-
],
|
|
2878
|
-
structuredContent: output
|
|
2879
|
-
};
|
|
2880
|
-
} catch (error) {
|
|
2881
|
-
result = formatMcpToolErrorResponse(error);
|
|
2882
|
-
}
|
|
2883
|
-
return result;
|
|
2884
|
-
}
|
|
2885
|
-
function resolveModelInfoOutput(input, manifest) {
|
|
2886
|
-
var output;
|
|
2887
|
-
if (input.modelQueries != null) {
|
|
2888
|
-
output = buildModelLookupOutput({
|
|
2889
|
-
queries: input.modelQueries,
|
|
2890
|
-
isArray: input.modelIsArray,
|
|
2891
|
-
manifest: manifest,
|
|
2892
|
-
fields: input.fields
|
|
2893
|
-
});
|
|
2894
|
-
} else if (input.modelGroup != null) {
|
|
2895
|
-
output = buildGroupFilterOutput({
|
|
2896
|
-
group: input.modelGroup,
|
|
2897
|
-
manifest: manifest,
|
|
2898
|
-
fields: input.fields
|
|
2899
|
-
});
|
|
2900
|
-
} else if (input.all) {
|
|
2901
|
-
output = buildAllOutput(manifest, input.fields);
|
|
2902
|
-
} else {
|
|
2903
|
-
output = buildGroupsOutput(manifest);
|
|
2904
|
-
}
|
|
2905
|
-
return output;
|
|
2906
|
-
}
|
|
2907
|
-
// MARK: Enum attachment
|
|
2908
|
-
/**
|
|
2909
|
-
* Attaches the value→label tables for every enum referenced (by `enumRef`) on the returned models'
|
|
2910
|
-
* fields — recursively through `nestedFields` — as a top-level `enums` section.
|
|
2911
|
-
*
|
|
2912
|
-
* Gated behind full field detail: only `single` / `multiple` rows and `list` rows that opted into
|
|
2913
|
-
* `fields:true` carry the persisted `fields` array, so the compact default modes are untouched.
|
|
2914
|
-
* Returns the input unchanged when no enum map is wired or no referenced enum resolves.
|
|
2915
|
-
*
|
|
2916
|
-
* @param output - The resolved model-info output.
|
|
2917
|
-
* @param enums - The optional enum value tables keyed by name.
|
|
2918
|
-
* @returns The output, with an `enums` section attached when detailed rows reference known enums.
|
|
2919
|
-
*/ function attachReferencedEnums(output, enums) {
|
|
2920
|
-
var result = output;
|
|
2921
|
-
if (enums != null) {
|
|
2922
|
-
var referenced = new Set();
|
|
2923
|
-
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
2924
|
-
try {
|
|
2925
|
-
for(var _iterator = collectDetailedEntries(output)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
2926
|
-
var entry = _step.value;
|
|
2927
|
-
collectFieldEnumRefs(entry.fields, referenced);
|
|
2928
|
-
}
|
|
2929
|
-
} catch (err) {
|
|
2930
|
-
_didIteratorError = true;
|
|
2931
|
-
_iteratorError = err;
|
|
2932
|
-
} finally{
|
|
2933
|
-
try {
|
|
2934
|
-
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
2935
|
-
_iterator.return();
|
|
2936
|
-
}
|
|
2937
|
-
} finally{
|
|
2938
|
-
if (_didIteratorError) {
|
|
2939
|
-
throw _iteratorError;
|
|
2940
|
-
}
|
|
2941
|
-
}
|
|
2942
|
-
}
|
|
2943
|
-
var tables = [];
|
|
2944
|
-
var _iteratorNormalCompletion1 = true, _didIteratorError1 = false, _iteratorError1 = undefined;
|
|
2945
|
-
try {
|
|
2946
|
-
for(var _iterator1 = referenced[Symbol.iterator](), _step1; !(_iteratorNormalCompletion1 = (_step1 = _iterator1.next()).done); _iteratorNormalCompletion1 = true){
|
|
2947
|
-
var name = _step1.value;
|
|
2948
|
-
var table = enums[name];
|
|
2949
|
-
if (table != null) tables.push(table);
|
|
2950
|
-
}
|
|
2951
|
-
} catch (err) {
|
|
2952
|
-
_didIteratorError1 = true;
|
|
2953
|
-
_iteratorError1 = err;
|
|
2954
|
-
} finally{
|
|
2955
|
-
try {
|
|
2956
|
-
if (!_iteratorNormalCompletion1 && _iterator1.return != null) {
|
|
2957
|
-
_iterator1.return();
|
|
2958
|
-
}
|
|
2959
|
-
} finally{
|
|
2960
|
-
if (_didIteratorError1) {
|
|
2961
|
-
throw _iteratorError1;
|
|
2962
|
-
}
|
|
2963
|
-
}
|
|
2964
|
-
}
|
|
2965
|
-
if (tables.length > 0) {
|
|
2966
|
-
result = _object_spread_props$2(_object_spread$6({}, output), {
|
|
2967
|
-
enums: tables
|
|
2968
|
-
});
|
|
2969
|
-
}
|
|
2970
|
-
}
|
|
2971
|
-
return result;
|
|
2972
|
-
}
|
|
2973
|
-
/**
|
|
2974
|
-
* Collects the full {@link McpManifestModelEntry} rows (those carrying a persisted `fields` array)
|
|
2975
|
-
* from a model-info output. Summary rows (which expose `fieldCount`, not `fields`) are skipped.
|
|
2976
|
-
*
|
|
2977
|
-
* @param output - The resolved model-info output.
|
|
2978
|
-
* @returns The detailed model entries present in the output.
|
|
2979
|
-
*/ function collectDetailedEntries(output) {
|
|
2980
|
-
var rows = [];
|
|
2981
|
-
if (output.mode === 'single') {
|
|
2982
|
-
rows.push(output.model);
|
|
2983
|
-
} else if (output.mode === 'list' || output.mode === 'multiple') {
|
|
2984
|
-
var _rows;
|
|
2985
|
-
(_rows = rows).push.apply(_rows, _to_consumable_array$5(output.models));
|
|
3152
|
+
var info = gen[key](arg);
|
|
3153
|
+
var value = info.value;
|
|
3154
|
+
} catch (error) {
|
|
3155
|
+
reject(error);
|
|
3156
|
+
return;
|
|
2986
3157
|
}
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
});
|
|
3158
|
+
if (info.done) resolve(value);
|
|
3159
|
+
else Promise.resolve(value).then(_next, _throw);
|
|
2990
3160
|
}
|
|
2991
|
-
function
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
var
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
}
|
|
2999
|
-
} catch (err) {
|
|
3000
|
-
_didIteratorError = true;
|
|
3001
|
-
_iteratorError = err;
|
|
3002
|
-
} finally{
|
|
3003
|
-
try {
|
|
3004
|
-
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
3005
|
-
_iterator.return();
|
|
3161
|
+
function _async_to_generator$6(fn) {
|
|
3162
|
+
return function() {
|
|
3163
|
+
var self = this, args = arguments;
|
|
3164
|
+
return new Promise(function(resolve, reject) {
|
|
3165
|
+
var gen = fn.apply(self, args);
|
|
3166
|
+
function _next(value) {
|
|
3167
|
+
asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "next", value);
|
|
3006
3168
|
}
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
throw _iteratorError;
|
|
3169
|
+
function _throw(err) {
|
|
3170
|
+
asyncGeneratorStep$6(gen, resolve, reject, _next, _throw, "throw", err);
|
|
3010
3171
|
}
|
|
3011
|
-
|
|
3012
|
-
|
|
3172
|
+
_next(undefined);
|
|
3173
|
+
});
|
|
3174
|
+
};
|
|
3013
3175
|
}
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
}
|
|
3023
|
-
|
|
3024
|
-
}), modelGroup == null ? {} : {
|
|
3025
|
-
modelGroup: modelGroup
|
|
3026
|
-
}), {
|
|
3027
|
-
all: all !== null && all !== void 0 ? all : false
|
|
3028
|
-
}), fields == null ? {} : {
|
|
3029
|
-
fields: fields
|
|
3030
|
-
});
|
|
3176
|
+
function _define_property$8(obj, key, value) {
|
|
3177
|
+
if (key in obj) {
|
|
3178
|
+
Object.defineProperty(obj, key, {
|
|
3179
|
+
value: value,
|
|
3180
|
+
enumerable: true,
|
|
3181
|
+
configurable: true,
|
|
3182
|
+
writable: true
|
|
3183
|
+
});
|
|
3184
|
+
} else obj[key] = value;
|
|
3185
|
+
return obj;
|
|
3031
3186
|
}
|
|
3032
|
-
function
|
|
3033
|
-
var
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
} else if (Array.isArray(raw)) {
|
|
3041
|
-
if (raw.length === 0) {
|
|
3042
|
-
throw new Error('model-info: "model" array must contain at least one entry.');
|
|
3187
|
+
function _object_spread$6(target) {
|
|
3188
|
+
for(var i = 1; i < arguments.length; i++){
|
|
3189
|
+
var source = arguments[i] != null ? arguments[i] : {};
|
|
3190
|
+
var ownKeys = Object.keys(source);
|
|
3191
|
+
if (typeof Object.getOwnPropertySymbols === "function") {
|
|
3192
|
+
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
|
|
3193
|
+
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
|
|
3194
|
+
}));
|
|
3043
3195
|
}
|
|
3044
|
-
|
|
3045
|
-
|
|
3196
|
+
ownKeys.forEach(function(key) {
|
|
3197
|
+
_define_property$8(target, key, source[key]);
|
|
3046
3198
|
});
|
|
3047
|
-
} else {
|
|
3048
|
-
throw new TypeError('model-info: "model" must be a string or an array of strings when provided.');
|
|
3049
|
-
}
|
|
3050
|
-
return result;
|
|
3051
|
-
}
|
|
3052
|
-
function parseModelGroupArg(raw) {
|
|
3053
|
-
var result;
|
|
3054
|
-
if (raw == null) {
|
|
3055
|
-
result = undefined;
|
|
3056
|
-
} else if (typeof raw === 'string') {
|
|
3057
|
-
result = requireNonEmptyString$1(raw, 'modelGroup');
|
|
3058
|
-
} else {
|
|
3059
|
-
throw new TypeError('model-info: "modelGroup" must be a string when provided.');
|
|
3060
|
-
}
|
|
3061
|
-
return result;
|
|
3062
|
-
}
|
|
3063
|
-
function parseBooleanArg(raw, label) {
|
|
3064
|
-
var result;
|
|
3065
|
-
if (raw == null) {
|
|
3066
|
-
result = undefined;
|
|
3067
|
-
} else if (typeof raw === 'boolean') {
|
|
3068
|
-
result = raw;
|
|
3069
|
-
} else {
|
|
3070
|
-
throw new TypeError('model-info: "'.concat(label, '" must be a boolean when provided.'));
|
|
3071
|
-
}
|
|
3072
|
-
return result;
|
|
3073
|
-
}
|
|
3074
|
-
function requireNonEmptyString$1(value, label) {
|
|
3075
|
-
if (typeof value !== 'string') {
|
|
3076
|
-
throw new TypeError('model-info: "'.concat(label, '" must be a string.'));
|
|
3077
3199
|
}
|
|
3078
|
-
|
|
3079
|
-
if (trimmed.length === 0) {
|
|
3080
|
-
throw new Error('model-info: "'.concat(label, '" must be a non-empty string.'));
|
|
3081
|
-
}
|
|
3082
|
-
return trimmed;
|
|
3083
|
-
}
|
|
3084
|
-
// MARK: Output builders
|
|
3085
|
-
function buildGroupsOutput(manifest) {
|
|
3086
|
-
return {
|
|
3087
|
-
mode: 'groups',
|
|
3088
|
-
groups: computeGroupCounts(manifest),
|
|
3089
|
-
totalModels: manifest.length,
|
|
3090
|
-
hint: MODEL_INFO_GROUPS_HINT
|
|
3091
|
-
};
|
|
3200
|
+
return target;
|
|
3092
3201
|
}
|
|
3093
|
-
function
|
|
3094
|
-
var
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3202
|
+
function _ts_generator$6(thisArg, body) {
|
|
3203
|
+
var f, y, t, _ = {
|
|
3204
|
+
label: 0,
|
|
3205
|
+
sent: function() {
|
|
3206
|
+
if (t[0] & 1) throw t[1];
|
|
3207
|
+
return t[1];
|
|
3208
|
+
},
|
|
3209
|
+
trys: [],
|
|
3210
|
+
ops: []
|
|
3211
|
+
}, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
|
|
3212
|
+
return d(g, "next", {
|
|
3213
|
+
value: verb(0)
|
|
3214
|
+
}), d(g, "throw", {
|
|
3215
|
+
value: verb(1)
|
|
3216
|
+
}), d(g, "return", {
|
|
3217
|
+
value: verb(2)
|
|
3218
|
+
}), typeof Symbol === "function" && d(g, Symbol.iterator, {
|
|
3219
|
+
value: function() {
|
|
3220
|
+
return this;
|
|
3221
|
+
}
|
|
3222
|
+
}), g;
|
|
3223
|
+
function verb(n) {
|
|
3224
|
+
return function(v) {
|
|
3225
|
+
return step([
|
|
3226
|
+
n,
|
|
3227
|
+
v
|
|
3228
|
+
]);
|
|
3112
3229
|
};
|
|
3113
3230
|
}
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3231
|
+
function step(op) {
|
|
3232
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
3233
|
+
while(g && (g = 0, op[0] && (_ = 0)), _)try {
|
|
3234
|
+
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;
|
|
3235
|
+
if (y = 0, t) op = [
|
|
3236
|
+
op[0] & 2,
|
|
3237
|
+
t.value
|
|
3238
|
+
];
|
|
3239
|
+
switch(op[0]){
|
|
3240
|
+
case 0:
|
|
3241
|
+
case 1:
|
|
3242
|
+
t = op;
|
|
3243
|
+
break;
|
|
3244
|
+
case 4:
|
|
3245
|
+
_.label++;
|
|
3246
|
+
return {
|
|
3247
|
+
value: op[1],
|
|
3248
|
+
done: false
|
|
3249
|
+
};
|
|
3250
|
+
case 5:
|
|
3251
|
+
_.label++;
|
|
3252
|
+
y = op[1];
|
|
3253
|
+
op = [
|
|
3254
|
+
0
|
|
3255
|
+
];
|
|
3256
|
+
continue;
|
|
3257
|
+
case 7:
|
|
3258
|
+
op = _.ops.pop();
|
|
3259
|
+
_.trys.pop();
|
|
3260
|
+
continue;
|
|
3261
|
+
default:
|
|
3262
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
|
|
3263
|
+
_ = 0;
|
|
3264
|
+
continue;
|
|
3265
|
+
}
|
|
3266
|
+
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
|
|
3267
|
+
_.label = op[1];
|
|
3268
|
+
break;
|
|
3269
|
+
}
|
|
3270
|
+
if (op[0] === 6 && _.label < t[1]) {
|
|
3271
|
+
_.label = t[1];
|
|
3272
|
+
t = op;
|
|
3273
|
+
break;
|
|
3274
|
+
}
|
|
3275
|
+
if (t && _.label < t[2]) {
|
|
3276
|
+
_.label = t[2];
|
|
3277
|
+
_.ops.push(op);
|
|
3278
|
+
break;
|
|
3279
|
+
}
|
|
3280
|
+
if (t[2]) _.ops.pop();
|
|
3281
|
+
_.trys.pop();
|
|
3282
|
+
continue;
|
|
3151
3283
|
}
|
|
3284
|
+
op = body.call(thisArg, _);
|
|
3285
|
+
} catch (e) {
|
|
3286
|
+
op = [
|
|
3287
|
+
6,
|
|
3288
|
+
e
|
|
3289
|
+
];
|
|
3290
|
+
y = 0;
|
|
3152
3291
|
} finally{
|
|
3153
|
-
|
|
3154
|
-
throw _iteratorError;
|
|
3155
|
-
}
|
|
3292
|
+
f = t = 0;
|
|
3156
3293
|
}
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
mode: 'multiple',
|
|
3162
|
-
models: matched,
|
|
3163
|
-
notFound: notFound
|
|
3164
|
-
} : {
|
|
3165
|
-
mode: 'multiple',
|
|
3166
|
-
models: matched
|
|
3167
|
-
};
|
|
3168
|
-
} else if (matched.length > 0) {
|
|
3169
|
-
result = {
|
|
3170
|
-
mode: 'single',
|
|
3171
|
-
model: matched[0]
|
|
3294
|
+
if (op[0] & 5) throw op[1];
|
|
3295
|
+
return {
|
|
3296
|
+
value: op[0] ? op[1] : void 0,
|
|
3297
|
+
done: true
|
|
3172
3298
|
};
|
|
3173
|
-
} else {
|
|
3174
|
-
throw new Error(notFound[0].message);
|
|
3175
3299
|
}
|
|
3176
|
-
return result;
|
|
3177
|
-
}
|
|
3178
|
-
// MARK: Row + group helpers
|
|
3179
|
-
function toModelRow(entry, detailed) {
|
|
3180
|
-
return detailed ? entry : toSummaryRow(entry);
|
|
3181
3300
|
}
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3301
|
+
// MARK: Constants
|
|
3302
|
+
/**
|
|
3303
|
+
* Reserved tool name for the built-in `model-roles` static tool.
|
|
3304
|
+
*/ var MODEL_ROLES_TOOL_NAME = 'model-roles';
|
|
3305
|
+
/**
|
|
3306
|
+
* Synthetic call type used in the tool's dispatch identity. Distinct from `model-get`'s `get` so
|
|
3307
|
+
* visibility predicates can target the two independently.
|
|
3308
|
+
*/ var MODEL_ROLES_DISPATCH_CALL = 'roles';
|
|
3309
|
+
/**
|
|
3310
|
+
* Synthetic model type used in the tool's dispatch identity. Mirrors {@link MODEL_GET_DISPATCH_MODEL_TYPE}
|
|
3311
|
+
* — the tool isn't bound to one model type, so the literal "model" stands in.
|
|
3312
|
+
*/ var MODEL_ROLES_DISPATCH_MODEL_TYPE = 'model';
|
|
3313
|
+
/**
|
|
3314
|
+
* Maximum number of keys accepted per `model-roles` call. Role resolution runs the model's real
|
|
3315
|
+
* permission delegate per key (which may itself read parent documents), so this is deliberately
|
|
3316
|
+
* lower than the `model-get` batch size.
|
|
3317
|
+
*/ var MCP_MODEL_ROLES_MAX_KEYS = 25;
|
|
3318
|
+
// MARK: Factory
|
|
3319
|
+
/**
|
|
3320
|
+
* Builds the built-in `model-roles` MCP tool definition.
|
|
3321
|
+
*
|
|
3322
|
+
* Answers "what is this user actually allowed to do with this document?" by running the same
|
|
3323
|
+
* `roleMapForModel()` delegate the permission-checked read/write paths use, and returning the
|
|
3324
|
+
* resolved roles instead of consuming them. Because the model's real delegate runs, derived and
|
|
3325
|
+
* cascading roles appear exactly as the API grants them — there is no second implementation of the
|
|
3326
|
+
* rules to drift.
|
|
3327
|
+
*
|
|
3328
|
+
* Two things it disambiguates that a plain read cannot:
|
|
3329
|
+
* - **Missing vs. forbidden.** A key that resolves to a missing document returns
|
|
3330
|
+
* `exists: false, roles: []` rather than an error, so "the document is not there" reads
|
|
3331
|
+
* differently from "it is there and you have no access" (`exists: true, roles: []`).
|
|
3332
|
+
* - **Full access.** Admin short-circuits that grant the full-access marker come back as
|
|
3333
|
+
* `fullAccess: true` rather than as an opaque enumerated set.
|
|
3334
|
+
*
|
|
3335
|
+
* By default roles are resolved for the calling user. Passing `uid` resolves them for another user
|
|
3336
|
+
* and is gated behind {@link CreateModelRolesToolDeps.canTargetOtherUids}.
|
|
3337
|
+
*
|
|
3338
|
+
* @param deps - Role-map reader, identity resolver, and the target-uid authorization predicate.
|
|
3339
|
+
* @returns A statically-registered {@link McpToolDefinition} ready to be appended to the MCP
|
|
3340
|
+
* server factory's tool registry.
|
|
3341
|
+
*/ function createModelRolesTool(deps) {
|
|
3342
|
+
var handler = function handler(args, ctx) {
|
|
3343
|
+
return modelRolesToolHandler(args, ctx, deps);
|
|
3344
|
+
};
|
|
3345
|
+
var name = MODEL_ROLES_TOOL_NAME;
|
|
3346
|
+
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.';
|
|
3347
|
+
return buildStaticToolDefinition({
|
|
3348
|
+
name: name,
|
|
3349
|
+
description: description,
|
|
3350
|
+
inputSchema: MODEL_ROLES_INPUT_SCHEMA,
|
|
3351
|
+
outputSchema: MODEL_ROLES_OUTPUT_SCHEMA,
|
|
3352
|
+
dispatch: {
|
|
3353
|
+
call: MODEL_ROLES_DISPATCH_CALL,
|
|
3354
|
+
modelType: MODEL_ROLES_DISPATCH_MODEL_TYPE
|
|
3355
|
+
},
|
|
3356
|
+
staticHandler: handler,
|
|
3357
|
+
effectiveReadOnly: true,
|
|
3358
|
+
rule: {
|
|
3359
|
+
requireAuthenticated: true
|
|
3360
|
+
}
|
|
3200
3361
|
});
|
|
3201
3362
|
}
|
|
3363
|
+
// MARK: Handler
|
|
3364
|
+
function modelRolesToolHandler(args, ctx, deps) {
|
|
3365
|
+
return _async_to_generator$6(function() {
|
|
3366
|
+
var result, input, identity, targetUid, keys, resolved, error;
|
|
3367
|
+
return _ts_generator$6(this, function(_state) {
|
|
3368
|
+
switch(_state.label){
|
|
3369
|
+
case 0:
|
|
3370
|
+
_state.trys.push([
|
|
3371
|
+
0,
|
|
3372
|
+
3,
|
|
3373
|
+
,
|
|
3374
|
+
4
|
|
3375
|
+
]);
|
|
3376
|
+
input = parseModelRolesInput(args);
|
|
3377
|
+
identity = deps.resolveIdentity(input.modelType, ctx.auth);
|
|
3378
|
+
if (identity == null) {
|
|
3379
|
+
throw new Error("Unknown modelType: ".concat(input.modelType));
|
|
3380
|
+
}
|
|
3381
|
+
return [
|
|
3382
|
+
4,
|
|
3383
|
+
resolveTargetUid({
|
|
3384
|
+
requestedUid: input.uid,
|
|
3385
|
+
auth: ctx.auth,
|
|
3386
|
+
canTargetOtherUids: deps.canTargetOtherUids
|
|
3387
|
+
})
|
|
3388
|
+
];
|
|
3389
|
+
case 1:
|
|
3390
|
+
targetUid = _state.sent();
|
|
3391
|
+
keys = resolveKeys(input.keys, identity);
|
|
3392
|
+
return [
|
|
3393
|
+
4,
|
|
3394
|
+
deps.readRoleMaps(_object_spread$6({
|
|
3395
|
+
modelType: input.modelType,
|
|
3396
|
+
keys: keys,
|
|
3397
|
+
auth: ctx.auth
|
|
3398
|
+
}, targetUid == null ? {} : {
|
|
3399
|
+
targetUid: targetUid
|
|
3400
|
+
}))
|
|
3401
|
+
];
|
|
3402
|
+
case 2:
|
|
3403
|
+
resolved = _state.sent();
|
|
3404
|
+
result = {
|
|
3405
|
+
content: [
|
|
3406
|
+
{
|
|
3407
|
+
type: 'text',
|
|
3408
|
+
text: JSON.stringify(resolved)
|
|
3409
|
+
}
|
|
3410
|
+
],
|
|
3411
|
+
structuredContent: resolved
|
|
3412
|
+
};
|
|
3413
|
+
return [
|
|
3414
|
+
3,
|
|
3415
|
+
4
|
|
3416
|
+
];
|
|
3417
|
+
case 3:
|
|
3418
|
+
error = _state.sent();
|
|
3419
|
+
result = formatMcpToolErrorResponse(error);
|
|
3420
|
+
return [
|
|
3421
|
+
3,
|
|
3422
|
+
4
|
|
3423
|
+
];
|
|
3424
|
+
case 4:
|
|
3425
|
+
return [
|
|
3426
|
+
2,
|
|
3427
|
+
result
|
|
3428
|
+
];
|
|
3429
|
+
}
|
|
3430
|
+
});
|
|
3431
|
+
})();
|
|
3432
|
+
}
|
|
3202
3433
|
/**
|
|
3203
|
-
*
|
|
3204
|
-
* {@link MODEL_INFO_UNGROUPED_LABEL}. Sorted by count descending, then group name ascending.
|
|
3434
|
+
* Resolves the effective target uid for a call, enforcing the elevated-access gate.
|
|
3205
3435
|
*
|
|
3206
|
-
*
|
|
3207
|
-
*
|
|
3436
|
+
* Requesting your own uid is always allowed and is treated as no target at all, so a caller that
|
|
3437
|
+
* passes their own uid never trips the predicate.
|
|
3208
3438
|
*
|
|
3209
|
-
* @
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3439
|
+
* @param input - The requested uid, the caller's auth, and the authorization predicate.
|
|
3440
|
+
* @returns The uid to resolve as, or `undefined` to resolve as the caller.
|
|
3441
|
+
* @throws {Error} When another user's uid is requested and the predicate denies (or is absent).
|
|
3442
|
+
*/ function resolveTargetUid(input) {
|
|
3443
|
+
return _async_to_generator$6(function() {
|
|
3444
|
+
var requestedUid, auth, canTargetOtherUids, result, allowed, _tmp;
|
|
3445
|
+
return _ts_generator$6(this, function(_state) {
|
|
3446
|
+
switch(_state.label){
|
|
3447
|
+
case 0:
|
|
3448
|
+
requestedUid = input.requestedUid, auth = input.auth, canTargetOtherUids = input.canTargetOtherUids;
|
|
3449
|
+
if (!(requestedUid != null && requestedUid !== (auth === null || auth === void 0 ? void 0 : auth.uid))) return [
|
|
3450
|
+
3,
|
|
3451
|
+
4
|
|
3452
|
+
];
|
|
3453
|
+
if (!(canTargetOtherUids == null)) return [
|
|
3454
|
+
3,
|
|
3455
|
+
1
|
|
3456
|
+
];
|
|
3457
|
+
_tmp = false;
|
|
3458
|
+
return [
|
|
3459
|
+
3,
|
|
3460
|
+
3
|
|
3461
|
+
];
|
|
3462
|
+
case 1:
|
|
3463
|
+
return [
|
|
3464
|
+
4,
|
|
3465
|
+
canTargetOtherUids(auth)
|
|
3466
|
+
];
|
|
3467
|
+
case 2:
|
|
3468
|
+
_tmp = _state.sent();
|
|
3469
|
+
_state.label = 3;
|
|
3470
|
+
case 3:
|
|
3471
|
+
allowed = _tmp;
|
|
3472
|
+
if (!allowed) {
|
|
3473
|
+
throw new Error("model-roles: resolving roles for another user's uid requires elevated access.");
|
|
3474
|
+
}
|
|
3475
|
+
result = requestedUid;
|
|
3476
|
+
_state.label = 4;
|
|
3477
|
+
case 4:
|
|
3478
|
+
return [
|
|
3479
|
+
2,
|
|
3480
|
+
result
|
|
3481
|
+
];
|
|
3482
|
+
}
|
|
3220
3483
|
});
|
|
3221
|
-
});
|
|
3222
|
-
counts.sort(function(a, b) {
|
|
3223
|
-
return b.modelCount - a.modelCount || a.modelGroup.localeCompare(b.modelGroup);
|
|
3224
|
-
});
|
|
3225
|
-
return counts;
|
|
3484
|
+
})();
|
|
3226
3485
|
}
|
|
3227
|
-
function
|
|
3228
|
-
var
|
|
3229
|
-
var
|
|
3230
|
-
var
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
var count = _step.value;
|
|
3234
|
-
if (count.modelGroup.toLowerCase() === lower) {
|
|
3235
|
-
result = count;
|
|
3236
|
-
break;
|
|
3237
|
-
}
|
|
3238
|
-
}
|
|
3239
|
-
} catch (err) {
|
|
3240
|
-
_didIteratorError = true;
|
|
3241
|
-
_iteratorError = err;
|
|
3242
|
-
} finally{
|
|
3243
|
-
try {
|
|
3244
|
-
if (!_iteratorNormalCompletion && _iterator.return != null) {
|
|
3245
|
-
_iterator.return();
|
|
3246
|
-
}
|
|
3247
|
-
} finally{
|
|
3248
|
-
if (_didIteratorError) {
|
|
3249
|
-
throw _iteratorError;
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3486
|
+
function parseModelRolesInput(args) {
|
|
3487
|
+
var modelType = args['modelType'];
|
|
3488
|
+
var keys = args['keys'];
|
|
3489
|
+
var uid = args['uid'];
|
|
3490
|
+
if (typeof modelType !== 'string' || modelType.length === 0) {
|
|
3491
|
+
throw new Error('model-roles: "modelType" is required and must be a non-empty string.');
|
|
3252
3492
|
}
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
function buildModelNotFoundMessage(query, manifest) {
|
|
3256
|
-
var groupMatch = findGroupCount(query, manifest);
|
|
3257
|
-
var message;
|
|
3258
|
-
if (groupMatch == null) {
|
|
3259
|
-
message = 'model-info: no exact match for "'.concat(query, '". Call `model-info` with no arguments to list groups, or pass all:true for the full catalog.');
|
|
3260
|
-
} else {
|
|
3261
|
-
var plural = groupMatch.modelCount === 1 ? '' : 's';
|
|
3262
|
-
message = 'model-info: no exact match for "'.concat(query, '" — did you mean group:"').concat(groupMatch.modelGroup, '" (').concat(groupMatch.modelCount, " model").concat(plural, ')? Use modelGroup:"').concat(groupMatch.modelGroup, '", or all:true for everything.');
|
|
3493
|
+
if (!Array.isArray(keys) || keys.length === 0) {
|
|
3494
|
+
throw new Error('model-roles: "keys" is required and must be a non-empty array.');
|
|
3263
3495
|
}
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
}
|
|
3270
|
-
|
|
3496
|
+
if (keys.length > MCP_MODEL_ROLES_MAX_KEYS) {
|
|
3497
|
+
throw new Error("model-roles: at most ".concat(MCP_MODEL_ROLES_MAX_KEYS, " keys may be resolved per call (received ").concat(keys.length, ")."));
|
|
3498
|
+
}
|
|
3499
|
+
if (uid !== undefined && (typeof uid !== 'string' || uid.length === 0)) {
|
|
3500
|
+
throw new Error('model-roles: "uid" must be a non-empty string when provided.');
|
|
3501
|
+
}
|
|
3502
|
+
var normalizedKeys = keys.map(function(value, index) {
|
|
3503
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
3504
|
+
throw new Error("model-roles: keys[".concat(index, "] must be a non-empty string."));
|
|
3505
|
+
}
|
|
3506
|
+
return value;
|
|
3507
|
+
});
|
|
3508
|
+
return _object_spread$6({
|
|
3509
|
+
modelType: modelType,
|
|
3510
|
+
keys: normalizedKeys
|
|
3511
|
+
}, uid === undefined ? {} : {
|
|
3512
|
+
uid: uid
|
|
3513
|
+
});
|
|
3271
3514
|
}
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
* @param query - Identifier to look up.
|
|
3276
|
-
* @param manifest - Model manifest to search.
|
|
3277
|
-
* @returns The matching entry or `undefined`.
|
|
3278
|
-
*
|
|
3279
|
-
* @__NO_SIDE_EFFECTS__
|
|
3280
|
-
*/ function findModelEntry(query, manifest) {
|
|
3281
|
-
var result;
|
|
3515
|
+
function resolveKeys(keys, identity) {
|
|
3516
|
+
var isRoot = identity.type === 'root';
|
|
3517
|
+
var resolved = [];
|
|
3282
3518
|
var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
|
|
3283
3519
|
try {
|
|
3284
|
-
for(var _iterator =
|
|
3285
|
-
var
|
|
3286
|
-
if (
|
|
3287
|
-
|
|
3288
|
-
|
|
3520
|
+
for(var _iterator = keys[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
|
|
3521
|
+
var value = _step.value;
|
|
3522
|
+
if (value.includes('/')) {
|
|
3523
|
+
resolved.push(value);
|
|
3524
|
+
} else if (isRoot) {
|
|
3525
|
+
resolved.push("".concat(identity.collectionName, "/").concat(value));
|
|
3526
|
+
} else {
|
|
3527
|
+
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, '").'));
|
|
3289
3528
|
}
|
|
3290
3529
|
}
|
|
3291
3530
|
} catch (err) {
|
|
@@ -3302,290 +3541,111 @@ function buildUnknownGroupMessage(group, manifest) {
|
|
|
3302
3541
|
}
|
|
3303
3542
|
}
|
|
3304
3543
|
}
|
|
3305
|
-
return
|
|
3544
|
+
return resolved;
|
|
3306
3545
|
}
|
|
3307
3546
|
// MARK: Schemas
|
|
3308
|
-
var
|
|
3309
|
-
type: 'object',
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
modelGroup: {
|
|
3329
|
-
type: 'string',
|
|
3330
|
-
minLength: 1,
|
|
3331
|
-
description: 'Return the summary list of models in this group (`mode:"list"`). Matched case-insensitively.'
|
|
3332
|
-
},
|
|
3333
|
-
all: {
|
|
3334
|
-
type: 'boolean',
|
|
3335
|
-
description: 'Opt in to the full catalog summary (every model). Never the default — omit to get groups instead.'
|
|
3336
|
-
},
|
|
3337
|
-
fields: {
|
|
3338
|
-
type: 'boolean',
|
|
3339
|
-
description: 'Force (true) or suppress (false) full persisted-field detail. Defaults to summary rows for list mode and full entries for single/multiple modes.'
|
|
3340
|
-
}
|
|
3341
|
-
},
|
|
3342
|
-
additionalProperties: false
|
|
3343
|
-
};
|
|
3344
|
-
// Shared item schema for model-bearing rows. Required props cover the summary form; full entries
|
|
3345
|
-
// add `fields`, `sourceFile`, and `serviceFactory` (allowed as additional properties).
|
|
3346
|
-
var MODEL_ROW_SCHEMA = {
|
|
3347
|
-
type: 'object',
|
|
3348
|
-
required: [
|
|
3349
|
-
'modelType',
|
|
3350
|
-
'modelName',
|
|
3351
|
-
'identityConst',
|
|
3352
|
-
'collectionPrefix',
|
|
3353
|
-
'sourcePackage'
|
|
3354
|
-
],
|
|
3355
|
-
properties: {
|
|
3356
|
-
modelType: {
|
|
3357
|
-
type: 'string'
|
|
3358
|
-
},
|
|
3359
|
-
modelName: {
|
|
3360
|
-
type: 'string'
|
|
3361
|
-
},
|
|
3362
|
-
modelGroup: {
|
|
3363
|
-
type: 'string'
|
|
3364
|
-
},
|
|
3365
|
-
identityConst: {
|
|
3366
|
-
type: 'string'
|
|
3367
|
-
},
|
|
3368
|
-
collectionPrefix: {
|
|
3369
|
-
type: 'string'
|
|
3370
|
-
},
|
|
3371
|
-
parentIdentityConst: {
|
|
3372
|
-
type: 'string'
|
|
3373
|
-
},
|
|
3374
|
-
sourcePackage: {
|
|
3375
|
-
type: 'string'
|
|
3376
|
-
},
|
|
3377
|
-
sourceFile: {
|
|
3378
|
-
type: 'string'
|
|
3379
|
-
},
|
|
3380
|
-
fieldCount: {
|
|
3381
|
-
type: 'integer'
|
|
3382
|
-
},
|
|
3383
|
-
description: {
|
|
3384
|
-
type: 'string'
|
|
3385
|
-
},
|
|
3386
|
-
read: {
|
|
3387
|
-
type: 'string',
|
|
3388
|
-
enum: [
|
|
3389
|
-
'system',
|
|
3390
|
-
'owner',
|
|
3391
|
-
'admin-only',
|
|
3392
|
-
'permissions'
|
|
3393
|
-
]
|
|
3394
|
-
},
|
|
3395
|
-
serviceFactoryExport: {
|
|
3396
|
-
type: 'string'
|
|
3397
|
-
},
|
|
3398
|
-
fields: {
|
|
3399
|
-
type: 'array',
|
|
3400
|
-
items: {
|
|
3401
|
-
type: 'object'
|
|
3402
|
-
}
|
|
3403
|
-
},
|
|
3404
|
-
serviceFactory: {
|
|
3405
|
-
type: 'object',
|
|
3406
|
-
required: [
|
|
3407
|
-
'exportName',
|
|
3408
|
-
'sourceFile'
|
|
3409
|
-
],
|
|
3410
|
-
properties: {
|
|
3411
|
-
exportName: {
|
|
3412
|
-
type: 'string'
|
|
3413
|
-
},
|
|
3414
|
-
sourceFile: {
|
|
3415
|
-
type: 'string'
|
|
3416
|
-
}
|
|
3417
|
-
}
|
|
3418
|
-
}
|
|
3419
|
-
}
|
|
3420
|
-
};
|
|
3421
|
-
/**
|
|
3422
|
-
* JSON-schema for one enum value→label table. Shared with the `enum-info` tool so both advertise the
|
|
3423
|
-
* identical enum shape.
|
|
3424
|
-
*/ var ENUM_TABLE_SCHEMA = {
|
|
3425
|
-
type: 'object',
|
|
3426
|
-
required: [
|
|
3427
|
-
'name',
|
|
3428
|
-
'values'
|
|
3429
|
-
],
|
|
3430
|
-
properties: {
|
|
3431
|
-
name: {
|
|
3432
|
-
type: 'string'
|
|
3433
|
-
},
|
|
3434
|
-
description: {
|
|
3435
|
-
type: 'string'
|
|
3436
|
-
},
|
|
3437
|
-
values: {
|
|
3438
|
-
type: 'array',
|
|
3439
|
-
items: {
|
|
3440
|
-
type: 'object',
|
|
3441
|
-
required: [
|
|
3442
|
-
'name',
|
|
3443
|
-
'value'
|
|
3444
|
-
],
|
|
3445
|
-
properties: {
|
|
3446
|
-
name: {
|
|
3447
|
-
type: 'string'
|
|
3448
|
-
},
|
|
3449
|
-
value: {
|
|
3450
|
-
type: [
|
|
3451
|
-
'string',
|
|
3452
|
-
'number'
|
|
3453
|
-
]
|
|
3454
|
-
},
|
|
3455
|
-
description: {
|
|
3456
|
-
type: 'string'
|
|
3457
|
-
}
|
|
3458
|
-
}
|
|
3547
|
+
var MODEL_ROLES_INPUT_SCHEMA = {
|
|
3548
|
+
type: 'object',
|
|
3549
|
+
required: [
|
|
3550
|
+
'modelType',
|
|
3551
|
+
'keys'
|
|
3552
|
+
],
|
|
3553
|
+
properties: {
|
|
3554
|
+
modelType: {
|
|
3555
|
+
type: 'string',
|
|
3556
|
+
minLength: 1,
|
|
3557
|
+
description: 'Firestore model type to resolve roles on (e.g. "guestbook", "profile").'
|
|
3558
|
+
},
|
|
3559
|
+
keys: {
|
|
3560
|
+
type: 'array',
|
|
3561
|
+
minItems: 1,
|
|
3562
|
+
maxItems: MCP_MODEL_ROLES_MAX_KEYS,
|
|
3563
|
+
description: 'Full keys ("prefix/id") or bare ids (root models only).',
|
|
3564
|
+
items: {
|
|
3565
|
+
type: 'string',
|
|
3566
|
+
minLength: 1
|
|
3459
3567
|
}
|
|
3568
|
+
},
|
|
3569
|
+
uid: {
|
|
3570
|
+
type: 'string',
|
|
3571
|
+
minLength: 1,
|
|
3572
|
+
description: 'Resolve roles as this user instead of the caller. Requires elevated access; passing your own uid is always allowed.'
|
|
3460
3573
|
}
|
|
3461
|
-
}
|
|
3574
|
+
},
|
|
3575
|
+
additionalProperties: false
|
|
3462
3576
|
};
|
|
3463
|
-
|
|
3464
|
-
// (see the MCP SDK's `ToolSchema`), so the variants are expressed via a top-level
|
|
3465
|
-
// object whose nested `oneOf` discriminates by the `mode` literal.
|
|
3466
|
-
var MODEL_INFO_OUTPUT_SCHEMA = {
|
|
3577
|
+
var MODEL_ROLES_OUTPUT_SCHEMA = {
|
|
3467
3578
|
type: 'object',
|
|
3468
3579
|
required: [
|
|
3469
|
-
'
|
|
3580
|
+
'targeted',
|
|
3581
|
+
'results',
|
|
3582
|
+
'errors'
|
|
3470
3583
|
],
|
|
3471
|
-
description: 'Discriminated by `mode`: `groups` (default model groups + counts), `list` (summary/full list for `modelGroup` or `all`), `single` (one `model`), or `multiple` (a `model` array, with misses in `notFound`).',
|
|
3472
3584
|
properties: {
|
|
3473
|
-
|
|
3585
|
+
uid: {
|
|
3474
3586
|
type: 'string',
|
|
3475
|
-
|
|
3476
|
-
'groups',
|
|
3477
|
-
'list',
|
|
3478
|
-
'single',
|
|
3479
|
-
'multiple'
|
|
3480
|
-
]
|
|
3587
|
+
description: 'The uid the roles were resolved for.'
|
|
3481
3588
|
},
|
|
3482
|
-
|
|
3589
|
+
targeted: {
|
|
3590
|
+
type: 'boolean',
|
|
3591
|
+
description: 'True when the roles were resolved for a user other than the caller.'
|
|
3592
|
+
},
|
|
3593
|
+
results: {
|
|
3483
3594
|
type: 'array',
|
|
3484
|
-
description: '
|
|
3595
|
+
description: 'Per-key resolved permission state.',
|
|
3485
3596
|
items: {
|
|
3486
3597
|
type: 'object',
|
|
3487
3598
|
required: [
|
|
3488
|
-
'
|
|
3489
|
-
'
|
|
3599
|
+
'key',
|
|
3600
|
+
'exists',
|
|
3601
|
+
'fullAccess',
|
|
3602
|
+
'roles'
|
|
3490
3603
|
],
|
|
3491
3604
|
properties: {
|
|
3492
|
-
|
|
3605
|
+
key: {
|
|
3493
3606
|
type: 'string'
|
|
3494
3607
|
},
|
|
3495
|
-
|
|
3496
|
-
type: '
|
|
3608
|
+
exists: {
|
|
3609
|
+
type: 'boolean',
|
|
3610
|
+
description: 'Whether the document exists. Roles are only computed for documents that exist.'
|
|
3611
|
+
},
|
|
3612
|
+
fullAccess: {
|
|
3613
|
+
type: 'boolean',
|
|
3614
|
+
description: 'True when the full-access marker was granted; every role is implicitly held and "roles" is empty.'
|
|
3615
|
+
},
|
|
3616
|
+
roles: {
|
|
3617
|
+
type: 'array',
|
|
3618
|
+
items: {
|
|
3619
|
+
type: 'string'
|
|
3620
|
+
},
|
|
3621
|
+
description: 'Granted role names, sorted.'
|
|
3497
3622
|
}
|
|
3498
3623
|
}
|
|
3499
3624
|
}
|
|
3500
3625
|
},
|
|
3501
|
-
|
|
3502
|
-
type: 'integer',
|
|
3503
|
-
description: 'Present when `mode` is `"groups"`. Total models across all groups.'
|
|
3504
|
-
},
|
|
3505
|
-
hint: {
|
|
3506
|
-
type: 'string',
|
|
3507
|
-
description: 'Present when `mode` is `"groups"`. Guidance on how to drill into the catalog.'
|
|
3508
|
-
},
|
|
3509
|
-
models: {
|
|
3510
|
-
type: 'array',
|
|
3511
|
-
description: 'Present when `mode` is `"list"` or `"multiple"`. Summary rows by default; full entries when `fields` requests detail.',
|
|
3512
|
-
items: MODEL_ROW_SCHEMA
|
|
3513
|
-
},
|
|
3514
|
-
modelGroup: {
|
|
3515
|
-
type: 'string',
|
|
3516
|
-
description: 'Present when `mode` is `"list"` from a `modelGroup` filter. The canonical group name.'
|
|
3517
|
-
},
|
|
3518
|
-
model: _object_spread_props$2(_object_spread$6({}, MODEL_ROW_SCHEMA), {
|
|
3519
|
-
description: 'Present when `mode` is `"single"`. The matched model entry (full detail unless `fields:false`).'
|
|
3520
|
-
}),
|
|
3521
|
-
notFound: {
|
|
3626
|
+
errors: {
|
|
3522
3627
|
type: 'array',
|
|
3523
|
-
description: '
|
|
3628
|
+
description: 'Per-key failures. A missing document is NOT an error — it appears in results with exists:false.',
|
|
3524
3629
|
items: {
|
|
3525
3630
|
type: 'object',
|
|
3526
3631
|
required: [
|
|
3527
|
-
'
|
|
3632
|
+
'key',
|
|
3528
3633
|
'message'
|
|
3529
3634
|
],
|
|
3530
3635
|
properties: {
|
|
3531
|
-
|
|
3636
|
+
key: {
|
|
3532
3637
|
type: 'string'
|
|
3533
3638
|
},
|
|
3534
3639
|
message: {
|
|
3535
3640
|
type: 'string'
|
|
3641
|
+
},
|
|
3642
|
+
code: {
|
|
3643
|
+
type: 'string'
|
|
3536
3644
|
}
|
|
3537
3645
|
}
|
|
3538
3646
|
}
|
|
3539
|
-
},
|
|
3540
|
-
enums: {
|
|
3541
|
-
type: 'array',
|
|
3542
|
-
description: 'Value→label tables for the enums referenced by the returned models’ fields. Present only when full field detail is returned (single/multiple modes, or list/all with `fields:true`) and at least one referenced enum is registered.',
|
|
3543
|
-
items: ENUM_TABLE_SCHEMA
|
|
3544
|
-
}
|
|
3545
|
-
},
|
|
3546
|
-
oneOf: [
|
|
3547
|
-
{
|
|
3548
|
-
required: [
|
|
3549
|
-
'groups',
|
|
3550
|
-
'totalModels'
|
|
3551
|
-
],
|
|
3552
|
-
properties: {
|
|
3553
|
-
mode: {
|
|
3554
|
-
const: 'groups'
|
|
3555
|
-
}
|
|
3556
|
-
}
|
|
3557
|
-
},
|
|
3558
|
-
{
|
|
3559
|
-
required: [
|
|
3560
|
-
'models'
|
|
3561
|
-
],
|
|
3562
|
-
properties: {
|
|
3563
|
-
mode: {
|
|
3564
|
-
const: 'list'
|
|
3565
|
-
}
|
|
3566
|
-
}
|
|
3567
|
-
},
|
|
3568
|
-
{
|
|
3569
|
-
required: [
|
|
3570
|
-
'model'
|
|
3571
|
-
],
|
|
3572
|
-
properties: {
|
|
3573
|
-
mode: {
|
|
3574
|
-
const: 'single'
|
|
3575
|
-
}
|
|
3576
|
-
}
|
|
3577
|
-
},
|
|
3578
|
-
{
|
|
3579
|
-
required: [
|
|
3580
|
-
'models'
|
|
3581
|
-
],
|
|
3582
|
-
properties: {
|
|
3583
|
-
mode: {
|
|
3584
|
-
const: 'multiple'
|
|
3585
|
-
}
|
|
3586
|
-
}
|
|
3587
3647
|
}
|
|
3588
|
-
|
|
3648
|
+
}
|
|
3589
3649
|
};
|
|
3590
3650
|
|
|
3591
3651
|
function _define_property$7(obj, key, value) {
|
|
@@ -3614,6 +3674,24 @@ function _object_spread$5(target) {
|
|
|
3614
3674
|
}
|
|
3615
3675
|
return target;
|
|
3616
3676
|
}
|
|
3677
|
+
function ownKeys$2(object, enumerableOnly) {
|
|
3678
|
+
var keys = Object.keys(object);
|
|
3679
|
+
if (Object.getOwnPropertySymbols) {
|
|
3680
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
|
3681
|
+
keys.push.apply(keys, symbols);
|
|
3682
|
+
}
|
|
3683
|
+
return keys;
|
|
3684
|
+
}
|
|
3685
|
+
function _object_spread_props$2(target, source) {
|
|
3686
|
+
source = source != null ? source : {};
|
|
3687
|
+
if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
|
|
3688
|
+
else {
|
|
3689
|
+
ownKeys$2(Object(source)).forEach(function(key) {
|
|
3690
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3693
|
+
return target;
|
|
3694
|
+
}
|
|
3617
3695
|
// MARK: Constants
|
|
3618
3696
|
/**
|
|
3619
3697
|
* Reserved tool name for the built-in `model-decode` static tool.
|
|
@@ -3647,7 +3725,7 @@ function _object_spread$5(target) {
|
|
|
3647
3725
|
return Promise.resolve(modelDecodeToolHandler(args, ctx, deps));
|
|
3648
3726
|
};
|
|
3649
3727
|
var name = MODEL_DECODE_TOOL_NAME;
|
|
3650
|
-
var description = 'Decode a Firestore model key ("prefix/id", or subcollection path "parentPrefix/parentId/childPrefix/childId") into { leaf, ancestors, unresolvedPrefixes } using the registered manifest ('.concat(deps.manifest.length, " model").concat(deps.manifest.length === 1 ? '' : 's', ").");
|
|
3728
|
+
var description = 'Decode a Firestore model key ("prefix/id", or subcollection path "parentPrefix/parentId/childPrefix/childId") into { leaf, ancestors, unresolvedPrefixes, derivedKeys, compositeSource? } using the registered manifest ('.concat(deps.manifest.length, " model").concat(deps.manifest.length === 1 ? '' : 's', "). `derivedKeys` lists composite-key models whose document id is a flattened form of this key, each with its ready-to-use key.");
|
|
3651
3729
|
return buildStaticToolDefinition({
|
|
3652
3730
|
name: name,
|
|
3653
3731
|
description: description,
|
|
@@ -3695,18 +3773,77 @@ function parseModelDecodeInput(args) {
|
|
|
3695
3773
|
}
|
|
3696
3774
|
/**
|
|
3697
3775
|
* Splits `rawKey` on `/`, resolves each `[prefix, id]` pair against the manifest, and
|
|
3698
|
-
* returns the leaf segment + ancestor chain
|
|
3776
|
+
* returns the leaf segment + ancestor chain, plus the composite-key relationships declared
|
|
3777
|
+
* on the manifest: the keys of models derived from this key (`derivedKeys`) and, for a
|
|
3778
|
+
* two-way composite-key leaf, the recovered source key (`compositeSource`).
|
|
3699
3779
|
*
|
|
3700
3780
|
* Mirrors the dbx-cli `decodeFirestoreModelKey` helper structurally; both implementations
|
|
3701
|
-
* must stay in lockstep on segment count and
|
|
3781
|
+
* must stay in lockstep on segment count, resolution order, and composite-key output.
|
|
3702
3782
|
*
|
|
3703
3783
|
* @param rawKey - The Firestore key string.
|
|
3704
3784
|
* @param manifest - The model manifest.
|
|
3705
|
-
* @returns The decoded key with leaf, ancestors, and
|
|
3785
|
+
* @returns The decoded key with leaf, ancestors, unresolved prefixes, and composite-key relationships.
|
|
3706
3786
|
* @throws {Error} When `rawKey` is empty or does not parse into an even number of `prefix/id` segments.
|
|
3707
3787
|
*
|
|
3708
3788
|
* @__NO_SIDE_EFFECTS__
|
|
3709
3789
|
*/ function decodeFirestoreModelKey(rawKey, manifest) {
|
|
3790
|
+
var _leafEntry_compositeKey;
|
|
3791
|
+
var segments = decodeFirestoreModelKeySegments(rawKey, manifest);
|
|
3792
|
+
var leafEntry = segments.leaf.modelType == null ? undefined : findModelEntry(segments.leaf.prefix, manifest);
|
|
3793
|
+
var derivedKeys = leafEntry == null ? [] : findCompositeKeyModelsDerivedFrom(leafEntry, manifest).map(function(entry) {
|
|
3794
|
+
return toDerivedCompositeKey(segments.key, entry);
|
|
3795
|
+
});
|
|
3796
|
+
var compositeSource = (leafEntry === null || leafEntry === void 0 ? void 0 : (_leafEntry_compositeKey = leafEntry.compositeKey) === null || _leafEntry_compositeKey === void 0 ? void 0 : _leafEntry_compositeKey.encoding) === 'two-way' ? decodeTwoWayCompositeSource(segments.leaf.id, manifest) : undefined;
|
|
3797
|
+
return _object_spread$5(_object_spread_props$2(_object_spread$5({}, segments), {
|
|
3798
|
+
derivedKeys: derivedKeys
|
|
3799
|
+
}), compositeSource == null ? {} : {
|
|
3800
|
+
compositeSource: compositeSource
|
|
3801
|
+
});
|
|
3802
|
+
}
|
|
3803
|
+
function toDerivedCompositeKey(sourceKey, entry) {
|
|
3804
|
+
var _ref;
|
|
3805
|
+
var _entry_compositeKey;
|
|
3806
|
+
var encoding = (_ref = (_entry_compositeKey = entry.compositeKey) === null || _entry_compositeKey === void 0 ? void 0 : _entry_compositeKey.encoding) !== null && _ref !== void 0 ? _ref : 'one-way';
|
|
3807
|
+
var flatId = encoding === 'two-way' ? twoWayFlatFirestoreModelKey(sourceKey) : flatFirestoreModelKey(sourceKey);
|
|
3808
|
+
return {
|
|
3809
|
+
key: "".concat(entry.collectionPrefix, "/").concat(flatId),
|
|
3810
|
+
modelType: entry.modelType,
|
|
3811
|
+
modelName: entry.modelName,
|
|
3812
|
+
collectionPrefix: entry.collectionPrefix,
|
|
3813
|
+
encoding: encoding
|
|
3814
|
+
};
|
|
3815
|
+
}
|
|
3816
|
+
/**
|
|
3817
|
+
* Recovers and decodes the source key behind a two-way flattened id.
|
|
3818
|
+
*
|
|
3819
|
+
* @param flatId - The leaf document id of a two-way composite-key model.
|
|
3820
|
+
* @param manifest - The model manifest.
|
|
3821
|
+
* @returns The decoded source key, or `undefined` when the id does not contain a separator or does
|
|
3822
|
+
* not recover to an even number of segments — it was not produced by `twoWayFlatFirestoreModelKey`.
|
|
3823
|
+
*/ function decodeTwoWayCompositeSource(flatId, manifest) {
|
|
3824
|
+
var result;
|
|
3825
|
+
if (flatId.includes('_')) {
|
|
3826
|
+
var sourceKey = inferKeyFromTwoWayFlatFirestoreModelKey(flatId);
|
|
3827
|
+
var segmentCount = sourceKey.split('/').filter(function(s) {
|
|
3828
|
+
return s.length > 0;
|
|
3829
|
+
}).length;
|
|
3830
|
+
if (segmentCount >= 2 && segmentCount % 2 === 0) {
|
|
3831
|
+
result = decodeFirestoreModelKeySegments(sourceKey, manifest);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
return result;
|
|
3835
|
+
}
|
|
3836
|
+
/**
|
|
3837
|
+
* Splits `rawKey` on `/` and resolves each `[prefix, id]` pair against the manifest — the segment
|
|
3838
|
+
* walk shared by {@link decodeFirestoreModelKey} and the two-way composite-source decode.
|
|
3839
|
+
*
|
|
3840
|
+
* @param rawKey - The Firestore key string.
|
|
3841
|
+
* @param manifest - The model manifest.
|
|
3842
|
+
* @returns The decoded key with leaf, ancestors, and any unresolved prefixes.
|
|
3843
|
+
* @throws {Error} When `rawKey` is empty or does not parse into an even number of `prefix/id` segments.
|
|
3844
|
+
*
|
|
3845
|
+
* @__NO_SIDE_EFFECTS__
|
|
3846
|
+
*/ function decodeFirestoreModelKeySegments(rawKey, manifest) {
|
|
3710
3847
|
var trimmed = rawKey.trim();
|
|
3711
3848
|
if (trimmed.length === 0) {
|
|
3712
3849
|
throw new Error('model-decode: key is empty. Provide a Firestore key like `sf/abc123`.');
|
|
@@ -3807,34 +3944,86 @@ var SEGMENT_SCHEMA = {
|
|
|
3807
3944
|
}
|
|
3808
3945
|
}
|
|
3809
3946
|
};
|
|
3810
|
-
var
|
|
3947
|
+
var DECODED_SEGMENTS_PROPERTIES = {
|
|
3948
|
+
key: {
|
|
3949
|
+
type: 'string',
|
|
3950
|
+
description: 'The trimmed input key.'
|
|
3951
|
+
},
|
|
3952
|
+
leaf: SEGMENT_SCHEMA,
|
|
3953
|
+
ancestors: {
|
|
3954
|
+
type: 'array',
|
|
3955
|
+
description: 'Parent segments, root-first.',
|
|
3956
|
+
items: SEGMENT_SCHEMA
|
|
3957
|
+
},
|
|
3958
|
+
unresolvedPrefixes: {
|
|
3959
|
+
type: 'array',
|
|
3960
|
+
description: 'Prefixes that did not match any model in the manifest.',
|
|
3961
|
+
items: {
|
|
3962
|
+
type: 'string'
|
|
3963
|
+
}
|
|
3964
|
+
}
|
|
3965
|
+
};
|
|
3966
|
+
var DERIVED_KEY_SCHEMA = {
|
|
3811
3967
|
type: 'object',
|
|
3812
3968
|
required: [
|
|
3813
3969
|
'key',
|
|
3814
|
-
'
|
|
3815
|
-
'
|
|
3816
|
-
'
|
|
3970
|
+
'modelType',
|
|
3971
|
+
'modelName',
|
|
3972
|
+
'collectionPrefix',
|
|
3973
|
+
'encoding'
|
|
3817
3974
|
],
|
|
3818
3975
|
properties: {
|
|
3819
3976
|
key: {
|
|
3820
3977
|
type: 'string',
|
|
3821
|
-
description: '
|
|
3978
|
+
description: 'Ready-to-use key of the derived document (`<collectionPrefix>/<flattened source key>`).'
|
|
3822
3979
|
},
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
type: 'array',
|
|
3826
|
-
description: 'Parent segments, root-first.',
|
|
3827
|
-
items: SEGMENT_SCHEMA
|
|
3980
|
+
modelType: {
|
|
3981
|
+
type: 'string'
|
|
3828
3982
|
},
|
|
3829
|
-
|
|
3830
|
-
type: '
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3983
|
+
modelName: {
|
|
3984
|
+
type: 'string'
|
|
3985
|
+
},
|
|
3986
|
+
collectionPrefix: {
|
|
3987
|
+
type: 'string'
|
|
3988
|
+
},
|
|
3989
|
+
encoding: {
|
|
3990
|
+
type: 'string',
|
|
3991
|
+
enum: [
|
|
3992
|
+
'one-way',
|
|
3993
|
+
'two-way'
|
|
3994
|
+
],
|
|
3995
|
+
description: 'Flat-key encoding: `one-way` strips slashes, `two-way` replaces them with underscores.'
|
|
3835
3996
|
}
|
|
3836
3997
|
}
|
|
3837
3998
|
};
|
|
3999
|
+
var MODEL_DECODE_OUTPUT_SCHEMA = {
|
|
4000
|
+
type: 'object',
|
|
4001
|
+
required: [
|
|
4002
|
+
'key',
|
|
4003
|
+
'leaf',
|
|
4004
|
+
'ancestors',
|
|
4005
|
+
'unresolvedPrefixes',
|
|
4006
|
+
'derivedKeys'
|
|
4007
|
+
],
|
|
4008
|
+
properties: _object_spread_props$2(_object_spread$5({}, DECODED_SEGMENTS_PROPERTIES), {
|
|
4009
|
+
derivedKeys: {
|
|
4010
|
+
type: 'array',
|
|
4011
|
+
description: 'Composite-key models whose document id is derived from this key (from `@dbxModelCompositeKey`), each with its ready-to-use key. Empty when none apply.',
|
|
4012
|
+
items: DERIVED_KEY_SCHEMA
|
|
4013
|
+
},
|
|
4014
|
+
compositeSource: {
|
|
4015
|
+
type: 'object',
|
|
4016
|
+
description: 'When the leaf is a two-way composite-key model, the source key recovered from its id, decoded. Absent otherwise.',
|
|
4017
|
+
required: [
|
|
4018
|
+
'key',
|
|
4019
|
+
'leaf',
|
|
4020
|
+
'ancestors',
|
|
4021
|
+
'unresolvedPrefixes'
|
|
4022
|
+
],
|
|
4023
|
+
properties: DECODED_SEGMENTS_PROPERTIES
|
|
4024
|
+
}
|
|
4025
|
+
})
|
|
4026
|
+
};
|
|
3838
4027
|
|
|
3839
4028
|
// MARK: Constants
|
|
3840
4029
|
/**
|
|
@@ -4722,21 +4911,35 @@ function cliTokenToolHandler(args, ctx, deps) {
|
|
|
4722
4911
|
});
|
|
4723
4912
|
})();
|
|
4724
4913
|
}
|
|
4725
|
-
|
|
4914
|
+
/**
|
|
4915
|
+
* Renders the tool's output, including the command the target machine runs verbatim.
|
|
4916
|
+
*
|
|
4917
|
+
* `--env` is appended whenever the mint supplied an `envName`. Without it the rendered command is
|
|
4918
|
+
* only correct on a machine that already has the right env ACTIVE — `auth handoff` takes the issuer
|
|
4919
|
+
* to redeem against from the active env, so a bare machine fails `AUTH_HANDOFF_NO_ISSUER` and a
|
|
4920
|
+
* machine pointed at another env sends the claim to the wrong issuer. Naming the env also
|
|
4921
|
+
* instantiates it from its built-in default template, which a name alone does not do.
|
|
4922
|
+
*
|
|
4923
|
+
* @param minted - The mint result from the app-supplied minter.
|
|
4924
|
+
* @returns The tool output payload.
|
|
4925
|
+
*/ function buildOutput(minted) {
|
|
4726
4926
|
var _minted_cliName;
|
|
4727
4927
|
var cliName = (_minted_cliName = minted.cliName) !== null && _minted_cliName !== void 0 ? _minted_cliName : '<cli>';
|
|
4928
|
+
var envArgument = minted.envName == null ? '' : " --env ".concat(minted.envName);
|
|
4728
4929
|
return _object_spread$3({
|
|
4729
4930
|
claimCode: minted.claimCode,
|
|
4730
4931
|
claimExpiresAt: minted.claimExpiresAt,
|
|
4731
4932
|
expiresAt: minted.expiresAt,
|
|
4732
4933
|
scope: minted.scope,
|
|
4733
|
-
handoffCommand: "".concat(cliName, " auth handoff ").concat(minted.claimCode)
|
|
4934
|
+
handoffCommand: "".concat(cliName, " auth handoff ").concat(minted.claimCode).concat(envArgument)
|
|
4734
4935
|
}, minted.cliName == null ? {} : {
|
|
4735
4936
|
cliName: minted.cliName
|
|
4736
4937
|
}, minted.downloadUrl == null ? {} : {
|
|
4737
4938
|
downloadUrl: minted.downloadUrl
|
|
4738
4939
|
}, minted.downloadSha256 == null ? {} : {
|
|
4739
4940
|
downloadSha256: minted.downloadSha256
|
|
4941
|
+
}, minted.envName == null ? {} : {
|
|
4942
|
+
envName: minted.envName
|
|
4740
4943
|
});
|
|
4741
4944
|
}
|
|
4742
4945
|
// Reads the optional `scopes` input as a string array, ignoring anything that is not a non-empty string.
|
|
@@ -4827,6 +5030,9 @@ var CLI_TOKEN_OUTPUT_SCHEMA = {
|
|
|
4827
5030
|
downloadSha256: {
|
|
4828
5031
|
type: 'string'
|
|
4829
5032
|
},
|
|
5033
|
+
envName: {
|
|
5034
|
+
type: 'string'
|
|
5035
|
+
},
|
|
4830
5036
|
handoffCommand: {
|
|
4831
5037
|
type: 'string'
|
|
4832
5038
|
}
|
|
@@ -7197,15 +7403,19 @@ var McpServerFactoryService_1;
|
|
|
7197
7403
|
this._resolveManifest();
|
|
7198
7404
|
var staticTools = [];
|
|
7199
7405
|
var getService = this.modelApiGetService;
|
|
7406
|
+
var modelManifest = this._cachedManifestModels;
|
|
7407
|
+
var enumManifest = this._cachedManifestEnums;
|
|
7200
7408
|
if (getService != null) {
|
|
7201
|
-
staticTools.push(createModelGetTool({
|
|
7409
|
+
staticTools.push(createModelGetTool(_object_spread$1({
|
|
7202
7410
|
readDocuments: function readDocuments(modelType, keys, auth) {
|
|
7203
7411
|
return getService.readDocuments(modelType, keys, auth);
|
|
7204
7412
|
},
|
|
7205
7413
|
resolveIdentity: function resolveIdentity(modelType, auth) {
|
|
7206
7414
|
return getService.getModelIdentity(modelType, auth);
|
|
7207
7415
|
}
|
|
7208
|
-
}
|
|
7416
|
+
}, modelManifest == null ? {} : {
|
|
7417
|
+
manifest: modelManifest
|
|
7418
|
+
})), createModelRolesTool({
|
|
7209
7419
|
readRoleMaps: function readRoleMaps(params) {
|
|
7210
7420
|
return getService.readRoleMaps(params);
|
|
7211
7421
|
},
|
|
@@ -7229,8 +7439,6 @@ var McpServerFactoryService_1;
|
|
|
7229
7439
|
}));
|
|
7230
7440
|
}
|
|
7231
7441
|
}
|
|
7232
|
-
var modelManifest = this._cachedManifestModels;
|
|
7233
|
-
var enumManifest = this._cachedManifestEnums;
|
|
7234
7442
|
if (modelManifest != null && modelManifest.length > 0) {
|
|
7235
7443
|
staticTools.push(createModelInfoTool(_object_spread$1({
|
|
7236
7444
|
manifest: modelManifest
|
|
@@ -9020,4 +9228,4 @@ function _unsupported_iterable_to_array(o, minLen) {
|
|
|
9020
9228
|
};
|
|
9021
9229
|
}
|
|
9022
9230
|
|
|
9023
|
-
export { BATCH_EXECUTE_DISPATCH_CALL, BATCH_EXECUTE_DISPATCH_MODEL_TYPE, BATCH_EXECUTE_TOOL_NAME, CLI_TOKEN_DISPATCH_CALL, CLI_TOKEN_DISPATCH_MODEL_TYPE, CLI_TOKEN_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_CLI_TOKEN_MINTER, MCP_MANIFEST_VERSION, MCP_MODEL_GET_BATCH_SIZE, MCP_MODEL_ROLES_MAX_KEYS, MCP_MODEL_ROLES_TARGET_UID_PREDICATE, 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, MODEL_ROLES_DISPATCH_CALL, MODEL_ROLES_DISPATCH_MODEL_TYPE, MODEL_ROLES_TOOL_NAME, 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, createCliTokenTool, createEnumInfoTool, createModelDecodeTool, createModelGetTool, createModelInfoTool, createModelRolesTool, createUrlModelsTool, decodeFirestoreModelKey, extractMcpReasonFromArgs, findModelEntry, formatMcpToolErrorResponse, formatMcpToolResponse, generateMcpToolDefinitions, handleStreamableHttpMcpRequest, matchRouteManifestUrl, mcpManifestKey, mcpModuleMetadata, mcpSchemaDeclaresProperty, noopMcpAnalyticsService, parseUrlModelsPathname, readUrlModelsImpersonationUid, resolveEffectiveReadOnly, resolveEnumInfoOutput, resolveMcpReasonParameterConfig, resolveMcpToolAnnotations, resolveRequiredScope, validateMcpToolName };
|
|
9231
|
+
export { BATCH_EXECUTE_DISPATCH_CALL, BATCH_EXECUTE_DISPATCH_MODEL_TYPE, BATCH_EXECUTE_TOOL_NAME, CLI_TOKEN_DISPATCH_CALL, CLI_TOKEN_DISPATCH_MODEL_TYPE, CLI_TOKEN_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_CLI_TOKEN_MINTER, MCP_MANIFEST_VERSION, MCP_MODEL_GET_BATCH_SIZE, MCP_MODEL_ROLES_MAX_KEYS, MCP_MODEL_ROLES_TARGET_UID_PREDICATE, 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, MODEL_ROLES_DISPATCH_CALL, MODEL_ROLES_DISPATCH_MODEL_TYPE, MODEL_ROLES_TOOL_NAME, 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, createCliTokenTool, createEnumInfoTool, createModelDecodeTool, createModelGetTool, createModelInfoTool, createModelRolesTool, createUrlModelsTool, decodeFirestoreModelKey, decodeFirestoreModelKeySegments, extractMcpReasonFromArgs, findCompositeKeyModelsDerivedFrom, findModelEntry, formatMcpToolErrorResponse, formatMcpToolResponse, generateMcpToolDefinitions, handleStreamableHttpMcpRequest, isCompositeKeyModelDerivedFrom, matchRouteManifestUrl, mcpManifestKey, mcpModuleMetadata, mcpSchemaDeclaresProperty, noopMcpAnalyticsService, parseUrlModelsPathname, readUrlModelsImpersonationUid, resolveEffectiveReadOnly, resolveEnumInfoOutput, resolveMcpReasonParameterConfig, resolveMcpToolAnnotations, resolveRequiredScope, validateMcpToolName };
|