@daeda/mcp-pro 0.1.4 → 0.1.6
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.js +153 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4218,9 +4218,27 @@ var FILTER_BRANCH_DESCRIPTION = `HubSpot filter definition for DYNAMIC lists. MU
|
|
|
4218
4218
|
- Each AND branch: { filterBranchType: "AND", filters: [<actual filters>], filterBranches: [] }
|
|
4219
4219
|
- For OR logic between filter groups, use multiple AND branches under the root OR.
|
|
4220
4220
|
- For AND logic within a group, put multiple filters in the same AND branch's filters array.
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4221
|
+
|
|
4222
|
+
operationType MUST match the HubSpot property type:
|
|
4223
|
+
- ENUMERATION \u2192 for enumeration properties (lifecyclestage, pipeline, dealstage, hs_lead_status, hs_pipeline, etc.). Operators: IS_ANY_OF, IS_NONE_OF, HAS_EVER_BEEN_ANY_OF, HAS_NEVER_BEEN_ANY_OF, IS_EXACTLY, IS_NOT_EXACTLY, CONTAINS_ALL_OF, DOES_NOT_CONTAIN_ALL_OF. WARNING: IS_EQUAL_TO is NOT valid for ENUMERATION \u2014 use IS_ANY_OF instead.
|
|
4224
|
+
- MULTISTRING \u2192 for string properties (firstname, lastname, email, city, company, etc.). Operators: IS_EQUAL_TO, IS_NOT_EQUAL_TO, CONTAINS, DOES_NOT_CONTAIN, STARTS_WITH, ENDS_WITH.
|
|
4225
|
+
- NUMBER \u2192 for number properties. Operators: IS_EQUAL_TO, IS_NOT_EQUAL_TO, IS_BETWEEN, IS_GREATER_THAN, IS_LESS_THAN.
|
|
4226
|
+
- BOOL \u2192 for boolean properties. Operators: IS_EQUAL_TO, IS_NOT_EQUAL_TO.
|
|
4227
|
+
- TIME_POINT \u2192 for date/datetime properties (single point comparison).
|
|
4228
|
+
- TIME_RANGED \u2192 for date/datetime properties (range with lowerBoundTimePoint / upperBoundTimePoint).
|
|
4229
|
+
- ALL_PROPERTY \u2192 any property type. Operators: IS_KNOWN, IS_UNKNOWN, IS_BLANK, IS_NOT_BLANK. WARNING: IS_NOT_KNOWN is NOT valid \u2014 use IS_UNKNOWN instead.
|
|
4230
|
+
Enum filter example: { filterType: "PROPERTY", property: "lifecyclestage", operation: { operationType: "ENUMERATION", operator: "IS_ANY_OF", values: ["lead"] } }
|
|
4231
|
+
|
|
4232
|
+
ASSOCIATION branches filter by associated records and MUST include these required fields:
|
|
4233
|
+
- filterBranchType: "ASSOCIATION"
|
|
4234
|
+
- objectTypeId: the associated object type ID (e.g. "0-3" for deals)
|
|
4235
|
+
- operator: "IN_LIST"
|
|
4236
|
+
- associationTypeId: (number) the association type ID \u2014 required by HubSpot (e.g. 4 for contact\u2192deal, 1 for contact\u2192company, 5 for deal\u2192company)
|
|
4237
|
+
- associationCategory: (string) usually "HUBSPOT_DEFINED" (also: "USER_DEFINED", "INTEGRATOR_DEFINED")
|
|
4238
|
+
- filters: property filters on the associated object
|
|
4239
|
+
- filterBranches: [] (no further nesting except CONTACT\u2192LINE_ITEM)
|
|
4240
|
+
ASSOCIATION branches must be nested inside an AND branch.
|
|
4241
|
+
Association example: { filterBranchType: "ASSOCIATION", objectTypeId: "0-3", operator: "IN_LIST", associationTypeId: 4, associationCategory: "HUBSPOT_DEFINED", filters: [{ filterType: "PROPERTY", property: "dealstage", operation: { operationType: "ENUMERATION", operator: "IS_NONE_OF", values: ["closedwon", "closedlost"] } }], filterBranches: [] }`;
|
|
4224
4242
|
var fields17 = [
|
|
4225
4243
|
{ name: "name", type: "string", required: true, description: "Name for the new list" },
|
|
4226
4244
|
{ name: "object_type_id", type: "string", required: true, description: "Object type ID (e.g. '0-1' for contacts, '0-2' for companies, '0-3' for deals)" },
|
|
@@ -4251,8 +4269,8 @@ For DYNAMIC lists, provide filter_branch with the HubSpot filter definition. The
|
|
|
4251
4269
|
filterType: "PROPERTY",
|
|
4252
4270
|
property: "lifecyclestage",
|
|
4253
4271
|
operation: {
|
|
4254
|
-
operationType: "
|
|
4255
|
-
operator: "
|
|
4272
|
+
operationType: "ENUMERATION",
|
|
4273
|
+
operator: "IS_ANY_OF",
|
|
4256
4274
|
values: ["lead"]
|
|
4257
4275
|
}
|
|
4258
4276
|
}
|
|
@@ -7068,6 +7086,59 @@ var batchDeleteRecordsHandler = {
|
|
|
7068
7086
|
// ../shared/operations/create-list/index.ts
|
|
7069
7087
|
import { Effect as Effect53, pipe as pipe42 } from "effect";
|
|
7070
7088
|
var VALID_PROCESSING_TYPES = /* @__PURE__ */ new Set(["MANUAL", "DYNAMIC"]);
|
|
7089
|
+
var OPERATION_TYPE_FOR_PROPERTY_TYPE = {
|
|
7090
|
+
enumeration: "ENUMERATION",
|
|
7091
|
+
string: "MULTISTRING",
|
|
7092
|
+
number: "NUMBER",
|
|
7093
|
+
bool: "BOOL",
|
|
7094
|
+
date: "TIME_POINT",
|
|
7095
|
+
datetime: "TIME_POINT"
|
|
7096
|
+
};
|
|
7097
|
+
var collectPropertyFilters = (branches, parentObjectTypeId) => {
|
|
7098
|
+
const refs = [];
|
|
7099
|
+
for (const branch of branches) {
|
|
7100
|
+
const ctxObjectTypeId = branch.filterBranchType === "ASSOCIATION" && typeof branch.objectTypeId === "string" ? branch.objectTypeId : parentObjectTypeId;
|
|
7101
|
+
const filters = branch.filters;
|
|
7102
|
+
if (filters) {
|
|
7103
|
+
for (const f of filters) {
|
|
7104
|
+
if (f.filterType === "PROPERTY" && typeof f.property === "string") {
|
|
7105
|
+
const op = f.operation;
|
|
7106
|
+
if (op && typeof op.operationType === "string") {
|
|
7107
|
+
refs.push({ property: f.property, operationType: op.operationType, objectTypeId: ctxObjectTypeId });
|
|
7108
|
+
}
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
}
|
|
7112
|
+
const nested = branch.filterBranches;
|
|
7113
|
+
if (nested?.length) {
|
|
7114
|
+
refs.push(...collectPropertyFilters(nested, ctxObjectTypeId));
|
|
7115
|
+
}
|
|
7116
|
+
}
|
|
7117
|
+
return refs;
|
|
7118
|
+
};
|
|
7119
|
+
var collectAssociationIssues = (branches, index) => {
|
|
7120
|
+
const issues = [];
|
|
7121
|
+
for (const branch of branches) {
|
|
7122
|
+
if (branch.filterBranchType === "ASSOCIATION") {
|
|
7123
|
+
const missing = [];
|
|
7124
|
+
if (branch.associationTypeId == null) missing.push("associationTypeId");
|
|
7125
|
+
if (branch.associationCategory == null) missing.push("associationCategory");
|
|
7126
|
+
if (missing.length > 0) {
|
|
7127
|
+
issues.push({
|
|
7128
|
+
severity: "error",
|
|
7129
|
+
operation_index: index,
|
|
7130
|
+
code: "ASSOCIATION_MISSING_REQUIRED_FIELDS",
|
|
7131
|
+
message: `ASSOCIATION filter branch (objectTypeId: ${branch.objectTypeId ?? "unknown"}) is missing required field(s): ${missing.join(", ")}. ASSOCIATION branches require associationTypeId (number) and associationCategory (string, usually "HUBSPOT_DEFINED").`
|
|
7132
|
+
});
|
|
7133
|
+
}
|
|
7134
|
+
}
|
|
7135
|
+
const nested = branch.filterBranches;
|
|
7136
|
+
if (nested?.length) {
|
|
7137
|
+
issues.push(...collectAssociationIssues(nested, index));
|
|
7138
|
+
}
|
|
7139
|
+
}
|
|
7140
|
+
return issues;
|
|
7141
|
+
};
|
|
7071
7142
|
var createListHandler = {
|
|
7072
7143
|
type: "create_list",
|
|
7073
7144
|
validate: (op, index) => {
|
|
@@ -7127,27 +7198,87 @@ var createListHandler = {
|
|
|
7127
7198
|
message: `Root OR branch must have an empty filters array \u2014 filters belong inside AND child branches`
|
|
7128
7199
|
});
|
|
7129
7200
|
}
|
|
7201
|
+
if (branches?.length) {
|
|
7202
|
+
issues.push(...collectAssociationIssues(branches, index));
|
|
7203
|
+
}
|
|
7130
7204
|
}
|
|
7131
7205
|
}
|
|
7132
7206
|
return issues;
|
|
7133
7207
|
},
|
|
7134
|
-
validateEffectful: (op, index) =>
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7208
|
+
validateEffectful: (op, index) => {
|
|
7209
|
+
const checkDuplicateList = pipe42(
|
|
7210
|
+
HubSpotService,
|
|
7211
|
+
Effect53.flatMap((hs) => hs.getLists),
|
|
7212
|
+
Effect53.map((lists) => {
|
|
7213
|
+
const issues = [];
|
|
7214
|
+
if (lists.find((l) => l.name === op.name)) {
|
|
7215
|
+
issues.push({
|
|
7216
|
+
severity: "error",
|
|
7217
|
+
operation_index: index,
|
|
7218
|
+
code: "LIST_ALREADY_EXISTS",
|
|
7219
|
+
message: `A list named '${op.name}' already exists \u2014 HubSpot may reject a duplicate`
|
|
7220
|
+
});
|
|
7221
|
+
}
|
|
7222
|
+
return issues;
|
|
7223
|
+
}),
|
|
7224
|
+
catchAllToWarning("VALIDATION_API_UNAVAILABLE", index, "Unable to verify existing lists during validation (API error)")
|
|
7225
|
+
);
|
|
7226
|
+
const checkOperationTypes = () => {
|
|
7227
|
+
if (op.processing_type !== "DYNAMIC" || !op.filter_branch) return Effect53.succeed([]);
|
|
7228
|
+
const filterRefs = collectPropertyFilters(
|
|
7229
|
+
op.filter_branch.filterBranches ?? [],
|
|
7230
|
+
op.object_type_id
|
|
7231
|
+
);
|
|
7232
|
+
if (filterRefs.length === 0) return Effect53.succeed([]);
|
|
7233
|
+
const uniqueObjectTypes = Array.from(new Set(filterRefs.map((r) => r.objectTypeId)));
|
|
7234
|
+
return pipe42(
|
|
7235
|
+
HubSpotService,
|
|
7236
|
+
Effect53.flatMap(
|
|
7237
|
+
(hs) => Effect53.all(
|
|
7238
|
+
uniqueObjectTypes.map(
|
|
7239
|
+
(ot) => pipe42(
|
|
7240
|
+
hs.getObjectPropertyDefinitions(ot),
|
|
7241
|
+
Effect53.map((defs) => [ot, defs])
|
|
7242
|
+
)
|
|
7243
|
+
),
|
|
7244
|
+
{ concurrency: "unbounded" }
|
|
7245
|
+
)
|
|
7246
|
+
),
|
|
7247
|
+
Effect53.map((results) => {
|
|
7248
|
+
const propTypeByObject = /* @__PURE__ */ new Map();
|
|
7249
|
+
for (const [ot, defs] of results) {
|
|
7250
|
+
const m = /* @__PURE__ */ new Map();
|
|
7251
|
+
for (const d of defs) m.set(d.name, d.type);
|
|
7252
|
+
propTypeByObject.set(ot, m);
|
|
7253
|
+
}
|
|
7254
|
+
const issues = [];
|
|
7255
|
+
for (const ref of filterRefs) {
|
|
7256
|
+
const propMap = propTypeByObject.get(ref.objectTypeId);
|
|
7257
|
+
if (!propMap) continue;
|
|
7258
|
+
const propType = propMap.get(ref.property);
|
|
7259
|
+
if (!propType) continue;
|
|
7260
|
+
const expected = OPERATION_TYPE_FOR_PROPERTY_TYPE[propType];
|
|
7261
|
+
if (!expected) continue;
|
|
7262
|
+
if (ref.operationType === expected) continue;
|
|
7263
|
+
if (ref.operationType === "ALL_PROPERTY") continue;
|
|
7264
|
+
if (ref.operationType === "TIME_RANGED" && (propType === "date" || propType === "datetime")) continue;
|
|
7265
|
+
issues.push({
|
|
7266
|
+
severity: "error",
|
|
7267
|
+
operation_index: index,
|
|
7268
|
+
code: "INVALID_OPERATION_TYPE",
|
|
7269
|
+
message: `Property '${ref.property}' has type '${propType}' but filter uses operationType '${ref.operationType}'. Use '${expected}' instead.${propType === "enumeration" ? " For enumeration properties use operators like IS_ANY_OF, IS_NONE_OF (not IS_EQUAL_TO)." : ""}`
|
|
7270
|
+
});
|
|
7271
|
+
}
|
|
7272
|
+
return issues;
|
|
7273
|
+
}),
|
|
7274
|
+
catchAllToWarning("VALIDATION_API_UNAVAILABLE", index, "Unable to verify filter operationTypes during validation (API error)")
|
|
7275
|
+
);
|
|
7276
|
+
};
|
|
7277
|
+
return pipe42(
|
|
7278
|
+
Effect53.all([checkDuplicateList, checkOperationTypes()], { concurrency: "unbounded" }),
|
|
7279
|
+
Effect53.map(([dupeIssues, opTypeIssues]) => [...dupeIssues, ...opTypeIssues])
|
|
7280
|
+
);
|
|
7281
|
+
},
|
|
7151
7282
|
preCheck: (op, index, seen) => pipe42(
|
|
7152
7283
|
HubSpotService,
|
|
7153
7284
|
Effect53.flatMap((hs) => hs.getLists),
|