@daeda/mcp-pro 0.1.1 → 0.1.5
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 +254 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4190,31 +4190,94 @@ var batchDeleteRecordsMeta = {
|
|
|
4190
4190
|
|
|
4191
4191
|
// ../shared/operations/create-list/meta.ts
|
|
4192
4192
|
import { z as z28 } from "zod";
|
|
4193
|
+
var FilterSchema = z28.object({
|
|
4194
|
+
filterType: z28.string(),
|
|
4195
|
+
property: z28.string().optional(),
|
|
4196
|
+
operation: z28.record(z28.unknown()).optional()
|
|
4197
|
+
}).passthrough();
|
|
4198
|
+
var FilterBranchSchema = z28.object({
|
|
4199
|
+
filterBranchType: z28.enum(["AND", "ASSOCIATION", "UNIFIED_EVENTS"]),
|
|
4200
|
+
filterBranches: z28.lazy(() => z28.array(FilterBranchSchema)).default([]),
|
|
4201
|
+
filters: z28.array(FilterSchema).default([])
|
|
4202
|
+
}).passthrough();
|
|
4203
|
+
var RootFilterBranchSchema = z28.object({
|
|
4204
|
+
filterBranchType: z28.literal("OR"),
|
|
4205
|
+
filterBranches: z28.array(FilterBranchSchema).min(1),
|
|
4206
|
+
filters: z28.array(FilterSchema).default([])
|
|
4207
|
+
}).passthrough();
|
|
4193
4208
|
var CreateListOperationSchema = z28.object({
|
|
4194
4209
|
type: z28.literal("create_list"),
|
|
4195
4210
|
description: z28.string().min(1),
|
|
4196
4211
|
name: z28.string().min(1),
|
|
4197
4212
|
object_type_id: z28.string().min(1),
|
|
4198
4213
|
processing_type: z28.enum(["MANUAL", "DYNAMIC"]),
|
|
4199
|
-
filter_branch:
|
|
4214
|
+
filter_branch: RootFilterBranchSchema.optional()
|
|
4200
4215
|
});
|
|
4216
|
+
var FILTER_BRANCH_DESCRIPTION = `HubSpot filter definition for DYNAMIC lists. MUST follow the OR\u2192AND hierarchy:
|
|
4217
|
+
- Root: { filterBranchType: "OR", filters: [], filterBranches: [<one or more AND branches>] }
|
|
4218
|
+
- Each AND branch: { filterBranchType: "AND", filters: [<actual filters>], filterBranches: [] }
|
|
4219
|
+
- For OR logic between filter groups, use multiple AND branches under the root OR.
|
|
4220
|
+
- For AND logic within a group, put multiple filters in the same AND branch's filters array.
|
|
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, for IS_KNOWN / IS_NOT_KNOWN checks.
|
|
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: [] }`;
|
|
4201
4242
|
var fields17 = [
|
|
4202
4243
|
{ name: "name", type: "string", required: true, description: "Name for the new list" },
|
|
4203
|
-
{ name: "object_type_id", type: "string", required: true, description: "Object type ID (e.g. '0-1' for contacts, '0-2' for companies)" },
|
|
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)" },
|
|
4204
4245
|
{ name: "processing_type", type: "string", required: true, description: "List type: 'MANUAL' (static) or 'DYNAMIC' (active)" },
|
|
4205
|
-
{ name: "filter_branch", type: "object", required: false, description:
|
|
4246
|
+
{ name: "filter_branch", type: "object", required: false, description: FILTER_BRANCH_DESCRIPTION }
|
|
4206
4247
|
];
|
|
4207
4248
|
var createListMeta = {
|
|
4208
4249
|
type: "create_list",
|
|
4209
4250
|
category: "create",
|
|
4210
4251
|
summary: "Create a contact or company list (static or dynamic)",
|
|
4211
|
-
description:
|
|
4252
|
+
description: `Create a new HubSpot list. MANUAL lists are static (members added manually). DYNAMIC lists are active (membership determined by filter criteria).
|
|
4253
|
+
For DYNAMIC lists, provide filter_branch with the HubSpot filter definition. The root filterBranchType MUST be "OR" with filters: [] and one or more "AND" child branches containing the actual filters. This structure is enforced by HubSpot's API.`,
|
|
4212
4254
|
fields: fields17,
|
|
4213
4255
|
example: {
|
|
4214
4256
|
fields: {
|
|
4215
|
-
name: "
|
|
4257
|
+
name: "Active Leads",
|
|
4216
4258
|
object_type_id: "0-1",
|
|
4217
|
-
processing_type: "
|
|
4259
|
+
processing_type: "DYNAMIC",
|
|
4260
|
+
filter_branch: {
|
|
4261
|
+
filterBranchType: "OR",
|
|
4262
|
+
filters: [],
|
|
4263
|
+
filterBranches: [
|
|
4264
|
+
{
|
|
4265
|
+
filterBranchType: "AND",
|
|
4266
|
+
filterBranches: [],
|
|
4267
|
+
filters: [
|
|
4268
|
+
{
|
|
4269
|
+
filterType: "PROPERTY",
|
|
4270
|
+
property: "lifecyclestage",
|
|
4271
|
+
operation: {
|
|
4272
|
+
operationType: "ENUMERATION",
|
|
4273
|
+
operator: "IS_ANY_OF",
|
|
4274
|
+
values: ["lead"]
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
]
|
|
4278
|
+
}
|
|
4279
|
+
]
|
|
4280
|
+
}
|
|
4218
4281
|
}
|
|
4219
4282
|
},
|
|
4220
4283
|
toNested: (description, fields29) => {
|
|
@@ -4230,13 +4293,21 @@ var createListMeta = {
|
|
|
4230
4293
|
},
|
|
4231
4294
|
requiredScopes: () => ["crm.lists.write"],
|
|
4232
4295
|
getSummary: (op) => `Create List \u2014 ${op.name} (${op.processing_type})`,
|
|
4233
|
-
getResourceUrl: (portalId) => `${HUBSPOT_BASE}/contacts/${portalId}/
|
|
4296
|
+
getResourceUrl: (portalId) => `${HUBSPOT_BASE}/contacts/${portalId}/objectLists/views/all`,
|
|
4234
4297
|
renderDetails: (op) => {
|
|
4235
4298
|
const rows = [
|
|
4236
4299
|
{ label: "Name", value: op.name },
|
|
4237
4300
|
{ label: "Object Type ID", value: op.object_type_id },
|
|
4238
4301
|
{ label: "Processing Type", value: op.processing_type }
|
|
4239
4302
|
];
|
|
4303
|
+
if (op.filter_branch) {
|
|
4304
|
+
const andCount = op.filter_branch.filterBranches?.length ?? 0;
|
|
4305
|
+
const totalFilters = op.filter_branch.filterBranches?.reduce(
|
|
4306
|
+
(sum, branch) => sum + (branch.filters?.length ?? 0),
|
|
4307
|
+
0
|
|
4308
|
+
) ?? 0;
|
|
4309
|
+
rows.push({ label: "Filter Groups", value: `${andCount} group(s), ${totalFilters} filter(s)` });
|
|
4310
|
+
}
|
|
4240
4311
|
return { rows };
|
|
4241
4312
|
}
|
|
4242
4313
|
};
|
|
@@ -7015,6 +7086,59 @@ var batchDeleteRecordsHandler = {
|
|
|
7015
7086
|
// ../shared/operations/create-list/index.ts
|
|
7016
7087
|
import { Effect as Effect53, pipe as pipe42 } from "effect";
|
|
7017
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
|
+
};
|
|
7018
7142
|
var createListHandler = {
|
|
7019
7143
|
type: "create_list",
|
|
7020
7144
|
validate: (op, index) => {
|
|
@@ -7027,25 +7151,134 @@ var createListHandler = {
|
|
|
7027
7151
|
message: `Processing type '${op.processing_type}' is invalid \u2014 must be "MANUAL" or "DYNAMIC"`
|
|
7028
7152
|
});
|
|
7029
7153
|
}
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7154
|
+
if (op.processing_type === "DYNAMIC" && !op.filter_branch) {
|
|
7155
|
+
issues.push({
|
|
7156
|
+
severity: "warning",
|
|
7157
|
+
operation_index: index,
|
|
7158
|
+
code: "DYNAMIC_LIST_NO_FILTER",
|
|
7159
|
+
message: `DYNAMIC list '${op.name}' has no filter_branch \u2014 it will match all records of the object type`
|
|
7160
|
+
});
|
|
7161
|
+
}
|
|
7162
|
+
if (op.filter_branch) {
|
|
7163
|
+
const result = RootFilterBranchSchema.safeParse(op.filter_branch);
|
|
7164
|
+
if (!result.success) {
|
|
7165
|
+
const zodIssues = result.error.issues.map((i) => i.message).join("; ");
|
|
7038
7166
|
issues.push({
|
|
7039
7167
|
severity: "error",
|
|
7040
7168
|
operation_index: index,
|
|
7041
|
-
code: "
|
|
7042
|
-
message: `
|
|
7169
|
+
code: "INVALID_FILTER_BRANCH",
|
|
7170
|
+
message: `filter_branch is invalid: ${zodIssues}. Root must be { filterBranchType: "OR", filters: [], filterBranches: [{ filterBranchType: "AND", filters: [...], filterBranches: [] }] }`
|
|
7043
7171
|
});
|
|
7172
|
+
} else {
|
|
7173
|
+
const fb = op.filter_branch;
|
|
7174
|
+
if (fb.filterBranchType !== "OR") {
|
|
7175
|
+
issues.push({
|
|
7176
|
+
severity: "error",
|
|
7177
|
+
operation_index: index,
|
|
7178
|
+
code: "INVALID_FILTER_BRANCH_ROOT",
|
|
7179
|
+
message: `Root filterBranchType must be "OR", got "${fb.filterBranchType}"`
|
|
7180
|
+
});
|
|
7181
|
+
}
|
|
7182
|
+
const branches = fb.filterBranches;
|
|
7183
|
+
const hasAndBranch = branches?.some((b) => b.filterBranchType === "AND");
|
|
7184
|
+
if (!hasAndBranch) {
|
|
7185
|
+
issues.push({
|
|
7186
|
+
severity: "error",
|
|
7187
|
+
operation_index: index,
|
|
7188
|
+
code: "INVALID_FILTER_BRANCH_NO_AND",
|
|
7189
|
+
message: `Root OR branch must contain at least one AND child branch`
|
|
7190
|
+
});
|
|
7191
|
+
}
|
|
7192
|
+
const rootFilters = fb.filters;
|
|
7193
|
+
if (rootFilters && rootFilters.length > 0) {
|
|
7194
|
+
issues.push({
|
|
7195
|
+
severity: "error",
|
|
7196
|
+
operation_index: index,
|
|
7197
|
+
code: "INVALID_FILTER_BRANCH_ROOT_FILTERS",
|
|
7198
|
+
message: `Root OR branch must have an empty filters array \u2014 filters belong inside AND child branches`
|
|
7199
|
+
});
|
|
7200
|
+
}
|
|
7201
|
+
if (branches?.length) {
|
|
7202
|
+
issues.push(...collectAssociationIssues(branches, index));
|
|
7203
|
+
}
|
|
7044
7204
|
}
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
)
|
|
7205
|
+
}
|
|
7206
|
+
return issues;
|
|
7207
|
+
},
|
|
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
|
+
},
|
|
7049
7282
|
preCheck: (op, index, seen) => pipe42(
|
|
7050
7283
|
HubSpotService,
|
|
7051
7284
|
Effect53.flatMap((hs) => hs.getLists),
|