feat(saas): full SquareMCP SaaS platform v1

- JWT auth with bcrypt password hashing, cookie sessions, forgot/reset password
- Per-user encrypted credential storage (Redis + AES-256-GCM) for all 9 platforms
- Usage tracking with monthly limits per plan (free/starter/growth/enterprise)
- Invoice generation and retrieval (admin + user views)
- Admin panel with customer listing (role-based access)
- Web app UI at app.squaremcp.com — login, dashboard, connections, usage, invoices
- Unified auth middleware: API key, OAuth Bearer, and JWT cookie support
- Facebook Graph API fixes: published_posts endpoint, photo/video post support
- TikTok sandbox compliance: SELF_ONLY privacy for unaudited apps
- URL verification files for TikTok app review
This commit is contained in:
Garfield
2026-05-13 08:42:33 -04:00
parent 7796de12bf
commit a5e4c55885
46 changed files with 4054 additions and 171 deletions

View File

@@ -99,7 +99,7 @@ export async function getPosts(
const { accessToken, pageId } = await resolveCreds(args, customer);
const limit = args.limit ?? 10;
const data = await fbRequest(
`/${pageId}/feed?fields=id,message,story,created_time,permalink_url&limit=${limit}`,
`/${pageId}/published_posts?fields=id,message,story,created_time,permalink_url&limit=${limit}`,
accessToken
);
return (data.data ?? []).map((p: Record<string, unknown>) => ({

View File

@@ -6,7 +6,7 @@ const TIKTOK_API_BASE = 'https://open.tiktokapis.com/v2';
function getEnvToken(account: string): string {
const envKey = `TIKTOK_${account.toUpperCase()}_ACCESS_TOKEN`;
return process.env[envKey] ?? '';
return process.env[envKey] ?? process.env.TIKTOK_DEFAULT_ACCESS_TOKEN ?? '';
}
async function resolveToken(args: { account?: string }, customer?: Customer): Promise<string> {
@@ -122,9 +122,13 @@ export async function createVideo(
// Step 1: query creator info to get valid privacy levels (sandbox may not support PUBLIC_TO_EVERYONE)
const creatorInfo = await getCreatorInfo(args, customer);
const privacyLevel = creatorInfo.privacy_level_options.includes('PUBLIC_TO_EVERYONE')
const options = creatorInfo.privacy_level_options;
// Unaudited apps MUST post SELF_ONLY; prefer that when public isn't available
const privacyLevel = options.includes('PUBLIC_TO_EVERYONE')
? 'PUBLIC_TO_EVERYONE'
: creatorInfo.privacy_level_options[0] ?? 'SELF_ONLY';
: options.includes('SELF_ONLY')
? 'SELF_ONLY'
: options[0] ?? 'SELF_ONLY';
// Step 2: initialise upload
const init = await tiktokRequest('/post/publish/video/init/', accessToken, 'POST', {