@socialseal/mcp-server 0.1.0 → 0.1.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.
@@ -0,0 +1,703 @@
1
+ import { SocialSealMcpError } from "./errors.js";
2
+ const TRANSLATED_TOOLS = new Set([
3
+ "tracking",
4
+ "group-management",
5
+ "brand-group-management",
6
+ "export_tracking_data",
7
+ ]);
8
+ export function isTranslatedTool(toolName) {
9
+ return TRANSLATED_TOOLS.has(toolName);
10
+ }
11
+ function invalidArgument(message, details) {
12
+ return new SocialSealMcpError(message, { code: "INVALID_ARGUMENT", details });
13
+ }
14
+ function missingArgument(message) {
15
+ return new SocialSealMcpError(message, { code: "MISSING_ARGUMENT" });
16
+ }
17
+ export function isJsonObject(value) {
18
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
19
+ }
20
+ function hasOwn(value, key) {
21
+ return Boolean(value) && Object.prototype.hasOwnProperty.call(value, key);
22
+ }
23
+ function firstDefined(source, keys) {
24
+ if (!isJsonObject(source))
25
+ return undefined;
26
+ for (const key of keys) {
27
+ if (hasOwn(source, key) && source[key] !== undefined && source[key] !== null) {
28
+ return source[key];
29
+ }
30
+ }
31
+ return undefined;
32
+ }
33
+ function trimString(value) {
34
+ return typeof value === "string" ? value.trim() : "";
35
+ }
36
+ function stripUndefinedEntries(value) {
37
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
38
+ }
39
+ function resolvePayloadWorkspaceId(payload, fallbackWorkspaceId) {
40
+ const workspaceId = firstDefined(payload, ["workspace_id", "workspaceId"]);
41
+ if (typeof workspaceId === "string" && workspaceId.trim().length > 0) {
42
+ return workspaceId.trim();
43
+ }
44
+ return fallbackWorkspaceId || null;
45
+ }
46
+ function coercePositiveInteger(value, label) {
47
+ if (value === undefined || value === null || value === "")
48
+ return undefined;
49
+ const parsed = Number(value);
50
+ if (Number.isInteger(parsed) && parsed > 0) {
51
+ return parsed;
52
+ }
53
+ throw invalidArgument(`Invalid ${label}: expected a positive integer.`, value);
54
+ }
55
+ function buildPathWithQuery(basePath, query) {
56
+ const params = new URLSearchParams();
57
+ for (const [key, rawValue] of Object.entries(query)) {
58
+ if (rawValue === undefined || rawValue === null || rawValue === "")
59
+ continue;
60
+ if (Array.isArray(rawValue)) {
61
+ for (const entry of rawValue) {
62
+ if (entry !== undefined && entry !== null && entry !== "") {
63
+ params.append(key, String(entry));
64
+ }
65
+ }
66
+ continue;
67
+ }
68
+ params.set(key, String(rawValue));
69
+ }
70
+ const queryString = params.toString();
71
+ return queryString ? `${basePath}?${queryString}` : basePath;
72
+ }
73
+ function normalizeTrackingType(value) {
74
+ const normalized = trimString(value).toLowerCase();
75
+ if (!normalized)
76
+ return undefined;
77
+ if (normalized === "keyword" || normalized === "search")
78
+ return "search";
79
+ if (normalized === "account" || normalized === "creator")
80
+ return "creator";
81
+ if (normalized === "hashtag")
82
+ return "hashtag";
83
+ throw invalidArgument(`Invalid tracking type: ${String(value)}. Use keyword/search, hashtag, or account/creator.`);
84
+ }
85
+ function normalizeTrackingPayload(payload, fallbackWorkspaceId) {
86
+ const trackValue = firstDefined(payload, ["track_value", "trackValue", "value"]);
87
+ const refreshFrequency = firstDefined(payload, ["refresh_frequency", "refreshFrequency"]);
88
+ const nextRefreshAt = firstDefined(payload, ["next_refresh_at", "nextRefreshAt"]);
89
+ const region = firstDefined(payload, ["region"]);
90
+ const platform = firstDefined(payload, ["platform"]);
91
+ const brandIds = firstDefined(payload, ["brand_ids", "brandIds"]);
92
+ const includeInactive = firstDefined(payload, ["includeInactive", "include_inactive"]);
93
+ const isActive = firstDefined(payload, ["is_active", "isActive"]);
94
+ const limit = firstDefined(payload, ["limit"]);
95
+ const page = firstDefined(payload, ["page"]);
96
+ const offset = firstDefined(payload, ["offset"]);
97
+ const itemId = firstDefined(payload, ["item_id", "itemId", "id"]);
98
+ return stripUndefinedEntries({
99
+ action: trimString(firstDefined(payload, ["action"])) || undefined,
100
+ workspaceId: resolvePayloadWorkspaceId(payload, fallbackWorkspaceId),
101
+ item_id: coercePositiveInteger(itemId, "item_id"),
102
+ name: trimString(firstDefined(payload, ["name"])) || (trimString(trackValue) || undefined),
103
+ track_type: normalizeTrackingType(firstDefined(payload, ["track_type", "trackType", "type"])),
104
+ track_value: trimString(trackValue) || undefined,
105
+ refresh_frequency: trimString(refreshFrequency) || undefined,
106
+ next_refresh_at: nextRefreshAt ?? undefined,
107
+ region: typeof region === "string" ? region.trim() || undefined : region,
108
+ platform: trimString(platform) || undefined,
109
+ brand_ids: Array.isArray(brandIds) ? brandIds : undefined,
110
+ limit: limit !== undefined ? Number(limit) : undefined,
111
+ page: page !== undefined ? Number(page) : undefined,
112
+ offset: offset !== undefined ? Number(offset) : undefined,
113
+ is_active: typeof isActive === "boolean" ? isActive : undefined,
114
+ include_inactive: typeof includeInactive === "boolean" ? includeInactive : undefined,
115
+ });
116
+ }
117
+ function normalizeGroupManagementPayload(payload, fallbackWorkspaceId) {
118
+ const groupId = firstDefined(payload, ["group_id", "groupId", "id"]);
119
+ const itemId = firstDefined(payload, ["item_id", "itemId"]);
120
+ const itemIds = firstDefined(payload, ["item_ids", "itemIds"]);
121
+ const items = firstDefined(payload, ["items"]);
122
+ const expectedItems = firstDefined(payload, ["expected_items", "expectedItems"]);
123
+ const limit = firstDefined(payload, ["limit"]);
124
+ const page = firstDefined(payload, ["page"]);
125
+ const force = firstDefined(payload, ["force"]);
126
+ return stripUndefinedEntries({
127
+ action: trimString(firstDefined(payload, ["action"])) || undefined,
128
+ workspaceId: resolvePayloadWorkspaceId(payload, fallbackWorkspaceId),
129
+ group_id: coercePositiveInteger(groupId, "group_id"),
130
+ item_id: coercePositiveInteger(itemId, "item_id"),
131
+ item_ids: Array.isArray(itemIds)
132
+ ? itemIds.map((value, index) => {
133
+ const parsed = coercePositiveInteger(value, `item_ids[${index}]`);
134
+ if (!parsed) {
135
+ throw invalidArgument(`Invalid item_ids[${index}]: expected a positive integer.`);
136
+ }
137
+ return parsed;
138
+ })
139
+ : undefined,
140
+ items: Array.isArray(items) ? items : undefined,
141
+ expected_items: Array.isArray(expectedItems) ? expectedItems : undefined,
142
+ name: trimString(firstDefined(payload, ["name"])) || undefined,
143
+ description: firstDefined(payload, ["description"]),
144
+ platform: trimString(firstDefined(payload, ["platform", "groupPlatform"])) || undefined,
145
+ refresh_frequency: trimString(firstDefined(payload, ["refresh_frequency", "refreshFrequency"])) || undefined,
146
+ next_refresh_at: firstDefined(payload, ["next_refresh_at", "nextRefreshAt"]) ?? undefined,
147
+ brand_id: trimString(firstDefined(payload, ["brand_id", "brandId"])) || undefined,
148
+ track_type: normalizeTrackingType(firstDefined(payload, ["track_type", "trackType", "type"])),
149
+ track_value: trimString(firstDefined(payload, ["track_value", "trackValue", "value"])) || undefined,
150
+ region: typeof firstDefined(payload, ["region"]) === "string"
151
+ ? trimString(firstDefined(payload, ["region"])) || undefined
152
+ : firstDefined(payload, ["region"]),
153
+ limit: limit !== undefined ? Number(limit) : undefined,
154
+ page: page !== undefined ? Number(page) : undefined,
155
+ force: force === true || trimString(force).toLowerCase() === "true" ? true : undefined,
156
+ });
157
+ }
158
+ function normalizeBrandGroupPayload(payload, fallbackWorkspaceId) {
159
+ return stripUndefinedEntries({
160
+ action: trimString(firstDefined(payload, ["action"])) || undefined,
161
+ workspaceId: resolvePayloadWorkspaceId(payload, fallbackWorkspaceId),
162
+ workspace_id: resolvePayloadWorkspaceId(payload, fallbackWorkspaceId) || undefined,
163
+ brand_group_id: trimString(firstDefined(payload, ["brand_group_id", "brandGroupId", "group_id", "groupId", "id"])) || undefined,
164
+ brand_id: trimString(firstDefined(payload, ["brand_id", "brandId"])) || undefined,
165
+ name: trimString(firstDefined(payload, ["name"])) || undefined,
166
+ description: firstDefined(payload, ["description"]),
167
+ });
168
+ }
169
+ function normalizeTrackingExportPayload(payload, fallbackWorkspaceId) {
170
+ const groupId = firstDefined(payload, ["group_id", "groupId", "tracking_group_id", "trackingGroupId"]);
171
+ const itemId = firstDefined(payload, ["tracking_item_id", "trackingItemId", "item_id", "itemId"]);
172
+ return stripUndefinedEntries({
173
+ workspace_id: resolvePayloadWorkspaceId(payload, fallbackWorkspaceId) || undefined,
174
+ group_id: coercePositiveInteger(groupId, "group_id"),
175
+ tracking_item_id: coercePositiveInteger(itemId, "tracking_item_id"),
176
+ time_period: trimString(firstDefined(payload, ["time_period", "timePeriod"])) || undefined,
177
+ });
178
+ }
179
+ function buildGroupAddPayloadFromValue(rawValue, payload, label) {
180
+ const value = trimString(rawValue);
181
+ if (!value) {
182
+ throw invalidArgument(`Invalid ${label}: expected a non-empty tracking value.`);
183
+ }
184
+ if (!payload.track_type) {
185
+ throw missingArgument(`${label} requires track_type/type when using raw values. Use type=keyword/search, hashtag, or account/creator.`);
186
+ }
187
+ return stripUndefinedEntries({
188
+ name: value,
189
+ track_type: payload.track_type,
190
+ track_value: value,
191
+ refresh_frequency: payload.refresh_frequency,
192
+ next_refresh_at: payload.next_refresh_at,
193
+ region: payload.region,
194
+ platform: payload.platform,
195
+ });
196
+ }
197
+ function buildGroupAddPayloadFromItem(rawItem, payload, label) {
198
+ if (typeof rawItem === "number") {
199
+ return { item_id: coercePositiveInteger(rawItem, label) };
200
+ }
201
+ if (typeof rawItem === "string") {
202
+ const trimmed = rawItem.trim();
203
+ if (/^\d+$/.test(trimmed)) {
204
+ return { item_id: coercePositiveInteger(trimmed, label) };
205
+ }
206
+ return buildGroupAddPayloadFromValue(rawItem, payload, label);
207
+ }
208
+ if (!isJsonObject(rawItem)) {
209
+ throw invalidArgument(`Invalid ${label}: expected an item id, string value, or object payload.`);
210
+ }
211
+ const itemId = coercePositiveInteger(firstDefined(rawItem, ["item_id", "itemId", "id"]), `${label}.item_id`);
212
+ if (itemId) {
213
+ return { item_id: itemId };
214
+ }
215
+ const trackValue = trimString(firstDefined(rawItem, ["track_value", "trackValue", "value"])) || undefined;
216
+ const name = trimString(firstDefined(rawItem, ["name"])) || trackValue;
217
+ const trackType = normalizeTrackingType(firstDefined(rawItem, ["track_type", "trackType", "type"])) ||
218
+ payload.track_type;
219
+ const region = firstDefined(rawItem, ["region"]) ?? payload.region;
220
+ const platform = trimString(firstDefined(rawItem, ["platform"])) || payload.platform;
221
+ const refreshFrequency = trimString(firstDefined(rawItem, ["refresh_frequency", "refreshFrequency"])) ||
222
+ payload.refresh_frequency;
223
+ const nextRefreshAt = firstDefined(rawItem, ["next_refresh_at", "nextRefreshAt"]) ?? payload.next_refresh_at;
224
+ if (!name || !trackValue || !trackType) {
225
+ throw missingArgument(`${label} requires item_id or name/track_value + track_type.`);
226
+ }
227
+ return stripUndefinedEntries({
228
+ name,
229
+ track_type: trackType,
230
+ track_value: trackValue,
231
+ refresh_frequency: refreshFrequency,
232
+ next_refresh_at: nextRefreshAt,
233
+ region,
234
+ platform,
235
+ });
236
+ }
237
+ function buildSingleGroupAddBody(payload) {
238
+ if (payload.item_id) {
239
+ return { item_id: payload.item_id };
240
+ }
241
+ if (payload.track_value || payload.name) {
242
+ return buildGroupAddPayloadFromItem({
243
+ name: payload.name,
244
+ track_type: payload.track_type,
245
+ track_value: payload.track_value,
246
+ refresh_frequency: payload.refresh_frequency,
247
+ next_refresh_at: payload.next_refresh_at,
248
+ region: payload.region,
249
+ platform: payload.platform,
250
+ }, payload, "group add item payload");
251
+ }
252
+ throw missingArgument("group add_item requires item_id or a tracking payload. Provide item_id to attach an existing tracking item, or provide track_type + track_value to create/link by value.");
253
+ }
254
+ function buildBulkGroupAddBody(payload) {
255
+ if (Array.isArray(payload.item_ids) && payload.item_ids.length > 0) {
256
+ return payload.item_ids.map((item_id) => ({ item_id }));
257
+ }
258
+ if (Array.isArray(payload.items) && payload.items.length > 0) {
259
+ return payload.items.map((item, index) => buildGroupAddPayloadFromItem(item, payload, `items[${index}]`));
260
+ }
261
+ if (payload.item_id || payload.track_value || payload.name) {
262
+ return [buildSingleGroupAddBody(payload)];
263
+ }
264
+ throw missingArgument("group add_items requires item_ids, items, or a single item payload. Use item_ids to bulk attach existing tracking items, or use items with track_type/type for value-based adds.");
265
+ }
266
+ function translateTrackingAction(payload, workspaceId) {
267
+ const action = payload.action ? String(payload.action).toLowerCase() : null;
268
+ if (!action || action === "create" || action === "item_create") {
269
+ return {
270
+ method: "POST",
271
+ pathSuffix: buildPathWithQuery("", { workspace_id: workspaceId || undefined }),
272
+ body: stripUndefinedEntries({
273
+ name: payload.name,
274
+ track_type: payload.track_type,
275
+ track_value: payload.track_value,
276
+ refresh_frequency: payload.refresh_frequency,
277
+ next_refresh_at: payload.next_refresh_at,
278
+ region: payload.region,
279
+ platform: payload.platform,
280
+ brand_ids: payload.brand_ids,
281
+ }),
282
+ workspaceId,
283
+ };
284
+ }
285
+ if (action === "list" || action === "item_list") {
286
+ const limit = Number.isFinite(payload.limit) ? payload.limit : 20;
287
+ const page = Number.isFinite(payload.page) ? Math.max(1, payload.page) : 1;
288
+ const offset = Number.isFinite(payload.offset)
289
+ ? Math.max(0, payload.offset)
290
+ : (page - 1) * limit;
291
+ const isActive = typeof payload.is_active === "boolean"
292
+ ? payload.is_active
293
+ : (payload.include_inactive ? undefined : true);
294
+ return {
295
+ method: "GET",
296
+ pathSuffix: buildPathWithQuery("", {
297
+ workspace_id: workspaceId || undefined,
298
+ limit,
299
+ offset,
300
+ track_type: payload.track_type,
301
+ track_value: payload.track_value,
302
+ platform: payload.platform,
303
+ region: payload.region,
304
+ is_active: isActive,
305
+ }),
306
+ body: undefined,
307
+ workspaceId,
308
+ };
309
+ }
310
+ if (action === "get" || action === "item_get") {
311
+ const itemId = coercePositiveInteger(payload.item_id, "item_id");
312
+ if (!itemId) {
313
+ throw missingArgument("item_id is required for tracking get.");
314
+ }
315
+ return {
316
+ method: "GET",
317
+ pathSuffix: buildPathWithQuery(`/${itemId}`, { workspace_id: workspaceId || undefined }),
318
+ body: undefined,
319
+ workspaceId,
320
+ };
321
+ }
322
+ if (action === "resolve" ||
323
+ action === "item_resolve" ||
324
+ action === "get_by_value" ||
325
+ action === "item_get_by_value") {
326
+ if (!payload.track_type || !payload.track_value) {
327
+ throw missingArgument("track_type and track_value are required for tracking resolve.");
328
+ }
329
+ return {
330
+ method: "GET",
331
+ pathSuffix: buildPathWithQuery("", {
332
+ workspace_id: workspaceId || undefined,
333
+ resolve: "true",
334
+ track_type: payload.track_type,
335
+ track_value: payload.track_value,
336
+ platform: payload.platform,
337
+ region: payload.region,
338
+ }),
339
+ body: undefined,
340
+ workspaceId,
341
+ };
342
+ }
343
+ if (action === "update" || action === "item_update") {
344
+ const itemId = coercePositiveInteger(payload.item_id, "item_id");
345
+ if (!itemId) {
346
+ throw missingArgument("item_id is required for tracking update.");
347
+ }
348
+ return {
349
+ method: "PATCH",
350
+ pathSuffix: buildPathWithQuery(`/${itemId}`, { workspace_id: workspaceId || undefined }),
351
+ body: stripUndefinedEntries({
352
+ refresh_frequency: payload.refresh_frequency,
353
+ next_refresh_at: payload.next_refresh_at,
354
+ }),
355
+ workspaceId,
356
+ };
357
+ }
358
+ if (action === "delete" || action === "item_delete") {
359
+ const itemId = coercePositiveInteger(payload.item_id, "item_id");
360
+ if (!itemId) {
361
+ throw missingArgument("item_id is required for tracking delete.");
362
+ }
363
+ return {
364
+ method: "DELETE",
365
+ pathSuffix: buildPathWithQuery(`/${itemId}`, { workspace_id: workspaceId || undefined }),
366
+ body: undefined,
367
+ workspaceId,
368
+ };
369
+ }
370
+ if (action === "refresh" || action === "item_refresh") {
371
+ const itemId = coercePositiveInteger(payload.item_id, "item_id");
372
+ if (!itemId) {
373
+ throw missingArgument("item_id is required for tracking refresh.");
374
+ }
375
+ return {
376
+ method: "POST",
377
+ pathSuffix: buildPathWithQuery(`/${itemId}/refresh`, { workspace_id: workspaceId || undefined }),
378
+ body: {},
379
+ workspaceId,
380
+ };
381
+ }
382
+ throw invalidArgument(`Unsupported tracking action: ${String(payload.action)}. Supported tracking actions: list, get, resolve, create, update, delete, refresh.`);
383
+ }
384
+ function translateGroupManagementAction(payload, workspaceId) {
385
+ const action = payload.action ? String(payload.action).toLowerCase() : null;
386
+ if (!action || action === "create" || action === "group_create") {
387
+ return {
388
+ method: "POST",
389
+ pathSuffix: buildPathWithQuery("/groups", { workspace_id: workspaceId || undefined }),
390
+ body: stripUndefinedEntries({
391
+ name: payload.name,
392
+ description: payload.description,
393
+ platform: payload.platform,
394
+ refresh_frequency: payload.refresh_frequency,
395
+ next_refresh_at: payload.next_refresh_at,
396
+ brand_id: payload.brand_id,
397
+ }),
398
+ workspaceId,
399
+ };
400
+ }
401
+ if (action === "list" || action === "group_list") {
402
+ return {
403
+ method: "GET",
404
+ pathSuffix: buildPathWithQuery("/groups", { workspace_id: workspaceId || undefined }),
405
+ body: undefined,
406
+ workspaceId,
407
+ };
408
+ }
409
+ if (action === "get" || action === "group_get") {
410
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
411
+ if (!groupId) {
412
+ throw missingArgument("group_id is required for group get.");
413
+ }
414
+ return {
415
+ method: "GET",
416
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}`, { workspace_id: workspaceId || undefined }),
417
+ body: undefined,
418
+ workspaceId,
419
+ };
420
+ }
421
+ if (action === "update" || action === "group_update") {
422
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
423
+ if (!groupId) {
424
+ throw missingArgument("group_id is required for group update.");
425
+ }
426
+ return {
427
+ method: "PATCH",
428
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}`, { workspace_id: workspaceId || undefined }),
429
+ body: stripUndefinedEntries({
430
+ name: payload.name,
431
+ description: payload.description,
432
+ refresh_frequency: payload.refresh_frequency,
433
+ next_refresh_at: payload.next_refresh_at,
434
+ brand_id: payload.brand_id,
435
+ }),
436
+ workspaceId,
437
+ };
438
+ }
439
+ if (action === "delete" || action === "group_delete") {
440
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
441
+ if (!groupId) {
442
+ throw missingArgument("group_id is required for group delete.");
443
+ }
444
+ return {
445
+ method: "DELETE",
446
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}`, { workspace_id: workspaceId || undefined }),
447
+ body: undefined,
448
+ workspaceId,
449
+ };
450
+ }
451
+ if (action === "refresh" || action === "group_refresh") {
452
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
453
+ if (!groupId) {
454
+ throw missingArgument("group_id is required for group refresh.");
455
+ }
456
+ return {
457
+ method: "POST",
458
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}/refresh`, { workspace_id: workspaceId || undefined }),
459
+ body: {},
460
+ workspaceId,
461
+ };
462
+ }
463
+ if (action === "list_items" || action === "group_list_items") {
464
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
465
+ if (!groupId) {
466
+ throw missingArgument("group_id is required for group list_items.");
467
+ }
468
+ return {
469
+ method: "GET",
470
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}/items`, {
471
+ workspace_id: workspaceId || undefined,
472
+ page: Number.isFinite(payload.page) ? payload.page : undefined,
473
+ limit: Number.isFinite(payload.limit) ? payload.limit : undefined,
474
+ }),
475
+ body: undefined,
476
+ workspaceId,
477
+ };
478
+ }
479
+ if (action === "add_item" || action === "group_add_item") {
480
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
481
+ if (!groupId) {
482
+ throw missingArgument("group_id is required for group add_item.");
483
+ }
484
+ return {
485
+ method: "POST",
486
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}/items`, { workspace_id: workspaceId || undefined }),
487
+ body: buildSingleGroupAddBody(payload),
488
+ workspaceId,
489
+ };
490
+ }
491
+ if (action === "add_items" || action === "group_add_items") {
492
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
493
+ if (!groupId) {
494
+ throw missingArgument("group_id is required for group add_items.");
495
+ }
496
+ return {
497
+ method: "POST",
498
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}/items/bulk`, { workspace_id: workspaceId || undefined }),
499
+ body: buildBulkGroupAddBody(payload),
500
+ workspaceId,
501
+ };
502
+ }
503
+ if (action === "completeness" || action === "group_completeness") {
504
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
505
+ if (!groupId) {
506
+ throw missingArgument("group_id is required for group completeness.");
507
+ }
508
+ const expectedItems = Array.isArray(payload.expected_items)
509
+ ? payload.expected_items
510
+ : (Array.isArray(payload.items) ? payload.items : undefined);
511
+ return {
512
+ method: "POST",
513
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}/completeness`, {
514
+ workspace_id: workspaceId || undefined,
515
+ }),
516
+ body: stripUndefinedEntries({
517
+ expected_items: expectedItems,
518
+ include_refresh_status: firstDefined(payload, ["include_refresh_status", "includeRefreshStatus"]),
519
+ }),
520
+ workspaceId,
521
+ };
522
+ }
523
+ if (action === "remove_item" || action === "group_remove_item") {
524
+ const groupId = coercePositiveInteger(payload.group_id, "group_id");
525
+ const itemId = coercePositiveInteger(payload.item_id, "item_id");
526
+ if (!groupId || !itemId) {
527
+ throw missingArgument("group_id and item_id are required for group remove_item.");
528
+ }
529
+ return {
530
+ method: "DELETE",
531
+ pathSuffix: buildPathWithQuery(`/groups/${groupId}/items/${itemId}`, {
532
+ workspace_id: workspaceId || undefined,
533
+ }),
534
+ body: undefined,
535
+ workspaceId,
536
+ };
537
+ }
538
+ throw invalidArgument(`Unsupported group-management action: ${String(payload.action)}. Supported group-management actions: list, get, create, update, delete, refresh, list_items, add_item, add_items, completeness, remove_item.`);
539
+ }
540
+ function translateBrandGroupAction(payload, workspaceId) {
541
+ const action = payload.action ? String(payload.action).toLowerCase() : null;
542
+ const brandGroupId = payload.brand_group_id || undefined;
543
+ const effectiveWorkspaceId = payload.workspace_id || workspaceId || undefined;
544
+ if (!action || action === "create") {
545
+ return {
546
+ method: "POST",
547
+ pathSuffix: "",
548
+ body: stripUndefinedEntries({
549
+ name: payload.name,
550
+ description: payload.description,
551
+ workspace_id: effectiveWorkspaceId,
552
+ }),
553
+ workspaceId: workspaceId || null,
554
+ };
555
+ }
556
+ if (action === "list") {
557
+ return {
558
+ method: "GET",
559
+ pathSuffix: buildPathWithQuery("", { workspace_id: effectiveWorkspaceId }),
560
+ body: undefined,
561
+ workspaceId: workspaceId || null,
562
+ };
563
+ }
564
+ if (action === "update") {
565
+ if (!brandGroupId) {
566
+ throw missingArgument("brand_group_id is required for brand-group update.");
567
+ }
568
+ return {
569
+ method: "PATCH",
570
+ pathSuffix: `/${brandGroupId}`,
571
+ body: stripUndefinedEntries({
572
+ name: payload.name,
573
+ description: payload.description,
574
+ }),
575
+ workspaceId: workspaceId || null,
576
+ };
577
+ }
578
+ if (action === "delete") {
579
+ if (!brandGroupId) {
580
+ throw missingArgument("brand_group_id is required for brand-group delete.");
581
+ }
582
+ return {
583
+ method: "DELETE",
584
+ pathSuffix: `/${brandGroupId}`,
585
+ body: undefined,
586
+ workspaceId: workspaceId || null,
587
+ };
588
+ }
589
+ if (action === "add_member") {
590
+ if (!brandGroupId || !payload.brand_id) {
591
+ throw missingArgument("brand_group_id and brand_id are required for brand-group add_member.");
592
+ }
593
+ return {
594
+ method: "POST",
595
+ pathSuffix: `/${brandGroupId}/members`,
596
+ body: { brand_id: payload.brand_id },
597
+ workspaceId: workspaceId || null,
598
+ };
599
+ }
600
+ if (action === "remove_member") {
601
+ if (!brandGroupId || !payload.brand_id) {
602
+ throw missingArgument("brand_group_id and brand_id are required for brand-group remove_member.");
603
+ }
604
+ return {
605
+ method: "DELETE",
606
+ pathSuffix: `/${brandGroupId}/members/${payload.brand_id}`,
607
+ body: undefined,
608
+ workspaceId: workspaceId || null,
609
+ };
610
+ }
611
+ throw invalidArgument(`Unsupported brand-group-management action: ${String(payload.action)}. Supported brand-group-management actions: list, create, update, delete, add_member, remove_member.`);
612
+ }
613
+ export function translateToolInvocation(options) {
614
+ const { toolName, payload, workspaceId } = options;
615
+ if (toolName === "tracking") {
616
+ const normalizedPayload = normalizeTrackingPayload(payload, workspaceId);
617
+ const effectiveWorkspaceId = normalizedPayload.workspaceId || workspaceId || null;
618
+ const translated = translateTrackingAction(normalizedPayload, effectiveWorkspaceId);
619
+ return { ...translated, normalizedPayload };
620
+ }
621
+ if (toolName === "group-management") {
622
+ const normalizedPayload = normalizeGroupManagementPayload(payload, workspaceId);
623
+ const effectiveWorkspaceId = normalizedPayload.workspaceId || workspaceId || null;
624
+ const translated = translateGroupManagementAction(normalizedPayload, effectiveWorkspaceId);
625
+ return { ...translated, normalizedPayload };
626
+ }
627
+ if (toolName === "brand-group-management") {
628
+ const normalizedPayload = normalizeBrandGroupPayload(payload, workspaceId);
629
+ const effectiveWorkspaceId = normalizedPayload.workspaceId || workspaceId || null;
630
+ const translated = translateBrandGroupAction(normalizedPayload, effectiveWorkspaceId);
631
+ return { ...translated, normalizedPayload };
632
+ }
633
+ if (toolName === "export_tracking_data") {
634
+ const normalizedPayload = normalizeTrackingExportPayload(payload, workspaceId);
635
+ return {
636
+ method: "POST",
637
+ pathSuffix: "",
638
+ body: normalizedPayload,
639
+ workspaceId: normalizedPayload.workspace_id || workspaceId || null,
640
+ normalizedPayload,
641
+ };
642
+ }
643
+ return null;
644
+ }
645
+ // --- search_results_enriched report shim (CLI: data export-report/export-search-results) ---
646
+ export const SEARCH_RESULTS_ENRICHED_REPORT_TYPE = "search_results_enriched";
647
+ export const EXPORT_DATA_TEMPLATE_TRACKING_RANKED_VIDEOS_RAW = "tracking_ranked_videos_raw";
648
+ function normalizePositiveIntegerList(value, label, { max } = {}) {
649
+ if (value === undefined || value === null || value === "")
650
+ return [];
651
+ const entries = Array.isArray(value)
652
+ ? value
653
+ : String(value)
654
+ .split(",")
655
+ .map((entry) => entry.trim())
656
+ .filter(Boolean);
657
+ const parsed = entries.map((entry, index) => {
658
+ const normalized = coercePositiveInteger(entry, `${label}[${index}]`);
659
+ if (!normalized) {
660
+ throw invalidArgument(`Invalid ${label}[${index}] value.`);
661
+ }
662
+ return normalized;
663
+ });
664
+ const deduped = Array.from(new Set(parsed));
665
+ if (max && deduped.length > max) {
666
+ throw invalidArgument(`Too many ${label} values: received ${deduped.length}, max is ${max}.`);
667
+ }
668
+ return deduped;
669
+ }
670
+ function normalizeIsoDateTime(value, label) {
671
+ if (value === undefined || value === null || value === "")
672
+ return undefined;
673
+ if (typeof value !== "string") {
674
+ throw invalidArgument(`Invalid ${label}: expected an ISO datetime string.`);
675
+ }
676
+ const epoch = Date.parse(value.trim());
677
+ if (Number.isNaN(epoch)) {
678
+ throw invalidArgument(`Invalid ${label}: expected an ISO datetime string.`, value);
679
+ }
680
+ return new Date(epoch).toISOString();
681
+ }
682
+ export function buildSearchResultsEnrichedExportPayload(rawPayload, workspaceId) {
683
+ const payload = isJsonObject(rawPayload) ? rawPayload : {};
684
+ const groupIds = normalizePositiveIntegerList(firstDefined(payload, ["groupIds", "group_ids"]), "groupIds", { max: 100 });
685
+ if (groupIds.length === 0) {
686
+ throw missingArgument("search_results_enriched export requires at least one group id. Include groupIds in payload.");
687
+ }
688
+ const trackingItemIds = normalizePositiveIntegerList(firstDefined(payload, ["trackingItemIds", "tracking_item_ids"]), "trackingItemIds", { max: 1000 });
689
+ const dateFrom = normalizeIsoDateTime(firstDefined(payload, ["dateFrom", "date_from"]), "dateFrom");
690
+ const dateTo = normalizeIsoDateTime(firstDefined(payload, ["dateTo", "date_to"]), "dateTo");
691
+ const filename = trimString(firstDefined(payload, ["filename"])) || undefined;
692
+ return {
693
+ payload: stripUndefinedEntries({
694
+ workspaceId,
695
+ groupIds,
696
+ trackingItemIds: trackingItemIds.length > 0 ? trackingItemIds : undefined,
697
+ dateFrom,
698
+ dateTo,
699
+ }),
700
+ filename,
701
+ };
702
+ }
703
+ //# sourceMappingURL=translation.js.map