@exileum/meta-mcp 6.0.0 → 8.0.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 +44 -18
- package/dist/constants/fields.d.ts +6 -0
- package/dist/constants/fields.d.ts.map +1 -0
- package/dist/constants/fields.js +25 -0
- package/dist/constants/fields.js.map +1 -0
- package/dist/http-transport.d.ts +20 -0
- package/dist/http-transport.d.ts.map +1 -0
- package/dist/http-transport.js +228 -0
- package/dist/http-transport.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +77 -82
- package/dist/index.js.map +1 -1
- package/dist/prompts/index.d.ts +56 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +264 -41
- package/dist/prompts/index.js.map +1 -1
- package/dist/register-all.d.ts +4 -0
- package/dist/register-all.d.ts.map +1 -0
- package/dist/register-all.js +41 -0
- package/dist/register-all.js.map +1 -0
- package/dist/resources/instagram.d.ts.map +1 -1
- package/dist/resources/instagram.js +13 -4
- package/dist/resources/instagram.js.map +1 -1
- package/dist/resources/threads.d.ts.map +1 -1
- package/dist/resources/threads.js +13 -4
- package/dist/resources/threads.js.map +1 -1
- package/dist/services/meta-client.d.ts +76 -3
- package/dist/services/meta-client.d.ts.map +1 -1
- package/dist/services/meta-client.js +330 -46
- package/dist/services/meta-client.js.map +1 -1
- package/dist/shutdown.d.ts +18 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +60 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/tools/annotations.d.ts +6 -0
- package/dist/tools/annotations.d.ts.map +1 -0
- package/dist/tools/annotations.js +27 -0
- package/dist/tools/annotations.js.map +1 -0
- package/dist/tools/instagram/comments.d.ts.map +1 -1
- package/dist/tools/instagram/comments.js +75 -50
- package/dist/tools/instagram/comments.js.map +1 -1
- package/dist/tools/instagram/hashtags.d.ts +1 -0
- package/dist/tools/instagram/hashtags.d.ts.map +1 -1
- package/dist/tools/instagram/hashtags.js +54 -36
- package/dist/tools/instagram/hashtags.js.map +1 -1
- package/dist/tools/instagram/media.d.ts.map +1 -1
- package/dist/tools/instagram/media.js +53 -34
- package/dist/tools/instagram/media.js.map +1 -1
- package/dist/tools/instagram/mentions.d.ts.map +1 -1
- package/dist/tools/instagram/mentions.js +22 -17
- package/dist/tools/instagram/mentions.js.map +1 -1
- package/dist/tools/instagram/messaging.d.ts.map +1 -1
- package/dist/tools/instagram/messaging.js +74 -50
- package/dist/tools/instagram/messaging.js.map +1 -1
- package/dist/tools/instagram/profile.d.ts +2 -0
- package/dist/tools/instagram/profile.d.ts.map +1 -1
- package/dist/tools/instagram/profile.js +63 -43
- package/dist/tools/instagram/profile.js.map +1 -1
- package/dist/tools/instagram/publishing.d.ts.map +1 -1
- package/dist/tools/instagram/publishing.js +202 -139
- package/dist/tools/instagram/publishing.js.map +1 -1
- package/dist/tools/meta/auth.d.ts.map +1 -1
- package/dist/tools/meta/auth.js +63 -21
- package/dist/tools/meta/auth.js.map +1 -1
- package/dist/tools/threads/insights.d.ts.map +1 -1
- package/dist/tools/threads/insights.js +22 -15
- package/dist/tools/threads/insights.js.map +1 -1
- package/dist/tools/threads/media.d.ts.map +1 -1
- package/dist/tools/threads/media.js +42 -70
- package/dist/tools/threads/media.js.map +1 -1
- package/dist/tools/threads/mentions.d.ts.map +1 -1
- package/dist/tools/threads/mentions.js +15 -16
- package/dist/tools/threads/mentions.js.map +1 -1
- package/dist/tools/threads/profile.d.ts +2 -0
- package/dist/tools/threads/profile.d.ts.map +1 -1
- package/dist/tools/threads/profile.js +18 -3
- package/dist/tools/threads/profile.js.map +1 -1
- package/dist/tools/threads/publishing.d.ts.map +1 -1
- package/dist/tools/threads/publishing.js +260 -157
- package/dist/tools/threads/publishing.js.map +1 -1
- package/dist/tools/threads/replies.d.ts.map +1 -1
- package/dist/tools/threads/replies.js +55 -45
- package/dist/tools/threads/replies.js.map +1 -1
- package/dist/utils/container.d.ts +16 -4
- package/dist/utils/container.d.ts.map +1 -1
- package/dist/utils/container.js +36 -6
- package/dist/utils/container.js.map +1 -1
- package/dist/utils/errors.d.ts +23 -3
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +32 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/logger.d.ts +28 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/params.d.ts +3 -0
- package/dist/utils/params.d.ts.map +1 -0
- package/dist/utils/params.js +14 -0
- package/dist/utils/params.js.map +1 -0
- package/dist/utils/progress.d.ts +42 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +35 -0
- package/dist/utils/progress.js.map +1 -0
- package/dist/utils/response.d.ts +11 -0
- package/dist/utils/response.d.ts.map +1 -0
- package/dist/utils/response.js +6 -0
- package/dist/utils/response.js.map +1 -0
- package/package.json +5 -4
package/dist/tools/meta/auth.js
CHANGED
|
@@ -1,67 +1,105 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { httpsUrl } from "../../schemas.js";
|
|
3
3
|
import { formatErrorResponse } from "../../utils/errors.js";
|
|
4
|
+
import { formatResponse } from "../../utils/response.js";
|
|
5
|
+
import { READ_ONLY_TOOL, WRITE_TOOL, WRITE_IDEMPOTENT_TOOL } from "../annotations.js";
|
|
6
|
+
function applyTokenIfPresent(client, platform, data, source) {
|
|
7
|
+
// Guard against malformed/empty responses — overwriting a working token with
|
|
8
|
+
// `undefined` or `""` would silently brick the running session (#65).
|
|
9
|
+
const newToken = typeof data.access_token === "string" && data.access_token
|
|
10
|
+
? data.access_token
|
|
11
|
+
: undefined;
|
|
12
|
+
if (!newToken)
|
|
13
|
+
return;
|
|
14
|
+
client.updateConfig(platform === "threads"
|
|
15
|
+
? { threadsAccessToken: newToken }
|
|
16
|
+
: { instagramAccessToken: newToken });
|
|
17
|
+
const platformLabel = platform === "threads" ? "Threads" : "Instagram";
|
|
18
|
+
console.error(`[meta-mcp] ${platformLabel} access token updated in-memory after ${source}; subsequent tool calls will use the new token (no restart required).`);
|
|
19
|
+
}
|
|
4
20
|
export function registerMetaAuthTools(server, client) {
|
|
5
21
|
// ─── meta_exchange_token ─────────────────────────────────────
|
|
6
|
-
server.
|
|
7
|
-
|
|
8
|
-
|
|
22
|
+
server.registerTool("meta_exchange_token", {
|
|
23
|
+
description: "Exchange a short-lived token for a long-lived token (valid ~60 days). Uses platform-specific endpoints: Instagram (graph.instagram.com) or Threads (graph.threads.net). Requires META_APP_SECRET. On success the new token is also applied in-memory to the running server, so subsequent tool calls use it immediately — no restart required (#65).",
|
|
24
|
+
inputSchema: {
|
|
25
|
+
short_lived_token: z.string().describe("Short-lived access token to exchange"),
|
|
26
|
+
platform: z.enum(["instagram", "threads"]).describe("Target platform: 'instagram' or 'threads'"),
|
|
27
|
+
},
|
|
28
|
+
annotations: WRITE_TOOL,
|
|
9
29
|
}, async ({ short_lived_token, platform }) => {
|
|
10
30
|
try {
|
|
11
31
|
const { data, rateLimit } = platform === "threads"
|
|
12
32
|
? await client.threadsExchangeToken(short_lived_token)
|
|
13
33
|
: await client.igExchangeToken(short_lived_token);
|
|
14
|
-
|
|
34
|
+
applyTokenIfPresent(client, platform, data, "meta_exchange_token");
|
|
35
|
+
return formatResponse(data, rateLimit);
|
|
15
36
|
}
|
|
16
37
|
catch (error) {
|
|
17
38
|
return formatErrorResponse(error, "Token exchange");
|
|
18
39
|
}
|
|
19
40
|
});
|
|
20
41
|
// ─── meta_refresh_token ──────────────────────────────────────
|
|
21
|
-
server.
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
server.registerTool("meta_refresh_token", {
|
|
43
|
+
description: "Refresh a long-lived token before it expires (must be at least 24h old). Uses platform-specific endpoints: Instagram (graph.instagram.com) or Threads (graph.threads.net). Returns a new long-lived token valid for 60 days. On success the new token is also applied in-memory to the running server, so subsequent tool calls use it immediately — no restart required (#65).",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
long_lived_token: z.string().describe("Current long-lived access token to refresh"),
|
|
46
|
+
platform: z.enum(["instagram", "threads"]).describe("Target platform: 'instagram' or 'threads'"),
|
|
47
|
+
},
|
|
48
|
+
annotations: WRITE_TOOL,
|
|
24
49
|
}, async ({ long_lived_token, platform }) => {
|
|
25
50
|
try {
|
|
26
51
|
const { data, rateLimit } = platform === "threads"
|
|
27
52
|
? await client.threadsRefreshToken(long_lived_token)
|
|
28
53
|
: await client.igRefreshToken(long_lived_token);
|
|
29
|
-
|
|
54
|
+
applyTokenIfPresent(client, platform, data, "meta_refresh_token");
|
|
55
|
+
return formatResponse(data, rateLimit);
|
|
30
56
|
}
|
|
31
57
|
catch (error) {
|
|
32
58
|
return formatErrorResponse(error, "Token refresh");
|
|
33
59
|
}
|
|
34
60
|
});
|
|
35
61
|
// ─── meta_debug_token ────────────────────────────────────────
|
|
36
|
-
server.
|
|
37
|
-
|
|
62
|
+
server.registerTool("meta_debug_token", {
|
|
63
|
+
description: "Debug/inspect an access token to check validity, expiration, scopes and associated user.",
|
|
64
|
+
inputSchema: {
|
|
65
|
+
input_token: z.string().describe("Access token to inspect"),
|
|
66
|
+
},
|
|
67
|
+
annotations: READ_ONLY_TOOL,
|
|
38
68
|
}, async ({ input_token }) => {
|
|
39
69
|
try {
|
|
40
70
|
const { data, rateLimit } = await client.debugToken(input_token);
|
|
41
|
-
return
|
|
71
|
+
return formatResponse(data, rateLimit);
|
|
42
72
|
}
|
|
43
73
|
catch (error) {
|
|
44
74
|
return formatErrorResponse(error, "Token debug");
|
|
45
75
|
}
|
|
46
76
|
});
|
|
47
77
|
// ─── meta_get_app_info ───────────────────────────────────────
|
|
48
|
-
server.
|
|
78
|
+
server.registerTool("meta_get_app_info", {
|
|
79
|
+
description: "Get Meta App basic information (name, category, namespace, etc.).",
|
|
80
|
+
inputSchema: {},
|
|
81
|
+
annotations: READ_ONLY_TOOL,
|
|
82
|
+
}, async () => {
|
|
49
83
|
try {
|
|
50
84
|
const { data, rateLimit } = await client.meta("GET", `/app`, {
|
|
51
85
|
fields: "id,name,category,namespace,link,company,description",
|
|
52
86
|
});
|
|
53
|
-
return
|
|
87
|
+
return formatResponse(data, rateLimit);
|
|
54
88
|
}
|
|
55
89
|
catch (error) {
|
|
56
90
|
return formatErrorResponse(error, "Get app info");
|
|
57
91
|
}
|
|
58
92
|
});
|
|
59
93
|
// ─── meta_subscribe_webhook ──────────────────────────────────
|
|
60
|
-
server.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
94
|
+
server.registerTool("meta_subscribe_webhook", {
|
|
95
|
+
description: "Subscribe to webhook notifications for an object (e.g., 'instagram', 'page'). Requires META_APP_ID and META_APP_SECRET.",
|
|
96
|
+
inputSchema: {
|
|
97
|
+
object: z.enum(["instagram", "page", "user", "permissions"]).describe("Object type to subscribe to"),
|
|
98
|
+
callback_url: httpsUrl.describe("HTTPS webhook endpoint URL"),
|
|
99
|
+
verify_token: z.string().describe("Verification token for the webhook"),
|
|
100
|
+
fields: z.string().describe("Comma-separated list of fields to subscribe (e.g., 'messages,feed')"),
|
|
101
|
+
},
|
|
102
|
+
annotations: WRITE_IDEMPOTENT_TOOL,
|
|
65
103
|
}, async ({ object, callback_url, verify_token, fields }) => {
|
|
66
104
|
try {
|
|
67
105
|
const { data, rateLimit } = await client.meta("POST", `/app/subscriptions`, {
|
|
@@ -70,17 +108,21 @@ export function registerMetaAuthTools(server, client) {
|
|
|
70
108
|
verify_token,
|
|
71
109
|
fields,
|
|
72
110
|
});
|
|
73
|
-
return
|
|
111
|
+
return formatResponse(data, rateLimit);
|
|
74
112
|
}
|
|
75
113
|
catch (error) {
|
|
76
114
|
return formatErrorResponse(error, "Webhook subscribe");
|
|
77
115
|
}
|
|
78
116
|
});
|
|
79
117
|
// ─── meta_get_webhook_subscriptions ──────────────────────────
|
|
80
|
-
server.
|
|
118
|
+
server.registerTool("meta_get_webhook_subscriptions", {
|
|
119
|
+
description: "List current webhook subscriptions for the Meta App.",
|
|
120
|
+
inputSchema: {},
|
|
121
|
+
annotations: READ_ONLY_TOOL,
|
|
122
|
+
}, async () => {
|
|
81
123
|
try {
|
|
82
124
|
const { data, rateLimit } = await client.meta("GET", `/app/subscriptions`);
|
|
83
|
-
return
|
|
125
|
+
return formatResponse(data, rateLimit);
|
|
84
126
|
}
|
|
85
127
|
catch (error) {
|
|
86
128
|
return formatErrorResponse(error, "Get webhooks");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/tools/meta/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/tools/meta/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insights.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/insights.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"insights.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/insights.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAS3D,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA6CvF"}
|
|
@@ -1,36 +1,43 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { metaId } from "../../schemas.js";
|
|
3
3
|
import { formatErrorResponse } from "../../utils/errors.js";
|
|
4
|
+
import { formatResponse } from "../../utils/response.js";
|
|
5
|
+
import { buildParams } from "../../utils/params.js";
|
|
6
|
+
import { READ_ONLY_TOOL } from "../annotations.js";
|
|
4
7
|
const POST_INSIGHTS_DEFAULT_METRICS = "views,likes,replies,reposts,quotes,shares";
|
|
5
8
|
export function registerThreadsInsightTools(server, client) {
|
|
6
9
|
// ─── threads_get_post_insights ───────────────────────────────
|
|
7
|
-
server.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
server.registerTool("threads_get_post_insights", {
|
|
11
|
+
description: `Get insights/analytics for a specific Threads post (${POST_INSIGHTS_DEFAULT_METRICS.replaceAll(",", ", ")}).`,
|
|
12
|
+
inputSchema: {
|
|
13
|
+
post_id: metaId.describe("Threads post ID"),
|
|
14
|
+
metric: z.string().optional().default(POST_INSIGHTS_DEFAULT_METRICS).describe(`Comma-separated metrics (default: ${POST_INSIGHTS_DEFAULT_METRICS})`),
|
|
15
|
+
},
|
|
16
|
+
annotations: READ_ONLY_TOOL,
|
|
10
17
|
}, async ({ post_id, metric }) => {
|
|
11
18
|
try {
|
|
12
19
|
const { data, rateLimit } = await client.threads("GET", `/${post_id}/insights`, { metric });
|
|
13
|
-
return
|
|
20
|
+
return formatResponse(data, rateLimit);
|
|
14
21
|
}
|
|
15
22
|
catch (error) {
|
|
16
23
|
return formatErrorResponse(error, "Get post insights");
|
|
17
24
|
}
|
|
18
25
|
});
|
|
19
26
|
// ─── threads_get_user_insights ───────────────────────────────
|
|
20
|
-
server.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
server.registerTool("threads_get_user_insights", {
|
|
28
|
+
description: "Get account-level Threads insights (views, likes, replies, reposts, quotes, clicks, followers, follower demographics). Requires period parameter.",
|
|
29
|
+
inputSchema: {
|
|
30
|
+
metric: z.string().describe("Comma-separated metrics: views,likes,replies,reposts,quotes,clicks,followers_count,follower_demographics"),
|
|
31
|
+
period: z.enum(["day", "lifetime"]).optional().default("day").describe("Time aggregation period. Use 'day' for time-series metrics (views, likes, replies, reposts, quotes, followers_count). Use 'lifetime' only for follower_demographics."),
|
|
32
|
+
since: z.string().optional().describe("Start date (Unix timestamp). Required when period is 'day'."),
|
|
33
|
+
until: z.string().optional().describe("End date (Unix timestamp). Required when period is 'day'."),
|
|
34
|
+
},
|
|
35
|
+
annotations: READ_ONLY_TOOL,
|
|
25
36
|
}, async ({ metric, period, since, until }) => {
|
|
26
37
|
try {
|
|
27
|
-
const params = { metric, period };
|
|
28
|
-
if (since)
|
|
29
|
-
params.since = since;
|
|
30
|
-
if (until)
|
|
31
|
-
params.until = until;
|
|
38
|
+
const params = buildParams({ metric, period }, { since, until });
|
|
32
39
|
const { data, rateLimit } = await client.threads("GET", `/${client.threadsUserId}/threads_insights`, params);
|
|
33
|
-
return
|
|
40
|
+
return formatResponse(data, rateLimit);
|
|
34
41
|
}
|
|
35
42
|
catch (error) {
|
|
36
43
|
return formatErrorResponse(error, "Get user insights");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../../src/tools/threads/insights.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"insights.js","sourceRoot":"","sources":["../../../src/tools/threads/insights.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,6BAA6B,GAAG,2CAA2C,CAAC;AAElF,MAAM,UAAU,2BAA2B,CAAC,MAAiB,EAAE,MAAkB;IAC/E,gEAAgE;IAChE,MAAM,CAAC,YAAY,CACjB,2BAA2B,EAC3B;QACE,WAAW,EAAE,uDAAuD,6BAA6B,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI;QAC3H,WAAW,EAAE;YACX,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC;YAC3C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC,QAAQ,CAAC,qCAAqC,6BAA6B,GAAG,CAAC;SACrJ;QACD,WAAW,EAAE,cAAc;KAC5B,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE;QAC5B,IAAI,CAAC;YACH,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,OAAO,WAAW,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAC5F,OAAO,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CACF,CAAC;IAEF,gEAAgE;IAChE,MAAM,CAAC,YAAY,CACjB,2BAA2B,EAC3B;QACE,WAAW,EAAE,mJAAmJ;QAChK,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0GAA0G,CAAC;YACvI,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,sKAAsK,CAAC;YAC9O,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6DAA6D,CAAC;YACpG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;SACnG;QACD,WAAW,EAAE,cAAc;KAC5B,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;YACjE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,aAAa,mBAAmB,EAAE,MAAM,CAAC,CAAC;YAC7G,OAAO,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,mBAAmB,CAAC,KAAK,EAAE,mBAAmB,CAAC,CAAC;QACzD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"media.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAQ3D,eAAO,MAAM,oBAAoB,uEAQ9B,CAAC;AAEJ,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAkFrF"}
|
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { metaId } from "../../schemas.js";
|
|
3
|
+
import { THREADS_MEDIA_FIELDS } from "../../constants/fields.js";
|
|
3
4
|
import { formatErrorResponse } from "../../utils/errors.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"media_type",
|
|
8
|
-
"media_url",
|
|
9
|
-
"permalink",
|
|
10
|
-
"text",
|
|
11
|
-
"timestamp",
|
|
12
|
-
"shortcode",
|
|
13
|
-
"is_quote_post",
|
|
14
|
-
"has_replies",
|
|
15
|
-
"reply_audience",
|
|
16
|
-
"topic_tag",
|
|
17
|
-
"link_attachment_url",
|
|
18
|
-
"poll_attachment{option_a,option_b,option_c,option_d,option_a_votes_percentage,option_b_votes_percentage,option_c_votes_percentage,option_d_votes_percentage,total_votes,expiration_timestamp}",
|
|
19
|
-
"gif_url",
|
|
20
|
-
"alt_text",
|
|
21
|
-
].join(",");
|
|
5
|
+
import { formatResponse } from "../../utils/response.js";
|
|
6
|
+
import { buildParams } from "../../utils/params.js";
|
|
7
|
+
import { READ_ONLY_TOOL } from "../annotations.js";
|
|
22
8
|
export const authorUsernameSchema = z
|
|
23
9
|
.string()
|
|
24
10
|
.trim()
|
|
@@ -28,81 +14,67 @@ export const authorUsernameSchema = z
|
|
|
28
14
|
.describe("Filter results to posts by exact username (server-side filter via Threads /keyword_search; per Threads API the username must be an exact match without '@'; leading '@' characters and surrounding whitespace are auto-stripped if provided)");
|
|
29
15
|
export function registerThreadsMediaTools(server, client) {
|
|
30
16
|
// ─── threads_get_posts ───────────────────────────────────────
|
|
31
|
-
server.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
server.registerTool("threads_get_posts", {
|
|
18
|
+
description: "Get a list of Threads posts published by the authenticated user.",
|
|
19
|
+
inputSchema: {
|
|
20
|
+
limit: z.number().optional().describe("Number of results (default 25)"),
|
|
21
|
+
since: z.string().optional().describe("Start date (ISO 8601 or Unix timestamp)"),
|
|
22
|
+
until: z.string().optional().describe("End date (ISO 8601 or Unix timestamp)"),
|
|
23
|
+
after: z.string().optional().describe("Pagination cursor"),
|
|
24
|
+
before: z.string().optional().describe("Pagination cursor"),
|
|
25
|
+
fields: z.string().optional().default(THREADS_MEDIA_FIELDS).describe(`Comma-separated fields (default: ${THREADS_MEDIA_FIELDS})`),
|
|
26
|
+
},
|
|
27
|
+
annotations: READ_ONLY_TOOL,
|
|
38
28
|
}, async ({ limit, since, until, after, before, fields }) => {
|
|
39
29
|
try {
|
|
40
|
-
const params = { fields };
|
|
41
|
-
if (limit !== undefined)
|
|
42
|
-
params.limit = limit;
|
|
43
|
-
if (since)
|
|
44
|
-
params.since = since;
|
|
45
|
-
if (until)
|
|
46
|
-
params.until = until;
|
|
47
|
-
if (after)
|
|
48
|
-
params.after = after;
|
|
49
|
-
if (before)
|
|
50
|
-
params.before = before;
|
|
30
|
+
const params = buildParams({ fields }, { limit, since, until, after, before });
|
|
51
31
|
const { data, rateLimit } = await client.threads("GET", `/${client.threadsUserId}/threads`, params);
|
|
52
|
-
return
|
|
32
|
+
return formatResponse(data, rateLimit);
|
|
53
33
|
}
|
|
54
34
|
catch (error) {
|
|
55
35
|
return formatErrorResponse(error, "Get posts");
|
|
56
36
|
}
|
|
57
37
|
});
|
|
58
38
|
// ─── threads_get_post ────────────────────────────────────────
|
|
59
|
-
server.
|
|
60
|
-
|
|
61
|
-
|
|
39
|
+
server.registerTool("threads_get_post", {
|
|
40
|
+
description: "Get details of a specific Threads post.",
|
|
41
|
+
inputSchema: {
|
|
42
|
+
post_id: metaId.describe("Threads post ID"),
|
|
43
|
+
fields: z.string().optional().default(THREADS_MEDIA_FIELDS).describe(`Comma-separated fields (default: ${THREADS_MEDIA_FIELDS})`),
|
|
44
|
+
},
|
|
45
|
+
annotations: READ_ONLY_TOOL,
|
|
62
46
|
}, async ({ post_id, fields }) => {
|
|
63
47
|
try {
|
|
64
48
|
const { data, rateLimit } = await client.threads("GET", `/${post_id}`, { fields });
|
|
65
|
-
return
|
|
49
|
+
return formatResponse(data, rateLimit);
|
|
66
50
|
}
|
|
67
51
|
catch (error) {
|
|
68
52
|
return formatErrorResponse(error, "Get post");
|
|
69
53
|
}
|
|
70
54
|
});
|
|
71
55
|
// ─── threads_search_posts ────────────────────────────────────
|
|
72
|
-
server.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
56
|
+
server.registerTool("threads_search_posts", {
|
|
57
|
+
description: "Search for public Threads posts by keyword or topic tag. Requires threads_keyword_search permission.",
|
|
58
|
+
inputSchema: {
|
|
59
|
+
q: z.string().describe("Search keyword or query"),
|
|
60
|
+
search_type: z.enum(["TOP", "RECENT"]).optional().describe("Result ordering: TOP (default) or RECENT"),
|
|
61
|
+
search_mode: z.enum(["KEYWORD", "TAG"]).optional().describe("Search by KEYWORD (default) or TAG"),
|
|
62
|
+
media_type: z.enum(["TEXT", "IMAGE", "VIDEO"]).optional().describe("Filter results by media type"),
|
|
63
|
+
author_username: authorUsernameSchema,
|
|
64
|
+
since: z.string().optional().describe("Start date (Unix timestamp)"),
|
|
65
|
+
until: z.string().optional().describe("End date (Unix timestamp)"),
|
|
66
|
+
limit: z.number().min(1).max(100).optional().describe("Number of results (max 100, default 25)"),
|
|
67
|
+
after: z.string().optional().describe("Pagination cursor"),
|
|
68
|
+
},
|
|
69
|
+
annotations: READ_ONLY_TOOL,
|
|
82
70
|
}, async ({ q, search_type, search_mode, media_type, author_username, since, until, limit, after }) => {
|
|
83
71
|
try {
|
|
84
|
-
const params = {
|
|
72
|
+
const params = buildParams({
|
|
85
73
|
q,
|
|
86
74
|
fields: "id,text,username,permalink,timestamp,media_type,media_url,topic_tag",
|
|
87
|
-
};
|
|
88
|
-
if (search_type)
|
|
89
|
-
params.search_type = search_type;
|
|
90
|
-
if (search_mode)
|
|
91
|
-
params.search_mode = search_mode;
|
|
92
|
-
if (media_type)
|
|
93
|
-
params.media_type = media_type;
|
|
94
|
-
if (author_username)
|
|
95
|
-
params.author_username = author_username;
|
|
96
|
-
if (since)
|
|
97
|
-
params.since = since;
|
|
98
|
-
if (until)
|
|
99
|
-
params.until = until;
|
|
100
|
-
if (limit !== undefined)
|
|
101
|
-
params.limit = limit;
|
|
102
|
-
if (after)
|
|
103
|
-
params.after = after;
|
|
75
|
+
}, { search_type, search_mode, media_type, author_username, since, until, limit, after });
|
|
104
76
|
const { data, rateLimit } = await client.threads("GET", `/keyword_search`, params);
|
|
105
|
-
return
|
|
77
|
+
return formatResponse(data, rateLimit);
|
|
106
78
|
}
|
|
107
79
|
catch (error) {
|
|
108
80
|
return formatErrorResponse(error, "Search posts");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/tools/threads/media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/tools/threads/media.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mentions.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/mentions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"mentions.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/mentions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAM3D,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA6BxF"}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatErrorResponse } from "../../utils/errors.js";
|
|
3
|
+
import { formatResponse } from "../../utils/response.js";
|
|
4
|
+
import { buildParams } from "../../utils/params.js";
|
|
5
|
+
import { READ_ONLY_TOOL } from "../annotations.js";
|
|
3
6
|
export function registerThreadsMentionsTools(server, client) {
|
|
4
7
|
// ─── threads_get_mentions ────────────────────────────────────
|
|
5
|
-
server.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
server.registerTool("threads_get_mentions", {
|
|
9
|
+
description: "List Threads posts where the authenticated user has been @mentioned. Requires the threads_manage_mentions permission. Posts from private profiles are excluded by the API. Without advanced access approval, only mentions from designated app testers are returned.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
limit: z.number().optional().describe("Number of results"),
|
|
12
|
+
since: z.string().optional().describe("Start Unix timestamp (must be >= 1688540400)"),
|
|
13
|
+
until: z.string().optional().describe("End Unix timestamp (must be <= now)"),
|
|
14
|
+
after: z.string().optional().describe("Pagination cursor"),
|
|
15
|
+
},
|
|
16
|
+
annotations: READ_ONLY_TOOL,
|
|
10
17
|
}, async ({ limit, since, until, after }) => {
|
|
11
18
|
try {
|
|
12
|
-
const params = {
|
|
19
|
+
const params = buildParams({
|
|
13
20
|
fields: "id,media_product_type,media_type,media_url,text,permalink,timestamp,username,shortcode,is_quote_post,topic_tag,has_replies,is_verified,profile_picture_url",
|
|
14
|
-
};
|
|
15
|
-
if (limit !== undefined)
|
|
16
|
-
params.limit = limit;
|
|
17
|
-
if (since)
|
|
18
|
-
params.since = since;
|
|
19
|
-
if (until)
|
|
20
|
-
params.until = until;
|
|
21
|
-
if (after)
|
|
22
|
-
params.after = after;
|
|
21
|
+
}, { limit, since, until, after });
|
|
23
22
|
const { data, rateLimit } = await client.threads("GET", `/${client.threadsUserId}/mentions`, params);
|
|
24
|
-
return
|
|
23
|
+
return formatResponse(data, rateLimit);
|
|
25
24
|
}
|
|
26
25
|
catch (error) {
|
|
27
26
|
return formatErrorResponse(error, "Get mentions");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mentions.js","sourceRoot":"","sources":["../../../src/tools/threads/mentions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"mentions.js","sourceRoot":"","sources":["../../../src/tools/threads/mentions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,UAAU,4BAA4B,CAAC,MAAiB,EAAE,MAAkB;IAChF,gEAAgE;IAChE,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,WAAW,EAAE,sQAAsQ;QACnR,WAAW,EAAE;YACX,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;YAC1D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;YACrF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;YAC5E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mBAAmB,CAAC;SAC3D;QACD,WAAW,EAAE,cAAc;KAC5B,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACvC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,WAAW,CACxB;gBACE,MAAM,EAAE,4JAA4J;aACrK,EACD,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAC/B,CAAC;YACF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,aAAa,WAAW,EAAE,MAAM,CAAC,CAAC;YACrG,OAAO,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,mBAAmB,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
2
|
import { MetaClient } from "../../services/meta-client.js";
|
|
3
|
+
export declare const THREADS_PROFILE_CACHE_PREFIX = "threads:profile:";
|
|
4
|
+
export declare const threadsProfileCacheKey: (userId: string) => string;
|
|
3
5
|
export declare function registerThreadsProfileTools(server: McpServer, client: MetaClient): void;
|
|
4
6
|
//# sourceMappingURL=profile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAwB,MAAM,+BAA+B,CAAC;AAMjF,eAAO,MAAM,4BAA4B,qBAAqB,CAAC;AAC/D,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,KAAG,MAAoD,CAAC;AAE7G,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAwBvF"}
|
|
@@ -1,12 +1,27 @@
|
|
|
1
|
+
import { PROFILE_CACHE_TTL_MS } from "../../services/meta-client.js";
|
|
2
|
+
import { THREADS_PROFILE_FIELDS } from "../../constants/fields.js";
|
|
1
3
|
import { formatErrorResponse } from "../../utils/errors.js";
|
|
4
|
+
import { formatResponse } from "../../utils/response.js";
|
|
5
|
+
import { READ_ONLY_TOOL } from "../annotations.js";
|
|
6
|
+
export const THREADS_PROFILE_CACHE_PREFIX = "threads:profile:";
|
|
7
|
+
export const threadsProfileCacheKey = (userId) => `${THREADS_PROFILE_CACHE_PREFIX}${userId}`;
|
|
2
8
|
export function registerThreadsProfileTools(server, client) {
|
|
3
9
|
// ─── threads_get_profile ─────────────────────────────────────
|
|
4
|
-
server.
|
|
10
|
+
server.registerTool("threads_get_profile", {
|
|
11
|
+
description: "Get Threads user profile information including verification status and geo-gating eligibility (is_eligible_for_geo_gating).",
|
|
12
|
+
inputSchema: {},
|
|
13
|
+
annotations: READ_ONLY_TOOL,
|
|
14
|
+
}, async () => {
|
|
5
15
|
try {
|
|
16
|
+
const cacheKey = threadsProfileCacheKey(client.threadsUserId);
|
|
17
|
+
const cached = client.getCached(cacheKey);
|
|
18
|
+
if (cached)
|
|
19
|
+
return formatResponse(cached);
|
|
6
20
|
const { data, rateLimit } = await client.threads("GET", `/${client.threadsUserId}`, {
|
|
7
|
-
fields:
|
|
21
|
+
fields: THREADS_PROFILE_FIELDS,
|
|
8
22
|
});
|
|
9
|
-
|
|
23
|
+
client.setCache(cacheKey, data, PROFILE_CACHE_TTL_MS);
|
|
24
|
+
return formatResponse(data, rateLimit);
|
|
10
25
|
}
|
|
11
26
|
catch (error) {
|
|
12
27
|
return formatErrorResponse(error, "Get profile");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/tools/threads/profile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"profile.js","sourceRoot":"","sources":["../../../src/tools/threads/profile.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,CAAC,MAAM,4BAA4B,GAAG,kBAAkB,CAAC;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,MAAc,EAAU,EAAE,CAAC,GAAG,4BAA4B,GAAG,MAAM,EAAE,CAAC;AAE7G,MAAM,UAAU,2BAA2B,CAAC,MAAiB,EAAE,MAAkB;IAC/E,gEAAgE;IAChE,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,WAAW,EAAE,6HAA6H;QAC1I,WAAW,EAAE,EAAE;QACf,WAAW,EAAE,cAAc;KAC5B,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,sBAAsB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,CAA0B,QAAQ,CAAC,CAAC;YACnE,IAAI,MAAM;gBAAE,OAAO,cAAc,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;gBAClF,MAAM,EAAE,sBAAsB;aAC/B,CAAC,CAAC;YACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,oBAAoB,CAAC,CAAC;YACtD,OAAO,cAAc,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QACnD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publishing.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/publishing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAc,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"publishing.d.ts","sourceRoot":"","sources":["../../../src/tools/threads/publishing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAc,MAAM,+BAA+B,CAAC;AAUvE,eAAO,MAAM,cAAc,4BAAsL,CAAC;AAElN,eAAO,MAAM,oBAAoB;;;GAA0R,CAAC;AAE5T,eAAO,MAAM,iBAAiB,wCAAoO,CAAC;AAEnQ,eAAO,MAAM,eAAe;;;;;;EAAwE,CAAC;AAErG,eAAO,MAAM,2BAA2B;;;;;;;;;;mBAIoD,CAAC;AAE7F,eAAO,MAAM,6BAA6B,wCAEuW,CAAC;AAElZ,eAAO,MAAM,kBAAkB;;;;;;GAM+c,CAAC;AAiB/e,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CA6c1F"}
|