@classytic/arc 2.5.0 → 2.5.1
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/dist/index.mjs +1 -1
- package/dist/integrations/mcp/index.d.mts +2 -0
- package/dist/integrations/mcp/index.mjs +1 -1
- package/dist/integrations/mcp/testing.mjs +1 -1
- package/dist/plugins/tracing-entry.mjs +1 -1
- package/dist/{resourceToTools-CN0lwJrL.mjs → resourceToTools-B1B1svLx.mjs} +80 -6
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -127,6 +127,6 @@ function transform(name, handlerOrOptions) {
|
|
|
127
127
|
}
|
|
128
128
|
//#endregion
|
|
129
129
|
//#region src/index.ts
|
|
130
|
-
const version = "2.5.
|
|
130
|
+
const version = "2.5.1";
|
|
131
131
|
//#endregion
|
|
132
132
|
export { ArcError, BaseController, CRUD_OPERATIONS, DEFAULT_ID_FIELD, DEFAULT_LIMIT, DEFAULT_MAX_LIMIT, DEFAULT_SORT, DEFAULT_TENANT_FIELD, DEFAULT_UPDATE_METHOD, ForbiddenError, HOOK_OPERATIONS, HOOK_PHASES, MAX_FILTER_DEPTH, MAX_REGEX_LENGTH, MAX_SEARCH_LENGTH, MUTATION_OPERATIONS, MongooseAdapter, NotFoundError, PrismaAdapter, RESERVED_QUERY_PARAMS, ResourceDefinition, SYSTEM_FIELDS, UnauthorizedError, ValidationError, adminOnly, allOf, allowPublic, anyOf, applyFieldReadPermissions, applyFieldWritePermissions, arcLog, assertValidConfig, authenticated, configureArcLogger, createDomainError, createDynamicPermissionMatrix, createMongooseAdapter, createOrgPermissions, createPrismaAdapter, defineResource, denyAll, envelope, fields, formatValidationErrors, fullPublic, getControllerScope, guard, intercept, middleware, ownerWithAdminBypass, presets_exports as permissions, pipe, publicRead, publicReadAdminWrite, readOnly, requestContext, requireAuth, requireOrgMembership, requireOrgRole, requireOwnership, requireRoles, requireTeamMembership, sortMiddlewares, transform, validateResourceConfig, version, when };
|
|
@@ -75,6 +75,8 @@ interface FieldRulesToZodOptions {
|
|
|
75
75
|
extraHideFields?: string[];
|
|
76
76
|
/** Filterable fields — only used in list mode */
|
|
77
77
|
filterableFields?: readonly string[];
|
|
78
|
+
/** Allowed filter operators — generates `field[op]` entries in list mode (e.g., price[gt], price[lte]) */
|
|
79
|
+
allowedOperators?: readonly string[];
|
|
78
80
|
}
|
|
79
81
|
/** Single field rule entry from Arc's schemaOptions.fieldRules */
|
|
80
82
|
interface FieldRuleEntry {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as fieldRulesToZod, r as createMcpServer, t as resourceToTools } from "../../resourceToTools-
|
|
1
|
+
import { n as fieldRulesToZod, r as createMcpServer, t as resourceToTools } from "../../resourceToTools-B1B1svLx.mjs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import fp from "fastify-plugin";
|
|
4
4
|
//#region src/integrations/mcp/definePrompt.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as createMcpServer, t as resourceToTools } from "../../resourceToTools-
|
|
1
|
+
import { r as createMcpServer, t as resourceToTools } from "../../resourceToTools-B1B1svLx.mjs";
|
|
2
2
|
//#region src/integrations/mcp/testing.ts
|
|
3
3
|
/**
|
|
4
4
|
* @classytic/arc/mcp/testing — MCP Test Utilities
|
|
@@ -44,7 +44,7 @@ try {
|
|
|
44
44
|
function createTracerProvider(options) {
|
|
45
45
|
if (!isAvailable) return null;
|
|
46
46
|
const { serviceName = "@classytic/arc", serviceVersion, exporterUrl = "http://localhost:4318/v1/traces" } = options;
|
|
47
|
-
const resolvedVersion = serviceVersion ?? "2.5.
|
|
47
|
+
const resolvedVersion = serviceVersion ?? "2.5.1";
|
|
48
48
|
const exporter = new OTLPTraceExporter({ url: exporterUrl });
|
|
49
49
|
const provider = new NodeTracerProvider({ resource: { attributes: {
|
|
50
50
|
"service.name": serviceName,
|
|
@@ -148,16 +148,55 @@ function typeToZod(type) {
|
|
|
148
148
|
default: return z.string();
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
|
-
/**
|
|
151
|
+
/** Operators that apply to numeric/date fields */
|
|
152
|
+
const COMPARISON_OPS = new Set([
|
|
153
|
+
"gt",
|
|
154
|
+
"gte",
|
|
155
|
+
"lt",
|
|
156
|
+
"lte"
|
|
157
|
+
]);
|
|
158
|
+
/** Map operator to a human-readable description suffix */
|
|
159
|
+
function opDescription(op, fieldName) {
|
|
160
|
+
switch (op) {
|
|
161
|
+
case "gt": return `${fieldName} greater than`;
|
|
162
|
+
case "gte": return `${fieldName} greater than or equal`;
|
|
163
|
+
case "lt": return `${fieldName} less than`;
|
|
164
|
+
case "lte": return `${fieldName} less than or equal`;
|
|
165
|
+
case "ne": return `${fieldName} not equal to`;
|
|
166
|
+
case "in": return `${fieldName} in comma-separated list`;
|
|
167
|
+
case "nin": return `${fieldName} not in comma-separated list`;
|
|
168
|
+
case "exists": return `${fieldName} exists (true/false)`;
|
|
169
|
+
default: return `${fieldName} ${op}`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/** Build list/query shape with filterable fields, operators, and pagination */
|
|
152
173
|
function buildListShape(fieldRules, options) {
|
|
153
|
-
const { filterableFields = [], hiddenFields = [], extraHideFields = [] } = options;
|
|
174
|
+
const { filterableFields = [], hiddenFields = [], extraHideFields = [], allowedOperators } = options;
|
|
154
175
|
const allHidden = new Set([...hiddenFields, ...extraHideFields]);
|
|
155
176
|
const shape = { ...PAGINATION_SHAPE };
|
|
156
|
-
if (fieldRules)
|
|
177
|
+
if (!fieldRules) return shape;
|
|
178
|
+
for (const name of filterableFields) {
|
|
157
179
|
if (allHidden.has(name)) continue;
|
|
158
180
|
const rule = fieldRules[name];
|
|
159
181
|
if (!rule) continue;
|
|
160
|
-
|
|
182
|
+
const filterField = buildFieldSchema(rule);
|
|
183
|
+
shape[name] = filterField.optional();
|
|
184
|
+
if (allowedOperators?.length) {
|
|
185
|
+
const isNumericOrDate = rule.type === "number" || rule.type === "date";
|
|
186
|
+
for (const op of allowedOperators) {
|
|
187
|
+
if (COMPARISON_OPS.has(op) && !isNumericOrDate) continue;
|
|
188
|
+
if (op === "eq") continue;
|
|
189
|
+
if (op === "exists") {
|
|
190
|
+
shape[`${name}_${op}`] = z.boolean().optional().describe(opDescription(op, name));
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (op === "in" || op === "nin") {
|
|
194
|
+
shape[`${name}_${op}`] = z.string().optional().describe(opDescription(op, name));
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
shape[`${name}_${op}`] = filterField.optional().describe(opDescription(op, name));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
161
200
|
}
|
|
162
201
|
return shape;
|
|
163
202
|
}
|
|
@@ -193,7 +232,7 @@ function buildRequestContext(input, auth, operation, policyFilters) {
|
|
|
193
232
|
case "list": return {
|
|
194
233
|
...base,
|
|
195
234
|
params: {},
|
|
196
|
-
query:
|
|
235
|
+
query: expandOperatorKeys(input),
|
|
197
236
|
body: void 0
|
|
198
237
|
};
|
|
199
238
|
case "get": return {
|
|
@@ -225,6 +264,40 @@ function buildRequestContext(input, auth, operation, policyFilters) {
|
|
|
225
264
|
};
|
|
226
265
|
}
|
|
227
266
|
}
|
|
267
|
+
/** Convert MCP operator keys (`price_gt`) to MongoKit bracket notation (`price[gt]`). */
|
|
268
|
+
const OPERATOR_SUFFIXES = new Set([
|
|
269
|
+
"eq",
|
|
270
|
+
"ne",
|
|
271
|
+
"gt",
|
|
272
|
+
"gte",
|
|
273
|
+
"lt",
|
|
274
|
+
"lte",
|
|
275
|
+
"in",
|
|
276
|
+
"nin",
|
|
277
|
+
"exists"
|
|
278
|
+
]);
|
|
279
|
+
function expandOperatorKeys(input) {
|
|
280
|
+
const out = {};
|
|
281
|
+
for (const [key, value] of Object.entries(input)) {
|
|
282
|
+
const lastUnderscore = key.lastIndexOf("_");
|
|
283
|
+
if (lastUnderscore > 0) {
|
|
284
|
+
const op = key.slice(lastUnderscore + 1);
|
|
285
|
+
if (OPERATOR_SUFFIXES.has(op)) {
|
|
286
|
+
const field = key.slice(0, lastUnderscore);
|
|
287
|
+
const existing = out[field];
|
|
288
|
+
if (existing && typeof existing === "object" && existing !== null) existing[op] = value;
|
|
289
|
+
else if (existing === void 0) out[field] = { [op]: value };
|
|
290
|
+
else out[field] = {
|
|
291
|
+
eq: existing,
|
|
292
|
+
[op]: value
|
|
293
|
+
};
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
out[key] = value;
|
|
298
|
+
}
|
|
299
|
+
return out;
|
|
300
|
+
}
|
|
228
301
|
function buildScope(auth) {
|
|
229
302
|
if (!auth) return { kind: "public" };
|
|
230
303
|
if (auth.organizationId) return {
|
|
@@ -314,7 +387,8 @@ function resourceToTools(resource, config = {}) {
|
|
|
314
387
|
hiddenFields,
|
|
315
388
|
readonlyFields,
|
|
316
389
|
extraHideFields: config.hideFields,
|
|
317
|
-
filterableFields
|
|
390
|
+
filterableFields,
|
|
391
|
+
allowedOperators
|
|
318
392
|
}),
|
|
319
393
|
handler: createHandler(op, controller, resource.name, resource.permissions)
|
|
320
394
|
});
|