social-mcp 2.1.0 → 2.3.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 +129 -3
- package/dist/index.js +64 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.js +34 -0
- package/dist/lib/config.js.map +1 -1
- package/dist/services/beehiiv-service.d.ts +69 -0
- package/dist/services/beehiiv-service.js +97 -0
- package/dist/services/beehiiv-service.js.map +1 -0
- package/dist/services/devto-service.d.ts +99 -0
- package/dist/services/devto-service.js +92 -0
- package/dist/services/devto-service.js.map +1 -0
- package/dist/services/email-service.d.ts +5 -1
- package/dist/services/email-service.js +76 -4
- package/dist/services/email-service.js.map +1 -1
- package/dist/services/ghost-service.d.ts +80 -0
- package/dist/services/ghost-service.js +123 -0
- package/dist/services/ghost-service.js.map +1 -0
- package/dist/services/hashnode-service.d.ts +86 -0
- package/dist/services/hashnode-service.js +161 -0
- package/dist/services/hashnode-service.js.map +1 -0
- package/dist/services/tumblr-service.d.ts +73 -0
- package/dist/services/tumblr-service.js +113 -0
- package/dist/services/tumblr-service.js.map +1 -0
- package/dist/services/twitch-service.d.ts +85 -0
- package/dist/services/twitch-service.js +135 -0
- package/dist/services/twitch-service.js.map +1 -0
- package/dist/tools/beehiiv-tools/create-post.d.ts +40 -0
- package/dist/tools/beehiiv-tools/create-post.js +49 -0
- package/dist/tools/beehiiv-tools/create-post.js.map +1 -0
- package/dist/tools/beehiiv-tools/get-posts.d.ts +20 -0
- package/dist/tools/beehiiv-tools/get-posts.js +51 -0
- package/dist/tools/beehiiv-tools/get-posts.js.map +1 -0
- package/dist/tools/beehiiv-tools/get-subscribers.d.ts +20 -0
- package/dist/tools/beehiiv-tools/get-subscribers.js +48 -0
- package/dist/tools/beehiiv-tools/get-subscribers.js.map +1 -0
- package/dist/tools/devto-tools/create-article.d.ts +30 -0
- package/dist/tools/devto-tools/create-article.js +47 -0
- package/dist/tools/devto-tools/create-article.js.map +1 -0
- package/dist/tools/devto-tools/get-article.d.ts +16 -0
- package/dist/tools/devto-tools/get-article.js +40 -0
- package/dist/tools/devto-tools/get-article.js.map +1 -0
- package/dist/tools/devto-tools/get-articles.d.ts +18 -0
- package/dist/tools/devto-tools/get-articles.js +41 -0
- package/dist/tools/devto-tools/get-articles.js.map +1 -0
- package/dist/tools/devto-tools/update-article.d.ts +28 -0
- package/dist/tools/devto-tools/update-article.js +51 -0
- package/dist/tools/devto-tools/update-article.js.map +1 -0
- package/dist/tools/email-tools/send-bulk-email.d.ts +8 -0
- package/dist/tools/email-tools/send-bulk-email.js +17 -1
- package/dist/tools/email-tools/send-bulk-email.js.map +1 -1
- package/dist/tools/email-tools/send-email.d.ts +8 -0
- package/dist/tools/email-tools/send-email.js +17 -1
- package/dist/tools/email-tools/send-email.js.map +1 -1
- package/dist/tools/ghost-tools/create-post.d.ts +36 -0
- package/dist/tools/ghost-tools/create-post.js +51 -0
- package/dist/tools/ghost-tools/create-post.js.map +1 -0
- package/dist/tools/ghost-tools/delete-post.d.ts +18 -0
- package/dist/tools/ghost-tools/delete-post.js +28 -0
- package/dist/tools/ghost-tools/delete-post.js.map +1 -0
- package/dist/tools/ghost-tools/get-posts.d.ts +30 -0
- package/dist/tools/ghost-tools/get-posts.js +51 -0
- package/dist/tools/ghost-tools/get-posts.js.map +1 -0
- package/dist/tools/ghost-tools/update-post.d.ts +36 -0
- package/dist/tools/ghost-tools/update-post.js +58 -0
- package/dist/tools/ghost-tools/update-post.js.map +1 -0
- package/dist/tools/hashnode-tools/create-post.d.ts +34 -0
- package/dist/tools/hashnode-tools/create-post.js +46 -0
- package/dist/tools/hashnode-tools/create-post.js.map +1 -0
- package/dist/tools/hashnode-tools/get-posts.d.ts +18 -0
- package/dist/tools/hashnode-tools/get-posts.js +48 -0
- package/dist/tools/hashnode-tools/get-posts.js.map +1 -0
- package/dist/tools/hashnode-tools/get-publication.d.ts +16 -0
- package/dist/tools/hashnode-tools/get-publication.js +36 -0
- package/dist/tools/hashnode-tools/get-publication.js.map +1 -0
- package/dist/tools/tumblr-tools/create-post.d.ts +34 -0
- package/dist/tools/tumblr-tools/create-post.js +45 -0
- package/dist/tools/tumblr-tools/create-post.js.map +1 -0
- package/dist/tools/tumblr-tools/delete-post.d.ts +18 -0
- package/dist/tools/tumblr-tools/delete-post.js +28 -0
- package/dist/tools/tumblr-tools/delete-post.js.map +1 -0
- package/dist/tools/tumblr-tools/get-blog-info.d.ts +16 -0
- package/dist/tools/tumblr-tools/get-blog-info.js +38 -0
- package/dist/tools/tumblr-tools/get-blog-info.js.map +1 -0
- package/dist/tools/tumblr-tools/get-posts.d.ts +40 -0
- package/dist/tools/tumblr-tools/get-posts.js +53 -0
- package/dist/tools/tumblr-tools/get-posts.js.map +1 -0
- package/dist/tools/twitch-tools/get-channel-info.d.ts +18 -0
- package/dist/tools/twitch-tools/get-channel-info.js +38 -0
- package/dist/tools/twitch-tools/get-channel-info.js.map +1 -0
- package/dist/tools/twitch-tools/get-streams.d.ts +22 -0
- package/dist/tools/twitch-tools/get-streams.js +50 -0
- package/dist/tools/twitch-tools/get-streams.js.map +1 -0
- package/dist/tools/twitch-tools/get-user.d.ts +18 -0
- package/dist/tools/twitch-tools/get-user.js +39 -0
- package/dist/tools/twitch-tools/get-user.js.map +1 -0
- package/dist/tools/twitch-tools/search-channels.d.ts +22 -0
- package/dist/tools/twitch-tools/search-channels.js +41 -0
- package/dist/tools/twitch-tools/search-channels.js.map +1 -0
- package/dist/tools/twitch-tools/send-chat-message.d.ts +24 -0
- package/dist/tools/twitch-tools/send-chat-message.js +39 -0
- package/dist/tools/twitch-tools/send-chat-message.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
declare const articleSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodNumber;
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
description: z.ZodOptional<z.ZodString>;
|
|
6
|
+
url: z.ZodOptional<z.ZodString>;
|
|
7
|
+
slug: z.ZodOptional<z.ZodString>;
|
|
8
|
+
published: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
published_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
10
|
+
tag_list: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
11
|
+
tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
12
|
+
reading_time_minutes: z.ZodOptional<z.ZodNumber>;
|
|
13
|
+
comments_count: z.ZodOptional<z.ZodNumber>;
|
|
14
|
+
positive_reactions_count: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
page_views_count: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
body_markdown: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export type DevToArticle = z.infer<typeof articleSchema>;
|
|
19
|
+
export interface DevToCredentials {
|
|
20
|
+
apiKey: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class DevToService {
|
|
23
|
+
private baseUrl;
|
|
24
|
+
private headers;
|
|
25
|
+
constructor(credentials?: DevToCredentials);
|
|
26
|
+
getMyArticles(page?: number, perPage?: number): Promise<{
|
|
27
|
+
id: number;
|
|
28
|
+
title: string;
|
|
29
|
+
description?: string | undefined;
|
|
30
|
+
url?: string | undefined;
|
|
31
|
+
slug?: string | undefined;
|
|
32
|
+
published?: boolean | undefined;
|
|
33
|
+
published_at?: string | null | undefined;
|
|
34
|
+
tag_list?: string | string[] | undefined;
|
|
35
|
+
tags?: string[] | undefined;
|
|
36
|
+
reading_time_minutes?: number | undefined;
|
|
37
|
+
comments_count?: number | undefined;
|
|
38
|
+
positive_reactions_count?: number | undefined;
|
|
39
|
+
page_views_count?: number | undefined;
|
|
40
|
+
body_markdown?: string | undefined;
|
|
41
|
+
}[]>;
|
|
42
|
+
getArticle(id: number): Promise<{
|
|
43
|
+
id: number;
|
|
44
|
+
title: string;
|
|
45
|
+
description?: string | undefined;
|
|
46
|
+
url?: string | undefined;
|
|
47
|
+
slug?: string | undefined;
|
|
48
|
+
published?: boolean | undefined;
|
|
49
|
+
published_at?: string | null | undefined;
|
|
50
|
+
tag_list?: string | string[] | undefined;
|
|
51
|
+
tags?: string[] | undefined;
|
|
52
|
+
reading_time_minutes?: number | undefined;
|
|
53
|
+
comments_count?: number | undefined;
|
|
54
|
+
positive_reactions_count?: number | undefined;
|
|
55
|
+
page_views_count?: number | undefined;
|
|
56
|
+
body_markdown?: string | undefined;
|
|
57
|
+
}>;
|
|
58
|
+
createArticle(title: string, bodyMarkdown: string, tags?: string[], published?: boolean, description?: string, canonicalUrl?: string, series?: string, mainImage?: string): Promise<{
|
|
59
|
+
id: number;
|
|
60
|
+
title: string;
|
|
61
|
+
description?: string | undefined;
|
|
62
|
+
url?: string | undefined;
|
|
63
|
+
slug?: string | undefined;
|
|
64
|
+
published?: boolean | undefined;
|
|
65
|
+
published_at?: string | null | undefined;
|
|
66
|
+
tag_list?: string | string[] | undefined;
|
|
67
|
+
tags?: string[] | undefined;
|
|
68
|
+
reading_time_minutes?: number | undefined;
|
|
69
|
+
comments_count?: number | undefined;
|
|
70
|
+
positive_reactions_count?: number | undefined;
|
|
71
|
+
page_views_count?: number | undefined;
|
|
72
|
+
body_markdown?: string | undefined;
|
|
73
|
+
}>;
|
|
74
|
+
updateArticle(id: number, updates: {
|
|
75
|
+
title?: string;
|
|
76
|
+
body_markdown?: string;
|
|
77
|
+
published?: boolean;
|
|
78
|
+
tags?: string[];
|
|
79
|
+
description?: string;
|
|
80
|
+
canonical_url?: string;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
id: number;
|
|
83
|
+
title: string;
|
|
84
|
+
description?: string | undefined;
|
|
85
|
+
url?: string | undefined;
|
|
86
|
+
slug?: string | undefined;
|
|
87
|
+
published?: boolean | undefined;
|
|
88
|
+
published_at?: string | null | undefined;
|
|
89
|
+
tag_list?: string | string[] | undefined;
|
|
90
|
+
tags?: string[] | undefined;
|
|
91
|
+
reading_time_minutes?: number | undefined;
|
|
92
|
+
comments_count?: number | undefined;
|
|
93
|
+
positive_reactions_count?: number | undefined;
|
|
94
|
+
page_views_count?: number | undefined;
|
|
95
|
+
body_markdown?: string | undefined;
|
|
96
|
+
}>;
|
|
97
|
+
}
|
|
98
|
+
export declare function getDevToService(): DevToService;
|
|
99
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { config } from "../lib/config.js";
|
|
3
|
+
import { CredentialsError } from "../lib/errors.js";
|
|
4
|
+
import { fetchJson } from "../lib/http.js";
|
|
5
|
+
const articleSchema = z.object({
|
|
6
|
+
id: z.number(),
|
|
7
|
+
title: z.string(),
|
|
8
|
+
description: z.string().optional(),
|
|
9
|
+
url: z.string().optional(),
|
|
10
|
+
slug: z.string().optional(),
|
|
11
|
+
published: z.boolean().optional(),
|
|
12
|
+
published_at: z.string().nullable().optional(),
|
|
13
|
+
tag_list: z.union([z.string(), z.array(z.string())]).optional(),
|
|
14
|
+
tags: z.array(z.string()).optional(),
|
|
15
|
+
reading_time_minutes: z.number().optional(),
|
|
16
|
+
comments_count: z.number().optional(),
|
|
17
|
+
positive_reactions_count: z.number().optional(),
|
|
18
|
+
page_views_count: z.number().optional(),
|
|
19
|
+
body_markdown: z.string().optional(),
|
|
20
|
+
});
|
|
21
|
+
const articleResponseSchema = z.object({
|
|
22
|
+
id: z.number(),
|
|
23
|
+
title: z.string(),
|
|
24
|
+
description: z.string().optional(),
|
|
25
|
+
url: z.string().optional(),
|
|
26
|
+
slug: z.string().optional(),
|
|
27
|
+
published: z.boolean().optional(),
|
|
28
|
+
published_at: z.string().nullable().optional(),
|
|
29
|
+
tag_list: z.union([z.string(), z.array(z.string())]).optional(),
|
|
30
|
+
tags: z.array(z.string()).optional(),
|
|
31
|
+
reading_time_minutes: z.number().optional(),
|
|
32
|
+
comments_count: z.number().optional(),
|
|
33
|
+
positive_reactions_count: z.number().optional(),
|
|
34
|
+
page_views_count: z.number().optional(),
|
|
35
|
+
body_markdown: z.string().optional(),
|
|
36
|
+
});
|
|
37
|
+
export class DevToService {
|
|
38
|
+
baseUrl = config.devto.baseUrl;
|
|
39
|
+
headers;
|
|
40
|
+
constructor(credentials) {
|
|
41
|
+
const apiKey = credentials?.apiKey ?? config.devto.apiKey;
|
|
42
|
+
if (!apiKey) {
|
|
43
|
+
throw new CredentialsError("Dev.to", ["DEVTO_API_KEY"]);
|
|
44
|
+
}
|
|
45
|
+
this.headers = {
|
|
46
|
+
"api-key": apiKey,
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
Accept: "application/vnd.forem.api-v1+json",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async getMyArticles(page = 1, perPage = 30) {
|
|
52
|
+
return fetchJson(`${this.baseUrl}/articles/me?page=${page}&per_page=${perPage}`, { method: "GET", headers: this.headers }, z.array(articleSchema));
|
|
53
|
+
}
|
|
54
|
+
async getArticle(id) {
|
|
55
|
+
return fetchJson(`${this.baseUrl}/articles/${id}`, { method: "GET", headers: this.headers }, articleResponseSchema);
|
|
56
|
+
}
|
|
57
|
+
async createArticle(title, bodyMarkdown, tags = [], published = false, description, canonicalUrl, series, mainImage) {
|
|
58
|
+
const article = {
|
|
59
|
+
title,
|
|
60
|
+
body_markdown: bodyMarkdown,
|
|
61
|
+
published,
|
|
62
|
+
tags,
|
|
63
|
+
};
|
|
64
|
+
if (description)
|
|
65
|
+
article.description = description;
|
|
66
|
+
if (canonicalUrl)
|
|
67
|
+
article.canonical_url = canonicalUrl;
|
|
68
|
+
if (series)
|
|
69
|
+
article.series = series;
|
|
70
|
+
if (mainImage)
|
|
71
|
+
article.main_image = mainImage;
|
|
72
|
+
return fetchJson(`${this.baseUrl}/articles`, {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: this.headers,
|
|
75
|
+
body: JSON.stringify({ article }),
|
|
76
|
+
}, articleResponseSchema);
|
|
77
|
+
}
|
|
78
|
+
async updateArticle(id, updates) {
|
|
79
|
+
return fetchJson(`${this.baseUrl}/articles/${id}`, {
|
|
80
|
+
method: "PUT",
|
|
81
|
+
headers: this.headers,
|
|
82
|
+
body: JSON.stringify({ article: updates }),
|
|
83
|
+
}, articleResponseSchema);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
let _instance;
|
|
87
|
+
export function getDevToService() {
|
|
88
|
+
if (!_instance)
|
|
89
|
+
_instance = new DevToService();
|
|
90
|
+
return _instance;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=devto-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devto-service.js","sourceRoot":"","sources":["../../src/services/devto-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface EmailCredentials {
|
|
2
|
-
mailer: "smtp" | "sendgrid" | "mailgun";
|
|
2
|
+
mailer: "smtp" | "sendgrid" | "mailgun" | "ses";
|
|
3
3
|
fromAddress: string;
|
|
4
4
|
fromName?: string;
|
|
5
5
|
smtpHost?: string;
|
|
@@ -10,6 +10,9 @@ export interface EmailCredentials {
|
|
|
10
10
|
sendgridApiKey?: string;
|
|
11
11
|
mailgunApiKey?: string;
|
|
12
12
|
mailgunDomain?: string;
|
|
13
|
+
sesAccessKeyId?: string;
|
|
14
|
+
sesSecretAccessKey?: string;
|
|
15
|
+
sesRegion?: string;
|
|
13
16
|
}
|
|
14
17
|
export declare class EmailService {
|
|
15
18
|
private creds;
|
|
@@ -22,5 +25,6 @@ export declare class EmailService {
|
|
|
22
25
|
private sendViaSMTP;
|
|
23
26
|
private sendViaSendGrid;
|
|
24
27
|
private sendViaMailgun;
|
|
28
|
+
private sendViaSES;
|
|
25
29
|
}
|
|
26
30
|
export declare function getEmailService(): EmailService;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import nodemailer from "nodemailer";
|
|
2
|
+
import { createHash, createHmac } from "crypto";
|
|
2
3
|
import { config } from "../lib/config.js";
|
|
3
4
|
import { CredentialsError } from "../lib/errors.js";
|
|
4
5
|
function credentialsFromConfig() {
|
|
5
|
-
const { mailer, fromAddress, fromName, smtp, sendgrid, mailgun } = config.email;
|
|
6
|
+
const { mailer, fromAddress, fromName, smtp, sendgrid, mailgun, ses } = config.email;
|
|
6
7
|
return {
|
|
7
8
|
mailer: mailer,
|
|
8
9
|
fromAddress,
|
|
@@ -15,8 +16,24 @@ function credentialsFromConfig() {
|
|
|
15
16
|
sendgridApiKey: sendgrid.apiKey || undefined,
|
|
16
17
|
mailgunApiKey: mailgun.apiKey || undefined,
|
|
17
18
|
mailgunDomain: mailgun.domain || undefined,
|
|
19
|
+
sesAccessKeyId: ses.accessKeyId || undefined,
|
|
20
|
+
sesSecretAccessKey: ses.secretAccessKey || undefined,
|
|
21
|
+
sesRegion: ses.region || undefined,
|
|
18
22
|
};
|
|
19
23
|
}
|
|
24
|
+
// ── AWS Sig V4 helpers ────────────────────────────────────────────────────────
|
|
25
|
+
function sha256Hex(data) {
|
|
26
|
+
return createHash("sha256").update(data, "utf8").digest("hex");
|
|
27
|
+
}
|
|
28
|
+
function hmacSha256(key, data) {
|
|
29
|
+
return createHmac("sha256", key).update(data, "utf8").digest();
|
|
30
|
+
}
|
|
31
|
+
function sesSigningKey(secretKey, dateStamp, region) {
|
|
32
|
+
const kDate = hmacSha256(`AWS4${secretKey}`, dateStamp);
|
|
33
|
+
const kRegion = hmacSha256(kDate, region);
|
|
34
|
+
const kService = hmacSha256(kRegion, "ses");
|
|
35
|
+
return hmacSha256(kService, "aws4_request");
|
|
36
|
+
}
|
|
20
37
|
export class EmailService {
|
|
21
38
|
creds;
|
|
22
39
|
constructor(credentials) {
|
|
@@ -24,7 +41,7 @@ export class EmailService {
|
|
|
24
41
|
this.validateCredentials();
|
|
25
42
|
}
|
|
26
43
|
validateCredentials() {
|
|
27
|
-
const { mailer, fromAddress, smtpHost, smtpUsername, smtpPassword, sendgridApiKey, mailgunApiKey, mailgunDomain, } = this.creds;
|
|
44
|
+
const { mailer, fromAddress, smtpHost, smtpUsername, smtpPassword, sendgridApiKey, mailgunApiKey, mailgunDomain, sesAccessKeyId, sesSecretAccessKey, } = this.creds;
|
|
28
45
|
if (!fromAddress) {
|
|
29
46
|
throw new CredentialsError("Email", ["MAIL_FROM_ADDRESS"]);
|
|
30
47
|
}
|
|
@@ -50,8 +67,16 @@ export class EmailService {
|
|
|
50
67
|
]);
|
|
51
68
|
}
|
|
52
69
|
}
|
|
70
|
+
else if (mailer === "ses") {
|
|
71
|
+
if (!sesAccessKeyId || !sesSecretAccessKey) {
|
|
72
|
+
throw new CredentialsError("Email (Amazon SES)", [
|
|
73
|
+
"SES_ACCESS_KEY_ID",
|
|
74
|
+
"SES_SECRET_ACCESS_KEY",
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
53
78
|
else {
|
|
54
|
-
throw new Error(`Unsupported mailer: "${mailer}". Supported: smtp, sendgrid, mailgun`);
|
|
79
|
+
throw new Error(`Unsupported mailer: "${mailer}". Supported: smtp, sendgrid, mailgun, ses`);
|
|
55
80
|
}
|
|
56
81
|
}
|
|
57
82
|
fromHeader() {
|
|
@@ -68,7 +93,7 @@ export class EmailService {
|
|
|
68
93
|
auth: { user: smtpUsername, pass: smtpPassword },
|
|
69
94
|
});
|
|
70
95
|
}
|
|
71
|
-
// Verifies the SMTP connection. No-op for SendGrid/Mailgun (no free verify endpoint).
|
|
96
|
+
// Verifies the SMTP connection. No-op for SendGrid/Mailgun/SES (no free verify endpoint).
|
|
72
97
|
async verify() {
|
|
73
98
|
if (this.creds.mailer === "smtp") {
|
|
74
99
|
const transporter = this.createSMTPTransporter();
|
|
@@ -83,6 +108,8 @@ export class EmailService {
|
|
|
83
108
|
return this.sendViaSendGrid(to, subject, text, html);
|
|
84
109
|
case "mailgun":
|
|
85
110
|
return this.sendViaMailgun(to, subject, text, html);
|
|
111
|
+
case "ses":
|
|
112
|
+
return this.sendViaSES(to, subject, text, html);
|
|
86
113
|
}
|
|
87
114
|
}
|
|
88
115
|
async sendViaSMTP(to, subject, text, html) {
|
|
@@ -145,6 +172,51 @@ export class EmailService {
|
|
|
145
172
|
throw new Error(`Mailgun error (${response.status}): ${error}`);
|
|
146
173
|
}
|
|
147
174
|
}
|
|
175
|
+
async sendViaSES(to, subject, text, html) {
|
|
176
|
+
const { sesAccessKeyId, sesSecretAccessKey = "", sesRegion = "us-east-1", fromAddress, fromName } = this.creds;
|
|
177
|
+
const region = sesRegion;
|
|
178
|
+
const host = `email.${region}.amazonaws.com`;
|
|
179
|
+
const path = "/v2/email/outbound-emails";
|
|
180
|
+
const toAddresses = Array.isArray(to) ? to : [to];
|
|
181
|
+
const body = JSON.stringify({
|
|
182
|
+
FromEmailAddress: fromName ? `"${fromName}" <${fromAddress}>` : fromAddress,
|
|
183
|
+
Destination: { ToAddresses: toAddresses },
|
|
184
|
+
Content: {
|
|
185
|
+
Simple: {
|
|
186
|
+
Subject: { Data: subject, Charset: "UTF-8" },
|
|
187
|
+
Body: {
|
|
188
|
+
Text: { Data: text, Charset: "UTF-8" },
|
|
189
|
+
...(html ? { Html: { Data: html, Charset: "UTF-8" } } : {}),
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
const now = new Date();
|
|
195
|
+
const amzDate = now.toISOString().replace(/[:-]/g, "").replace(/\.\d{3}/, "");
|
|
196
|
+
const dateStamp = amzDate.slice(0, 8);
|
|
197
|
+
const bodyHash = sha256Hex(body);
|
|
198
|
+
const canonicalHeaders = `content-type:application/json\nhost:${host}\nx-amz-date:${amzDate}\n`;
|
|
199
|
+
const signedHeaders = "content-type;host;x-amz-date";
|
|
200
|
+
const canonicalRequest = ["POST", path, "", canonicalHeaders, signedHeaders, bodyHash].join("\n");
|
|
201
|
+
const credentialScope = `${dateStamp}/${region}/ses/aws4_request`;
|
|
202
|
+
const stringToSign = ["AWS4-HMAC-SHA256", amzDate, credentialScope, sha256Hex(canonicalRequest)].join("\n");
|
|
203
|
+
const signingKey = sesSigningKey(sesSecretAccessKey, dateStamp, region);
|
|
204
|
+
const signature = createHmac("sha256", signingKey).update(stringToSign, "utf8").digest("hex");
|
|
205
|
+
const authorization = `AWS4-HMAC-SHA256 Credential=${sesAccessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
206
|
+
const response = await fetch(`https://${host}${path}`, {
|
|
207
|
+
method: "POST",
|
|
208
|
+
headers: {
|
|
209
|
+
"Content-Type": "application/json",
|
|
210
|
+
"X-Amz-Date": amzDate,
|
|
211
|
+
Authorization: authorization,
|
|
212
|
+
},
|
|
213
|
+
body,
|
|
214
|
+
});
|
|
215
|
+
if (!response.ok) {
|
|
216
|
+
const error = await response.text();
|
|
217
|
+
throw new Error(`SES error (${response.status}): ${error}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
148
220
|
}
|
|
149
221
|
// Singleton for the env-var-based default configuration.
|
|
150
222
|
// When calling tools with per-org credentials, pass an EmailCredentials
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-service.js","sourceRoot":"","sources":["../../src/services/email-service.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"email-service.js","sourceRoot":"","sources":["../../src/services/email-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export interface GhostCredentials {
|
|
2
|
+
siteUrl: string;
|
|
3
|
+
adminApiKey: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class GhostService {
|
|
6
|
+
private siteUrl;
|
|
7
|
+
private keyId;
|
|
8
|
+
private keySecret;
|
|
9
|
+
constructor(credentials?: GhostCredentials);
|
|
10
|
+
private generateJwt;
|
|
11
|
+
private get headers();
|
|
12
|
+
private get adminBase();
|
|
13
|
+
getPosts(page?: number, limit?: number, status?: "all" | "published" | "draft"): Promise<{
|
|
14
|
+
posts: {
|
|
15
|
+
id: string;
|
|
16
|
+
title?: string | undefined;
|
|
17
|
+
slug?: string | undefined;
|
|
18
|
+
status?: string | undefined;
|
|
19
|
+
url?: string | undefined;
|
|
20
|
+
published_at?: string | null | undefined;
|
|
21
|
+
updated_at?: string | null | undefined;
|
|
22
|
+
excerpt?: string | null | undefined;
|
|
23
|
+
tags?: {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
}[] | undefined;
|
|
28
|
+
}[];
|
|
29
|
+
meta?: {
|
|
30
|
+
pagination?: {
|
|
31
|
+
page: number;
|
|
32
|
+
limit: number;
|
|
33
|
+
pages: number;
|
|
34
|
+
total: number;
|
|
35
|
+
} | undefined;
|
|
36
|
+
} | undefined;
|
|
37
|
+
}>;
|
|
38
|
+
createPost(title: string, html?: string, lexical?: string, status?: "draft" | "published" | "scheduled", tags?: string[], excerpt?: string, publishedAt?: string): Promise<{
|
|
39
|
+
posts: {
|
|
40
|
+
id: string;
|
|
41
|
+
title?: string | undefined;
|
|
42
|
+
slug?: string | undefined;
|
|
43
|
+
status?: string | undefined;
|
|
44
|
+
url?: string | undefined;
|
|
45
|
+
published_at?: string | null | undefined;
|
|
46
|
+
updated_at?: string | null | undefined;
|
|
47
|
+
excerpt?: string | null | undefined;
|
|
48
|
+
tags?: {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
slug: string;
|
|
52
|
+
}[] | undefined;
|
|
53
|
+
}[];
|
|
54
|
+
}>;
|
|
55
|
+
updatePost(id: string, updatedAt: string, updates: {
|
|
56
|
+
title?: string;
|
|
57
|
+
html?: string;
|
|
58
|
+
status?: "draft" | "published";
|
|
59
|
+
tags?: string[];
|
|
60
|
+
custom_excerpt?: string;
|
|
61
|
+
}): Promise<{
|
|
62
|
+
posts: {
|
|
63
|
+
id: string;
|
|
64
|
+
title?: string | undefined;
|
|
65
|
+
slug?: string | undefined;
|
|
66
|
+
status?: string | undefined;
|
|
67
|
+
url?: string | undefined;
|
|
68
|
+
published_at?: string | null | undefined;
|
|
69
|
+
updated_at?: string | null | undefined;
|
|
70
|
+
excerpt?: string | null | undefined;
|
|
71
|
+
tags?: {
|
|
72
|
+
id: string;
|
|
73
|
+
name: string;
|
|
74
|
+
slug: string;
|
|
75
|
+
}[] | undefined;
|
|
76
|
+
}[];
|
|
77
|
+
}>;
|
|
78
|
+
deletePost(id: string): Promise<void>;
|
|
79
|
+
}
|
|
80
|
+
export declare function getGhostService(): GhostService;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { createHmac } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { config } from "../lib/config.js";
|
|
4
|
+
import { CredentialsError } from "../lib/errors.js";
|
|
5
|
+
import { fetchJson } from "../lib/http.js";
|
|
6
|
+
const postSchema = z.object({
|
|
7
|
+
id: z.string(),
|
|
8
|
+
title: z.string().optional(),
|
|
9
|
+
slug: z.string().optional(),
|
|
10
|
+
status: z.string().optional(),
|
|
11
|
+
url: z.string().optional(),
|
|
12
|
+
published_at: z.string().nullable().optional(),
|
|
13
|
+
updated_at: z.string().nullable().optional(),
|
|
14
|
+
excerpt: z.string().nullable().optional(),
|
|
15
|
+
tags: z.array(z.object({ id: z.string(), name: z.string(), slug: z.string() })).optional(),
|
|
16
|
+
});
|
|
17
|
+
const postsResponseSchema = z.object({
|
|
18
|
+
posts: z.array(postSchema),
|
|
19
|
+
meta: z.object({
|
|
20
|
+
pagination: z.object({
|
|
21
|
+
page: z.number(),
|
|
22
|
+
limit: z.number(),
|
|
23
|
+
pages: z.number(),
|
|
24
|
+
total: z.number(),
|
|
25
|
+
}).optional(),
|
|
26
|
+
}).optional(),
|
|
27
|
+
});
|
|
28
|
+
const singlePostResponseSchema = z.object({
|
|
29
|
+
posts: z.array(postSchema),
|
|
30
|
+
});
|
|
31
|
+
export class GhostService {
|
|
32
|
+
siteUrl;
|
|
33
|
+
keyId;
|
|
34
|
+
keySecret;
|
|
35
|
+
constructor(credentials) {
|
|
36
|
+
const siteUrl = credentials?.siteUrl ?? config.ghost.siteUrl;
|
|
37
|
+
const adminApiKey = credentials?.adminApiKey ?? config.ghost.adminApiKey;
|
|
38
|
+
if (!siteUrl || !adminApiKey) {
|
|
39
|
+
throw new CredentialsError("Ghost", ["GHOST_SITE_URL", "GHOST_ADMIN_API_KEY"]);
|
|
40
|
+
}
|
|
41
|
+
const parts = adminApiKey.split(":");
|
|
42
|
+
if (parts.length !== 2) {
|
|
43
|
+
throw new Error("GHOST_ADMIN_API_KEY must be in the format 'id:secret'");
|
|
44
|
+
}
|
|
45
|
+
this.siteUrl = siteUrl.replace(/\/$/, "");
|
|
46
|
+
this.keyId = parts[0];
|
|
47
|
+
this.keySecret = parts[1];
|
|
48
|
+
}
|
|
49
|
+
generateJwt() {
|
|
50
|
+
const now = Math.floor(Date.now() / 1000);
|
|
51
|
+
const header = Buffer.from(JSON.stringify({ alg: "HS256", typ: "JWT", kid: this.keyId })).toString("base64url");
|
|
52
|
+
const payload = Buffer.from(JSON.stringify({ iat: now, exp: now + 300, aud: "/admin/" })).toString("base64url");
|
|
53
|
+
const signing = `${header}.${payload}`;
|
|
54
|
+
const signature = createHmac("sha256", Buffer.from(this.keySecret, "hex"))
|
|
55
|
+
.update(signing)
|
|
56
|
+
.digest("base64url");
|
|
57
|
+
return `${signing}.${signature}`;
|
|
58
|
+
}
|
|
59
|
+
get headers() {
|
|
60
|
+
return {
|
|
61
|
+
Authorization: `Ghost ${this.generateJwt()}`,
|
|
62
|
+
"Content-Type": "application/json",
|
|
63
|
+
"Accept-Version": "v5.0",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
get adminBase() {
|
|
67
|
+
return `${this.siteUrl}/ghost/api/admin`;
|
|
68
|
+
}
|
|
69
|
+
async getPosts(page = 1, limit = 10, status = "all") {
|
|
70
|
+
const params = new URLSearchParams({ page: String(page), limit: String(limit), filter: `status:${status}` });
|
|
71
|
+
if (status === "all")
|
|
72
|
+
params.delete("filter");
|
|
73
|
+
else
|
|
74
|
+
params.set("filter", `status:${status}`);
|
|
75
|
+
return fetchJson(`${this.adminBase}/posts?${params}`, { method: "GET", headers: this.headers }, postsResponseSchema);
|
|
76
|
+
}
|
|
77
|
+
async createPost(title, html, lexical, status = "draft", tags = [], excerpt, publishedAt) {
|
|
78
|
+
const post = {
|
|
79
|
+
title,
|
|
80
|
+
status,
|
|
81
|
+
tags: tags.map((name) => ({ name })),
|
|
82
|
+
};
|
|
83
|
+
if (html)
|
|
84
|
+
post.html = html;
|
|
85
|
+
if (lexical)
|
|
86
|
+
post.lexical = lexical;
|
|
87
|
+
if (excerpt)
|
|
88
|
+
post.custom_excerpt = excerpt;
|
|
89
|
+
if (publishedAt)
|
|
90
|
+
post.published_at = publishedAt;
|
|
91
|
+
return fetchJson(`${this.adminBase}/posts`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
headers: this.headers,
|
|
94
|
+
body: JSON.stringify({ posts: [post] }),
|
|
95
|
+
}, singlePostResponseSchema);
|
|
96
|
+
}
|
|
97
|
+
async updatePost(id, updatedAt, updates) {
|
|
98
|
+
const body = { ...updates, updated_at: updatedAt };
|
|
99
|
+
if (updates.tags)
|
|
100
|
+
body.tags = updates.tags.map((name) => ({ name }));
|
|
101
|
+
return fetchJson(`${this.adminBase}/posts/${id}`, {
|
|
102
|
+
method: "PUT",
|
|
103
|
+
headers: this.headers,
|
|
104
|
+
body: JSON.stringify({ posts: [body] }),
|
|
105
|
+
}, singlePostResponseSchema);
|
|
106
|
+
}
|
|
107
|
+
async deletePost(id) {
|
|
108
|
+
const response = await fetch(`${this.adminBase}/posts/${id}`, {
|
|
109
|
+
method: "DELETE",
|
|
110
|
+
headers: this.headers,
|
|
111
|
+
});
|
|
112
|
+
if (!response.ok) {
|
|
113
|
+
throw new Error(`Ghost API error ${response.status}: ${response.statusText}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
let _instance;
|
|
118
|
+
export function getGhostService() {
|
|
119
|
+
if (!_instance)
|
|
120
|
+
_instance = new GhostService();
|
|
121
|
+
return _instance;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=ghost-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ghost-service.js","sourceRoot":"","sources":["../../src/services/ghost-service.ts"],"names":[],"mappings":"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"}
|