postproxy-mcp 0.1.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/LICENSE +21 -0
- package/README.md +635 -0
- package/dist/api/client.d.ts +71 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +432 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth/credentials.d.ts +19 -0
- package/dist/auth/credentials.d.ts.map +1 -0
- package/dist/auth/credentials.js +40 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +162 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +220 -0
- package/dist/server.js.map +1 -0
- package/dist/setup-cli.d.ts +6 -0
- package/dist/setup-cli.d.ts.map +1 -0
- package/dist/setup-cli.js +10 -0
- package/dist/setup-cli.js.map +1 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +143 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/accounts.d.ts +11 -0
- package/dist/tools/accounts.d.ts.map +1 -0
- package/dist/tools/accounts.js +53 -0
- package/dist/tools/accounts.js.map +1 -0
- package/dist/tools/auth.d.ts +11 -0
- package/dist/tools/auth.d.ts.map +1 -0
- package/dist/tools/auth.js +35 -0
- package/dist/tools/auth.js.map +1 -0
- package/dist/tools/history.d.ts +13 -0
- package/dist/tools/history.d.ts.map +1 -0
- package/dist/tools/history.js +79 -0
- package/dist/tools/history.js.map +1 -0
- package/dist/tools/post.d.ts +44 -0
- package/dist/tools/post.d.ts.map +1 -0
- package/dist/tools/post.js +251 -0
- package/dist/tools/post.js.map +1 -0
- package/dist/tools/profiles.d.ts +11 -0
- package/dist/tools/profiles.d.ts.map +1 -0
- package/dist/tools/profiles.js +52 -0
- package/dist/tools/profiles.js.map +1 -0
- package/dist/types/index.d.ts +147 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/errors.d.ts +21 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +33 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/idempotency.d.ts +8 -0
- package/dist/utils/idempotency.d.ts.map +1 -0
- package/dist/utils/idempotency.js +23 -0
- package/dist/utils/idempotency.js.map +1 -0
- package/dist/utils/logger.d.ts +20 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +68 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +555 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +145 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +39 -0
- package/src/api/client.ts +497 -0
- package/src/auth/credentials.ts +43 -0
- package/src/index.ts +57 -0
- package/src/server.ts +235 -0
- package/src/setup-cli.ts +11 -0
- package/src/setup.ts +187 -0
- package/src/tools/auth.ts +45 -0
- package/src/tools/history.ts +89 -0
- package/src/tools/post.ts +338 -0
- package/src/tools/profiles.ts +69 -0
- package/src/types/index.ts +161 -0
- package/src/utils/errors.ts +38 -0
- package/src/utils/idempotency.ts +31 -0
- package/src/utils/logger.ts +75 -0
- package/src/utils/validation.ts +171 -0
- package/tsconfig.json +19 -0
- package/worker/index.ts +901 -0
- package/wrangler.toml +11 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure logging utilities that sanitize sensitive data
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const DEBUG = process.env.POSTPROXY_MCP_DEBUG === "1";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Sanitize data for logging by removing sensitive fields
|
|
9
|
+
*/
|
|
10
|
+
export function sanitizeForLog(data: any): any {
|
|
11
|
+
if (data === null || data === undefined) {
|
|
12
|
+
return data;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof data !== "object") {
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (Array.isArray(data)) {
|
|
20
|
+
return data.map(sanitizeForLog);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const sanitized: any = {};
|
|
24
|
+
const sensitiveKeys = [
|
|
25
|
+
"apiKey",
|
|
26
|
+
"api_key",
|
|
27
|
+
"api-key",
|
|
28
|
+
"authorization",
|
|
29
|
+
"token",
|
|
30
|
+
"password",
|
|
31
|
+
"secret",
|
|
32
|
+
"POSTPROXY_API_KEY",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
for (const [key, value] of Object.entries(data)) {
|
|
36
|
+
const lowerKey = key.toLowerCase();
|
|
37
|
+
if (sensitiveKeys.some((sk) => lowerKey.includes(sk.toLowerCase()))) {
|
|
38
|
+
sanitized[key] = "[REDACTED]";
|
|
39
|
+
} else if (typeof value === "object") {
|
|
40
|
+
sanitized[key] = sanitizeForLog(value);
|
|
41
|
+
} else {
|
|
42
|
+
sanitized[key] = value;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return sanitized;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Log a message to stderr
|
|
51
|
+
*/
|
|
52
|
+
export function log(message: string, ...args: any[]): void {
|
|
53
|
+
const sanitizedArgs = args.map(sanitizeForLog);
|
|
54
|
+
console.error(`[postproxy-mcp] ${message}`, ...sanitizedArgs);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Log a tool call (without sensitive data)
|
|
59
|
+
*/
|
|
60
|
+
export function logToolCall(toolName: string, params: any): void {
|
|
61
|
+
if (DEBUG) {
|
|
62
|
+
log(`Tool call: ${toolName}`, sanitizeForLog(params));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Log an error
|
|
68
|
+
*/
|
|
69
|
+
export function logError(error: Error, context?: string): void {
|
|
70
|
+
const contextMsg = context ? `[${context}] ` : "";
|
|
71
|
+
log(`Error ${contextMsg}${error.message}`, error);
|
|
72
|
+
if (DEBUG && error.stack) {
|
|
73
|
+
log("Stack trace:", error.stack);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation schemas using Zod
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Schema for ISO 8601 date strings
|
|
9
|
+
*/
|
|
10
|
+
export const ISO8601DateSchema = z.string().refine(
|
|
11
|
+
(date) => {
|
|
12
|
+
const d = new Date(date);
|
|
13
|
+
return !isNaN(d.getTime()) && date.includes("T");
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
message: "Must be a valid ISO 8601 date string (e.g., 2024-01-01T12:00:00Z)",
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Schema for URL strings
|
|
22
|
+
*/
|
|
23
|
+
export const URLSchema = z.string().url({
|
|
24
|
+
message: "Must be a valid URL",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Check if a string looks like a file path
|
|
29
|
+
*/
|
|
30
|
+
export function isFilePath(value: string): boolean {
|
|
31
|
+
// Absolute paths, relative paths, or home directory paths
|
|
32
|
+
return (
|
|
33
|
+
value.startsWith("/") ||
|
|
34
|
+
value.startsWith("./") ||
|
|
35
|
+
value.startsWith("../") ||
|
|
36
|
+
value.startsWith("~/") ||
|
|
37
|
+
// Windows absolute paths
|
|
38
|
+
/^[A-Za-z]:[\\/]/.test(value)
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Schema for media items (URLs or file paths)
|
|
44
|
+
*/
|
|
45
|
+
export const MediaItemSchema = z.string().refine(
|
|
46
|
+
(value) => {
|
|
47
|
+
// Allow file paths
|
|
48
|
+
if (isFilePath(value)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
// Or valid URLs
|
|
52
|
+
try {
|
|
53
|
+
new URL(value);
|
|
54
|
+
return true;
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
message: "Must be a valid URL or file path",
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Platform-specific validation schemas
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
// Instagram parameters validation
|
|
69
|
+
export const InstagramParamsSchema = z.object({
|
|
70
|
+
format: z.enum(["post", "reel", "story"], {
|
|
71
|
+
errorMap: () => ({ message: "Instagram format must be 'post', 'reel', or 'story'" }),
|
|
72
|
+
}).optional(),
|
|
73
|
+
collaborators: z.array(z.string()).max(10, {
|
|
74
|
+
message: "Instagram allows up to 10 collaborators for posts, 3 for reels",
|
|
75
|
+
}).optional(),
|
|
76
|
+
first_comment: z.string().optional(),
|
|
77
|
+
cover_url: URLSchema.optional(),
|
|
78
|
+
audio_name: z.string().optional(),
|
|
79
|
+
trial_strategy: z.enum(["MANUAL", "SS_PERFORMANCE"], {
|
|
80
|
+
errorMap: () => ({ message: "Instagram trial_strategy must be 'MANUAL' or 'SS_PERFORMANCE'" }),
|
|
81
|
+
}).optional(),
|
|
82
|
+
thumb_offset: z.string().optional(),
|
|
83
|
+
}).strict();
|
|
84
|
+
|
|
85
|
+
// YouTube parameters validation
|
|
86
|
+
export const YouTubeParamsSchema = z.object({
|
|
87
|
+
title: z.string().optional(),
|
|
88
|
+
privacy_status: z.enum(["public", "unlisted", "private"], {
|
|
89
|
+
errorMap: () => ({ message: "YouTube privacy_status must be 'public', 'unlisted', or 'private'" }),
|
|
90
|
+
}).optional(),
|
|
91
|
+
cover_url: URLSchema.optional(),
|
|
92
|
+
}).strict();
|
|
93
|
+
|
|
94
|
+
// TikTok parameters validation
|
|
95
|
+
export const TikTokParamsSchema = z.object({
|
|
96
|
+
privacy_status: z.enum([
|
|
97
|
+
"PUBLIC_TO_EVERYONE",
|
|
98
|
+
"MUTUAL_FOLLOW_FRIENDS",
|
|
99
|
+
"FOLLOWER_OF_CREATOR",
|
|
100
|
+
"SELF_ONLY"
|
|
101
|
+
], {
|
|
102
|
+
errorMap: () => ({ message: "TikTok privacy_status must be one of: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY" }),
|
|
103
|
+
}).optional(),
|
|
104
|
+
photo_cover_index: z.number().int().nonnegative({
|
|
105
|
+
message: "TikTok photo_cover_index must be a non-negative integer",
|
|
106
|
+
}).optional(),
|
|
107
|
+
auto_add_music: z.boolean().optional(),
|
|
108
|
+
made_with_ai: z.boolean().optional(),
|
|
109
|
+
disable_comment: z.boolean().optional(),
|
|
110
|
+
disable_duet: z.boolean().optional(),
|
|
111
|
+
disable_stitch: z.boolean().optional(),
|
|
112
|
+
brand_content_toggle: z.boolean().optional(),
|
|
113
|
+
brand_organic_toggle: z.boolean().optional(),
|
|
114
|
+
}).strict();
|
|
115
|
+
|
|
116
|
+
// Facebook parameters validation
|
|
117
|
+
export const FacebookParamsSchema = z.object({
|
|
118
|
+
format: z.enum(["post", "story"], {
|
|
119
|
+
errorMap: () => ({ message: "Facebook format must be 'post' or 'story'" }),
|
|
120
|
+
}).optional(),
|
|
121
|
+
first_comment: z.string().optional(),
|
|
122
|
+
page_id: z.string().optional(),
|
|
123
|
+
}).strict();
|
|
124
|
+
|
|
125
|
+
// LinkedIn parameters validation
|
|
126
|
+
export const LinkedInParamsSchema = z.object({
|
|
127
|
+
organization_id: z.string().optional(),
|
|
128
|
+
}).strict();
|
|
129
|
+
|
|
130
|
+
// Twitter/X and Threads don't have platform-specific parameters
|
|
131
|
+
export const TwitterParamsSchema = z.object({}).strict();
|
|
132
|
+
export const ThreadsParamsSchema = z.object({}).strict();
|
|
133
|
+
|
|
134
|
+
// Combined platform parameters schema
|
|
135
|
+
export const PlatformParamsSchema = z.object({
|
|
136
|
+
instagram: InstagramParamsSchema.optional(),
|
|
137
|
+
youtube: YouTubeParamsSchema.optional(),
|
|
138
|
+
tiktok: TikTokParamsSchema.optional(),
|
|
139
|
+
facebook: FacebookParamsSchema.optional(),
|
|
140
|
+
linkedin: LinkedInParamsSchema.optional(),
|
|
141
|
+
twitter: TwitterParamsSchema.optional(),
|
|
142
|
+
threads: ThreadsParamsSchema.optional(),
|
|
143
|
+
}).strict().optional();
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Schema for post.publish parameters
|
|
147
|
+
*/
|
|
148
|
+
export const PostPublishSchema = z.object({
|
|
149
|
+
content: z.string().min(1, "Content cannot be empty"),
|
|
150
|
+
targets: z.array(z.string()).min(1, "At least one target is required"),
|
|
151
|
+
schedule: ISO8601DateSchema.optional(),
|
|
152
|
+
media: z.array(MediaItemSchema).optional(),
|
|
153
|
+
idempotency_key: z.string().optional(),
|
|
154
|
+
require_confirmation: z.boolean().optional(),
|
|
155
|
+
draft: z.boolean().optional(),
|
|
156
|
+
platforms: PlatformParamsSchema,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Validate that a schedule date is in the future
|
|
161
|
+
*/
|
|
162
|
+
export function validateScheduleInFuture(schedule: string): boolean {
|
|
163
|
+
const scheduleDate = new Date(schedule);
|
|
164
|
+
const now = new Date();
|
|
165
|
+
return scheduleDate > now;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Type inference helpers
|
|
170
|
+
*/
|
|
171
|
+
export type PostPublishParams = z.infer<typeof PostPublishSchema>;
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*"],
|
|
18
|
+
"exclude": ["node_modules", "dist"]
|
|
19
|
+
}
|