@forestadmin/mcp-server 0.1.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/README.md +128 -0
- package/dist/__mocks__/version.d.ts +3 -0
- package/dist/__mocks__/version.js +7 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +14 -0
- package/dist/factory.d.ts +51 -0
- package/dist/factory.js +40 -0
- package/dist/forest-oauth-provider.d.ts +44 -0
- package/dist/forest-oauth-provider.js +253 -0
- package/dist/forest-oauth-provider.test.d.ts +2 -0
- package/dist/forest-oauth-provider.test.js +590 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +13 -0
- package/dist/mcp-paths.d.ts +5 -0
- package/dist/mcp-paths.js +11 -0
- package/dist/polyfills.d.ts +12 -0
- package/dist/polyfills.js +27 -0
- package/dist/schemas/filter.d.ts +4 -0
- package/dist/schemas/filter.js +70 -0
- package/dist/schemas/filter.test.d.ts +2 -0
- package/dist/schemas/filter.test.js +234 -0
- package/dist/server.d.ts +87 -0
- package/dist/server.js +341 -0
- package/dist/server.test.d.ts +2 -0
- package/dist/server.test.js +901 -0
- package/dist/test-utils/mock-server.d.ts +62 -0
- package/dist/test-utils/mock-server.js +187 -0
- package/dist/tools/list.d.ts +4 -0
- package/dist/tools/list.js +98 -0
- package/dist/tools/list.test.d.ts +2 -0
- package/dist/tools/list.test.js +385 -0
- package/dist/utils/activity-logs-creator.d.ts +9 -0
- package/dist/utils/activity-logs-creator.js +65 -0
- package/dist/utils/activity-logs-creator.test.d.ts +2 -0
- package/dist/utils/activity-logs-creator.test.js +239 -0
- package/dist/utils/agent-caller.d.ts +13 -0
- package/dist/utils/agent-caller.js +24 -0
- package/dist/utils/agent-caller.test.d.ts +2 -0
- package/dist/utils/agent-caller.test.js +102 -0
- package/dist/utils/error-parser.d.ts +10 -0
- package/dist/utils/error-parser.js +56 -0
- package/dist/utils/error-parser.test.d.ts +2 -0
- package/dist/utils/error-parser.test.js +124 -0
- package/dist/utils/schema-fetcher.d.ts +53 -0
- package/dist/utils/schema-fetcher.js +85 -0
- package/dist/utils/schema-fetcher.test.d.ts +2 -0
- package/dist/utils/schema-fetcher.test.js +212 -0
- package/dist/utils/sse-error-logger.d.ts +14 -0
- package/dist/utils/sse-error-logger.js +112 -0
- package/dist/utils/tool-with-logging.d.ts +44 -0
- package/dist/utils/tool-with-logging.js +66 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.js +43 -0
- package/package.json +49 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
type MockRouteHandler<T> = T | ((url: string, options?: RequestInit) => T);
|
|
2
|
+
/**
|
|
3
|
+
* Mock server class for mocking fetch requests to specific routes
|
|
4
|
+
* Also intercepts superagent requests used by forestadmin-client
|
|
5
|
+
*/
|
|
6
|
+
export default class MockServer {
|
|
7
|
+
private routes;
|
|
8
|
+
private mockFn;
|
|
9
|
+
private superagentMocked;
|
|
10
|
+
constructor();
|
|
11
|
+
/**
|
|
12
|
+
* Setup superagent mocking to intercept HTTP requests made by forestadmin-client
|
|
13
|
+
*/
|
|
14
|
+
setupSuperagentMock(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Restore original superagent methods
|
|
17
|
+
*/
|
|
18
|
+
restoreSuperagent(): void;
|
|
19
|
+
private handleSuperagentRequest;
|
|
20
|
+
/**
|
|
21
|
+
* Register a route with a JSON payload or a function that returns a payload
|
|
22
|
+
*/
|
|
23
|
+
route<T>(pattern: string | RegExp, response: MockRouteHandler<T>, options?: {
|
|
24
|
+
method?: string;
|
|
25
|
+
status?: number;
|
|
26
|
+
}): this;
|
|
27
|
+
/**
|
|
28
|
+
* Register a GET route
|
|
29
|
+
*/
|
|
30
|
+
get<T>(pattern: string | RegExp, response: MockRouteHandler<T>, status?: number): this;
|
|
31
|
+
/**
|
|
32
|
+
* Register a POST route
|
|
33
|
+
*/
|
|
34
|
+
post<T>(pattern: string | RegExp, response: MockRouteHandler<T>, status?: number): this;
|
|
35
|
+
/**
|
|
36
|
+
* Register a PUT route
|
|
37
|
+
*/
|
|
38
|
+
put<T>(pattern: string | RegExp, response: MockRouteHandler<T>, status?: number): this;
|
|
39
|
+
/**
|
|
40
|
+
* Register a DELETE route
|
|
41
|
+
*/
|
|
42
|
+
delete<T>(pattern: string | RegExp, response: MockRouteHandler<T>, status?: number): this;
|
|
43
|
+
/**
|
|
44
|
+
* Register a PATCH route
|
|
45
|
+
*/
|
|
46
|
+
patch<T>(pattern: string | RegExp, response: MockRouteHandler<T>, status?: number): this;
|
|
47
|
+
/**
|
|
48
|
+
* Get the mock function to use as global.fetch
|
|
49
|
+
*/
|
|
50
|
+
get fetch(): jest.Mock;
|
|
51
|
+
/**
|
|
52
|
+
* Clear mock call history
|
|
53
|
+
*/
|
|
54
|
+
clear(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Reset all routes
|
|
57
|
+
*/
|
|
58
|
+
reset(): void;
|
|
59
|
+
private handleRequest;
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=mock-server.d.ts.map
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
// Store original superagent methods for restoration
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
let originalSuperagent = null;
|
|
6
|
+
/**
|
|
7
|
+
* Mock server class for mocking fetch requests to specific routes
|
|
8
|
+
* Also intercepts superagent requests used by forestadmin-client
|
|
9
|
+
*/
|
|
10
|
+
class MockServer {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.routes = [];
|
|
13
|
+
this.superagentMocked = false;
|
|
14
|
+
this.mockFn = jest.fn((url, options) => {
|
|
15
|
+
return this.handleRequest(url, options);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Setup superagent mocking to intercept HTTP requests made by forestadmin-client
|
|
20
|
+
*/
|
|
21
|
+
setupSuperagentMock() {
|
|
22
|
+
if (this.superagentMocked)
|
|
23
|
+
return;
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires, global-require
|
|
25
|
+
const superagent = require('superagent');
|
|
26
|
+
if (!originalSuperagent) {
|
|
27
|
+
originalSuperagent = { ...superagent };
|
|
28
|
+
}
|
|
29
|
+
// Create mock request builder using arrow function to preserve 'this'
|
|
30
|
+
const createMockRequest = (method, reqUrl) => {
|
|
31
|
+
let headers = {};
|
|
32
|
+
let body = null;
|
|
33
|
+
const mockRequest = {
|
|
34
|
+
set: (key, value) => {
|
|
35
|
+
if (typeof key === 'object') {
|
|
36
|
+
headers = { ...headers, ...key };
|
|
37
|
+
}
|
|
38
|
+
else if (value !== undefined) {
|
|
39
|
+
headers[key] = value;
|
|
40
|
+
}
|
|
41
|
+
return mockRequest;
|
|
42
|
+
},
|
|
43
|
+
timeout: () => mockRequest,
|
|
44
|
+
send: async (data) => {
|
|
45
|
+
body = data;
|
|
46
|
+
return this.handleSuperagentRequest(method, reqUrl, headers, body);
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
return mockRequest;
|
|
50
|
+
};
|
|
51
|
+
// Override superagent methods
|
|
52
|
+
superagent.get = (reqUrl) => createMockRequest('GET', reqUrl);
|
|
53
|
+
superagent.post = (reqUrl) => createMockRequest('POST', reqUrl);
|
|
54
|
+
superagent.put = (reqUrl) => createMockRequest('PUT', reqUrl);
|
|
55
|
+
superagent.delete = (reqUrl) => createMockRequest('DELETE', reqUrl);
|
|
56
|
+
this.superagentMocked = true;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Restore original superagent methods
|
|
60
|
+
*/
|
|
61
|
+
restoreSuperagent() {
|
|
62
|
+
if (!this.superagentMocked || !originalSuperagent)
|
|
63
|
+
return;
|
|
64
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires, global-require
|
|
65
|
+
const superagent = require('superagent');
|
|
66
|
+
Object.assign(superagent, originalSuperagent);
|
|
67
|
+
this.superagentMocked = false;
|
|
68
|
+
}
|
|
69
|
+
async handleSuperagentRequest(method, reqUrl, headers, body) {
|
|
70
|
+
for (const route of this.routes) {
|
|
71
|
+
const patternMatch = typeof route.pattern === 'string'
|
|
72
|
+
? reqUrl.includes(route.pattern)
|
|
73
|
+
: route.pattern.test(reqUrl);
|
|
74
|
+
const methodMatch = !route.method || route.method.toUpperCase() === method.toUpperCase();
|
|
75
|
+
if (patternMatch && methodMatch) {
|
|
76
|
+
const payload = typeof route.response === 'function'
|
|
77
|
+
? route.response(reqUrl, {
|
|
78
|
+
method,
|
|
79
|
+
headers: headers,
|
|
80
|
+
body: body,
|
|
81
|
+
})
|
|
82
|
+
: route.response;
|
|
83
|
+
const status = route.status ?? 200;
|
|
84
|
+
return { body: payload, status };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// No match found - throw error like superagent would for 404
|
|
88
|
+
const error = new Error(`Not Found: ${method} ${reqUrl}`);
|
|
89
|
+
error.response = {
|
|
90
|
+
status: 404,
|
|
91
|
+
body: { errors: [{ detail: 'Not found' }] },
|
|
92
|
+
};
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Register a route with a JSON payload or a function that returns a payload
|
|
97
|
+
*/
|
|
98
|
+
route(pattern, response, options = {}) {
|
|
99
|
+
this.routes.push({
|
|
100
|
+
pattern,
|
|
101
|
+
method: options.method,
|
|
102
|
+
response,
|
|
103
|
+
status: options.status ?? 200,
|
|
104
|
+
});
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Register a GET route
|
|
109
|
+
*/
|
|
110
|
+
get(pattern, response, status) {
|
|
111
|
+
return this.route(pattern, response, { method: 'GET', status });
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Register a POST route
|
|
115
|
+
*/
|
|
116
|
+
post(pattern, response, status) {
|
|
117
|
+
return this.route(pattern, response, { method: 'POST', status });
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Register a PUT route
|
|
121
|
+
*/
|
|
122
|
+
put(pattern, response, status) {
|
|
123
|
+
return this.route(pattern, response, { method: 'PUT', status });
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Register a DELETE route
|
|
127
|
+
*/
|
|
128
|
+
delete(pattern, response, status) {
|
|
129
|
+
return this.route(pattern, response, { method: 'DELETE', status });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Register a PATCH route
|
|
133
|
+
*/
|
|
134
|
+
patch(pattern, response, status) {
|
|
135
|
+
return this.route(pattern, response, { method: 'PATCH', status });
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get the mock function to use as global.fetch
|
|
139
|
+
*/
|
|
140
|
+
get fetch() {
|
|
141
|
+
return this.mockFn;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Clear mock call history
|
|
145
|
+
*/
|
|
146
|
+
clear() {
|
|
147
|
+
this.mockFn.mockClear();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Reset all routes
|
|
151
|
+
*/
|
|
152
|
+
reset() {
|
|
153
|
+
this.routes = [];
|
|
154
|
+
this.mockFn.mockClear();
|
|
155
|
+
}
|
|
156
|
+
handleRequest(url, options) {
|
|
157
|
+
const urlString = url.toString();
|
|
158
|
+
const method = options?.method || 'GET';
|
|
159
|
+
for (const route of this.routes) {
|
|
160
|
+
const patternMatch = typeof route.pattern === 'string'
|
|
161
|
+
? urlString.includes(route.pattern)
|
|
162
|
+
: route.pattern.test(urlString);
|
|
163
|
+
const methodMatch = !route.method || route.method.toUpperCase() === method.toUpperCase();
|
|
164
|
+
if (patternMatch && methodMatch) {
|
|
165
|
+
const payload = typeof route.response === 'function'
|
|
166
|
+
? route.response(url, options)
|
|
167
|
+
: route.response;
|
|
168
|
+
const status = route.status ?? 200;
|
|
169
|
+
return Promise.resolve({
|
|
170
|
+
ok: status >= 200 && status < 300,
|
|
171
|
+
status,
|
|
172
|
+
statusText: status === 200 ? 'OK' : 'Error',
|
|
173
|
+
json: () => Promise.resolve(payload),
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Default: return 404 for unknown endpoints
|
|
178
|
+
return Promise.resolve({
|
|
179
|
+
ok: false,
|
|
180
|
+
status: 404,
|
|
181
|
+
statusText: 'Not Found',
|
|
182
|
+
json: () => Promise.resolve({ error: 'Not found' }),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.default = MockServer;
|
|
187
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9jay1zZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC11dGlscy9tb2NrLXNlcnZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVNBLG9EQUFvRDtBQUNwRCw4REFBOEQ7QUFDOUQsSUFBSSxrQkFBa0IsR0FBUSxJQUFJLENBQUM7QUFFbkM7OztHQUdHO0FBQ0gsTUFBcUIsVUFBVTtJQUs3QjtRQUpRLFdBQU0sR0FBeUIsRUFBRSxDQUFDO1FBRWxDLHFCQUFnQixHQUFHLEtBQUssQ0FBQztRQUcvQixJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFXLEVBQUUsT0FBcUIsRUFBRSxFQUFFO1lBQzNELE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxtQkFBbUI7UUFDakIsSUFBSSxJQUFJLENBQUMsZ0JBQWdCO1lBQUUsT0FBTztRQUVsQyxxSEFBcUg7UUFDckgsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRXpDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQ3hCLGtCQUFrQixHQUFHLEVBQUUsR0FBRyxVQUFVLEVBQUUsQ0FBQztRQUN6QyxDQUFDO1FBRUQsc0VBQXNFO1FBQ3RFLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxNQUFjLEVBQUUsTUFBYyxFQUFFLEVBQUU7WUFDM0QsSUFBSSxPQUFPLEdBQTJCLEVBQUUsQ0FBQztZQUN6QyxJQUFJLElBQUksR0FBWSxJQUFJLENBQUM7WUFFekIsTUFBTSxXQUFXLEdBQUc7Z0JBQ2xCLEdBQUcsRUFBRSxDQUFDLEdBQW9DLEVBQUUsS0FBYyxFQUFFLEVBQUU7b0JBQzVELElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFFLENBQUM7d0JBQzVCLE9BQU8sR0FB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
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Logger } from '../server';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
export default function declareListTool(mcpServer: McpServer, forestServerUrl: string, logger: Logger, collectionNames?: string[]): void;
|
|
4
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = declareListTool;
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const filter_js_1 = __importDefault(require("../schemas/filter.js"));
|
|
9
|
+
const activity_logs_creator_js_1 = __importDefault(require("../utils/activity-logs-creator.js"));
|
|
10
|
+
const agent_caller_js_1 = __importDefault(require("../utils/agent-caller.js"));
|
|
11
|
+
const error_parser_js_1 = __importDefault(require("../utils/error-parser.js"));
|
|
12
|
+
const schema_fetcher_js_1 = require("../utils/schema-fetcher.js");
|
|
13
|
+
const tool_with_logging_js_1 = __importDefault(require("../utils/tool-with-logging.js"));
|
|
14
|
+
// Preprocess to handle LLM sending filters as JSON string instead of object
|
|
15
|
+
const filtersWithPreprocess = zod_1.z.preprocess(val => {
|
|
16
|
+
if (typeof val !== 'string')
|
|
17
|
+
return val;
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(val);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Return original value to let Zod validation produce a proper error
|
|
23
|
+
return val;
|
|
24
|
+
}
|
|
25
|
+
}, filter_js_1.default);
|
|
26
|
+
const listArgumentSchema = zod_1.z.object({
|
|
27
|
+
collectionName: zod_1.z.string(),
|
|
28
|
+
search: zod_1.z.string().optional(),
|
|
29
|
+
filters: filtersWithPreprocess
|
|
30
|
+
.describe('Filters to apply on collection. To filter on a nested field, use "@@@" to separate relations, e.g. "relationName@@@fieldName". One level deep max.')
|
|
31
|
+
.optional(),
|
|
32
|
+
sort: zod_1.z
|
|
33
|
+
.object({
|
|
34
|
+
field: zod_1.z.string(),
|
|
35
|
+
ascending: zod_1.z.boolean(),
|
|
36
|
+
})
|
|
37
|
+
.optional(),
|
|
38
|
+
shouldSearchInRelation: zod_1.z
|
|
39
|
+
.boolean()
|
|
40
|
+
.optional()
|
|
41
|
+
.default(false)
|
|
42
|
+
.describe('Whether to search also on related collections'),
|
|
43
|
+
fields: zod_1.z
|
|
44
|
+
.array(zod_1.z.string())
|
|
45
|
+
.describe('Fields to include in the list. Reduces the amount of data returned. For sub fields, use "@@@" to separate relations, e.g. "relationName@@@fieldName".')
|
|
46
|
+
.optional(),
|
|
47
|
+
pagination: zod_1.z
|
|
48
|
+
.object({
|
|
49
|
+
size: zod_1.z.number().default(15).optional(),
|
|
50
|
+
number: zod_1.z.number().default(1).optional(),
|
|
51
|
+
})
|
|
52
|
+
.optional(),
|
|
53
|
+
});
|
|
54
|
+
function createListArgumentShape(collectionNames) {
|
|
55
|
+
return {
|
|
56
|
+
...listArgumentSchema.shape,
|
|
57
|
+
collectionName: collectionNames.length > 0 ? zod_1.z.enum(collectionNames) : zod_1.z.string(),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function declareListTool(mcpServer, forestServerUrl, logger, collectionNames = []) {
|
|
61
|
+
const listArgumentShape = createListArgumentShape(collectionNames);
|
|
62
|
+
(0, tool_with_logging_js_1.default)(mcpServer, 'list', {
|
|
63
|
+
title: 'List records from a collection',
|
|
64
|
+
description: 'Retrieve a list of records from the specified collection.',
|
|
65
|
+
inputSchema: listArgumentShape,
|
|
66
|
+
}, async (options, extra) => {
|
|
67
|
+
const { rpcClient } = await (0, agent_caller_js_1.default)(extra);
|
|
68
|
+
let actionType = 'index';
|
|
69
|
+
if (options.search) {
|
|
70
|
+
actionType = 'search';
|
|
71
|
+
}
|
|
72
|
+
else if (options.filters) {
|
|
73
|
+
actionType = 'filter';
|
|
74
|
+
}
|
|
75
|
+
await (0, activity_logs_creator_js_1.default)(forestServerUrl, extra, actionType, {
|
|
76
|
+
collectionName: options.collectionName,
|
|
77
|
+
});
|
|
78
|
+
try {
|
|
79
|
+
const result = await rpcClient
|
|
80
|
+
.collection(options.collectionName)
|
|
81
|
+
.list(options);
|
|
82
|
+
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Parse error text if it's a JSON string from the agent
|
|
86
|
+
const errorDetail = (0, error_parser_js_1.default)(error);
|
|
87
|
+
if (errorDetail?.includes('Invalid sort')) {
|
|
88
|
+
const fields = (0, schema_fetcher_js_1.getFieldsOfCollection)(await (0, schema_fetcher_js_1.fetchForestSchema)(forestServerUrl), options.collectionName);
|
|
89
|
+
throw new Error(`The sort field provided is invalid for this collection. Available fields for the collection ${options.collectionName} are: ${fields
|
|
90
|
+
.filter(field => field.isSortable)
|
|
91
|
+
.map(field => field.field)
|
|
92
|
+
.join(', ')}.`);
|
|
93
|
+
}
|
|
94
|
+
throw errorDetail ? new Error(errorDetail) : error;
|
|
95
|
+
}
|
|
96
|
+
}, logger);
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90b29scy9saXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBb0VBLGtDQTZEQztBQTdIRCw2QkFBd0I7QUFFeEIscUVBQWdEO0FBQ2hELGlHQUFrRTtBQUNsRSwrRUFBbUQ7QUFDbkQsK0VBQXVEO0FBQ3ZELGtFQUFzRjtBQUN0Rix5RkFBb0U7QUFFcEUsNEVBQTRFO0FBQzVFLE1BQU0scUJBQXFCLEdBQUcsT0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtJQUMvQyxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVE7UUFBRSxPQUFPLEdBQUcsQ0FBQztJQUV4QyxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLHFFQUFxRTtRQUNyRSxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7QUFDSCxDQUFDLEVBQUUsbUJBQVksQ0FBQyxDQUFDO0FBRWpCLE1BQU0sa0JBQWtCLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUNsQyxjQUFjLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRTtJQUMxQixNQUFNLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM3QixPQUFPLEVBQUUscUJBQXFCO1NBQzNCLFFBQVEsQ0FDUCxvSkFBb0osQ0FDcko7U0FDQSxRQUFRLEVBQUU7SUFDYixJQUFJLEVBQUUsT0FBQztTQUNKLE1BQU0sQ0FBQztRQUNOLEtBQUssRUFBRSxPQUFDLENBQUMsTUFBTSxFQUFFO1FBQ2pCLFNBQVMsRUFBRSxPQUFDLENBQUMsT0FBTyxFQUFFO0tBQ3ZCLENBQUM7U0FDRCxRQUFRLEVBQUU7SUFDYixzQkFBc0IsRUFBRSxPQUFDO1NBQ3RCLE9BQU8sRUFBRTtTQUNULFFBQVEsRUFBRTtTQUNWLE9BQU8sQ0FBQyxLQUFL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
|