diff --git a/.env.browser-use.secret b/.env.browser-use.secret deleted file mode 100644 index 84e6885..0000000 --- a/.env.browser-use.secret +++ /dev/null @@ -1,5 +0,0 @@ -# Browser Use MCP Environment Variables -# DO NOT COMMIT TO PUBLIC REPOS - -BROWSER_USE_API_KEY=not_set - diff --git a/.gitignore b/.gitignore index 12030cb..24054c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,29 +1,87 @@ - -.DS_Store -.env -.idea/ -.reonomy-credentials.* -.vscode/ -*.env -*.env.local -*.log -*.png -*.swo -*.swp -/tmp/reonomy-*.html -/tmp/reonomy-*.json -/tmp/reonomy-*.png -/tmp/reonomy-*.txt -# Credentials -# IDE files -# Logs -# Node modules # OS files -# Screenshots -# Test files -node_modules/ -npm-debug.log* -package-lock.json -reonomy-scraper.log +.DS_Store Thumbs.db + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo + +# Environment / Secrets +.env +*.env +*.env.* +.reonomy-credentials.* + +# Logs +*.log +npm-debug.log* +reonomy-scraper.log + +# Node +node_modules/ +package-lock.json + +# ======================== +# Binary / Media Files +# (These don't belong in git) +# ======================== + +# Images +*.png +*.jpg +*.jpeg +*.gif +*.webp +*.ico +*.svg +*.bmp +*.tiff + +# Video +*.mp4 +*.webm +*.mov +*.avi +*.mkv +*.wmv + +# Audio +*.wav +*.mp3 +*.ogg +*.flac +*.aac +*.m4a +*.caf + +# Documents / PDFs +*.pdf + +# Archives +*.zip +*.tar +*.gz +*.rar +*.7z + +# Compiled / Binary +*.pyc +__pycache__/ +dist/ + +# ======================== +# Project-Specific +# ======================== + +# Reonomy +/tmp/reonomy-* +reonomy-auth.json +reonomy-daily-stats.json + +# Frameworks pageindex-framework/ + +# Temp files +/tmp/ diff --git a/__pycache__/memory-retrieval.cpython-314.pyc b/__pycache__/memory-retrieval.cpython-314.pyc deleted file mode 100644 index 07109f4..0000000 Binary files a/__pycache__/memory-retrieval.cpython-314.pyc and /dev/null differ diff --git a/book-compressed/2026-01-27-book-00-cover.jpg b/book-compressed/2026-01-27-book-00-cover.jpg deleted file mode 100644 index eb6bdea..0000000 Binary files a/book-compressed/2026-01-27-book-00-cover.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-01-incident.jpg b/book-compressed/2026-01-27-book-01-incident.jpg deleted file mode 100644 index 3aa79ef..0000000 Binary files a/book-compressed/2026-01-27-book-01-incident.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-02-trademark.jpg b/book-compressed/2026-01-27-book-02-trademark.jpg deleted file mode 100644 index a461871..0000000 Binary files a/book-compressed/2026-01-27-book-02-trademark.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-03-heist.jpg b/book-compressed/2026-01-27-book-03-heist.jpg deleted file mode 100644 index ca0dce3..0000000 Binary files a/book-compressed/2026-01-27-book-03-heist.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-04-scam.jpg b/book-compressed/2026-01-27-book-04-scam.jpg deleted file mode 100644 index e6b8589..0000000 Binary files a/book-compressed/2026-01-27-book-04-scam.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-05-portforward.jpg b/book-compressed/2026-01-27-book-05-portforward.jpg deleted file mode 100644 index c292218..0000000 Binary files a/book-compressed/2026-01-27-book-05-portforward.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-06-exposed.jpg b/book-compressed/2026-01-27-book-06-exposed.jpg deleted file mode 100644 index 5a9574c..0000000 Binary files a/book-compressed/2026-01-27-book-06-exposed.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-07-injection.jpg b/book-compressed/2026-01-27-book-07-injection.jpg deleted file mode 100644 index 1e977ad..0000000 Binary files a/book-compressed/2026-01-27-book-07-injection.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-08-fud.jpg b/book-compressed/2026-01-27-book-08-fud.jpg deleted file mode 100644 index 65151a2..0000000 Binary files a/book-compressed/2026-01-27-book-08-fud.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-09-safety.jpg b/book-compressed/2026-01-27-book-09-safety.jpg deleted file mode 100644 index edf4707..0000000 Binary files a/book-compressed/2026-01-27-book-09-safety.jpg and /dev/null differ diff --git a/book-compressed/2026-01-27-book-10-conclusion.jpg b/book-compressed/2026-01-27-book-10-conclusion.jpg deleted file mode 100644 index 82ebbb5..0000000 Binary files a/book-compressed/2026-01-27-book-10-conclusion.jpg and /dev/null differ diff --git a/burton-method/lead-magnets/7-traps-under-165.pdf b/burton-method/lead-magnets/7-traps-under-165.pdf deleted file mode 100644 index dfa1e3c..0000000 Binary files a/burton-method/lead-magnets/7-traps-under-165.pdf and /dev/null differ diff --git a/burton-method/lead-magnets/lr-cheatsheet.pdf b/burton-method/lead-magnets/lr-cheatsheet.pdf deleted file mode 100644 index b4b6c80..0000000 Binary files a/burton-method/lead-magnets/lr-cheatsheet.pdf and /dev/null differ diff --git a/carousel-1-story-compressed.jpg b/carousel-1-story-compressed.jpg deleted file mode 100644 index 73a1792..0000000 Binary files a/carousel-1-story-compressed.jpg and /dev/null differ diff --git a/carousel-2-chaos-compressed.jpg b/carousel-2-chaos-compressed.jpg deleted file mode 100644 index 1e39b18..0000000 Binary files a/carousel-2-chaos-compressed.jpg and /dev/null differ diff --git a/carousel-3-verdict-compressed.jpg b/carousel-3-verdict-compressed.jpg deleted file mode 100644 index 8ab6d49..0000000 Binary files a/carousel-3-verdict-compressed.jpg and /dev/null differ diff --git a/clawdbot-book/Clawdbot-Security-Guide.pdf b/clawdbot-book/Clawdbot-Security-Guide.pdf deleted file mode 100644 index 1bbbcdc..0000000 Binary files a/clawdbot-book/Clawdbot-Security-Guide.pdf and /dev/null differ diff --git a/clawdbot-book/slide-01.jpg b/clawdbot-book/slide-01.jpg deleted file mode 100644 index 1241ef8..0000000 Binary files a/clawdbot-book/slide-01.jpg and /dev/null differ diff --git a/clawdbot-book/slide-02.jpg b/clawdbot-book/slide-02.jpg deleted file mode 100644 index 0353ef5..0000000 Binary files a/clawdbot-book/slide-02.jpg and /dev/null differ diff --git a/clawdbot-book/slide-03.jpg b/clawdbot-book/slide-03.jpg deleted file mode 100644 index 4b019e6..0000000 Binary files a/clawdbot-book/slide-03.jpg and /dev/null differ diff --git a/clawdbot-book/slide-04.jpg b/clawdbot-book/slide-04.jpg deleted file mode 100644 index f205036..0000000 Binary files a/clawdbot-book/slide-04.jpg and /dev/null differ diff --git a/clawdbot-book/slide-05.jpg b/clawdbot-book/slide-05.jpg deleted file mode 100644 index 77b61cc..0000000 Binary files a/clawdbot-book/slide-05.jpg and /dev/null differ diff --git a/clawdbot-book/slide-06.jpg b/clawdbot-book/slide-06.jpg deleted file mode 100644 index 4b4f66d..0000000 Binary files a/clawdbot-book/slide-06.jpg and /dev/null differ diff --git a/clawdbot-book/slide-07.jpg b/clawdbot-book/slide-07.jpg deleted file mode 100644 index 350db3f..0000000 Binary files a/clawdbot-book/slide-07.jpg and /dev/null differ diff --git a/clawdbot-book/slide-08.jpg b/clawdbot-book/slide-08.jpg deleted file mode 100644 index 32e1242..0000000 Binary files a/clawdbot-book/slide-08.jpg and /dev/null differ diff --git a/clawdbot-book/slide-09.jpg b/clawdbot-book/slide-09.jpg deleted file mode 100644 index 255b716..0000000 Binary files a/clawdbot-book/slide-09.jpg and /dev/null differ diff --git a/clawdbot-book/slide-10.jpg b/clawdbot-book/slide-10.jpg deleted file mode 100644 index 3d0aa3c..0000000 Binary files a/clawdbot-book/slide-10.jpg and /dev/null differ diff --git a/das-surya-review/lyrics/01-skin-intro.txt b/das-surya-review/lyrics/01-skin-intro.txt new file mode 100644 index 0000000..7f2d436 --- /dev/null +++ b/das-surya-review/lyrics/01-skin-intro.txt @@ -0,0 +1 @@ +Take a step to do it. Yes. Yes! You did it! I didn't know all the feelings I could miss. Until I looked inside my mind I've been lost since. I don't know how to fit in my own skin. Don't feel at home in this world I'm living in. diff --git a/das-surya-review/lyrics/02-u-saved-me.txt b/das-surya-review/lyrics/02-u-saved-me.txt new file mode 100644 index 0000000..c9d4c63 --- /dev/null +++ b/das-surya-review/lyrics/02-u-saved-me.txt @@ -0,0 +1 @@ +There's no me, there's just us When I said it, I swear I meant it You were always enough I didn't mean to take you for granted You saved me from my broken soul We gave each other full control I left you crying on the road We both know that the night gets cold We gave each other full control We both know that the night gets cold You call me crazy, I'm just faded I'm escaping from your clutch I'm just chasing sweet sedation Using your heart as my crutch Self-inflated expectations Never met or overcome Now I'm jaded, complicated No surprise you chose to run You saved me from my broken soul We gave each other full control I left you crying on the road We both know that the night gets cold We gave each other full control We both know that the night gets cold You saved me from my broken soul We gave each other full control I left you crying on the road We both know that the night gets cold diff --git a/das-surya-review/lyrics/03-nothing.txt b/das-surya-review/lyrics/03-nothing.txt new file mode 100644 index 0000000..e7850a1 --- /dev/null +++ b/das-surya-review/lyrics/03-nothing.txt @@ -0,0 +1 @@ +I lost my heart, now I feel nothing It's been a while since I've felt something The blame cuts deep and thoughts start crushing I ease the pain with self-destruction I've been so out of touch Mistaken kindness for affection, it's not love Have I been cursed with bad luck? Cause my stars don't align with my sun I lost my heart, now I feel nothing It's been a while since I've felt something The blame cuts deep and thoughts start crushing I ease the pain with self-destruction diff --git a/das-surya-review/lyrics/04-sweet-relief.txt b/das-surya-review/lyrics/04-sweet-relief.txt new file mode 100644 index 0000000..d6c194d --- /dev/null +++ b/das-surya-review/lyrics/04-sweet-relief.txt @@ -0,0 +1 @@ +The teardrop in your eye Contains a single lethal dose You're lying by my side But I can't seem to find a pulse The days keep passing by This love's a waste of time, you know Another sleepless night And I might need to overdose Please don't go Won't you stay? Please don't go Won't you stay? You've got me on my knees I'm begging for sweet relief Each time you go You break a piece of my soul You cut me then stomp the blade And convince me you're all I need I'm seeing ghosts They've got their hands around my throat You keep on turning little nothings into somethings You throw in pillows slamming undeserving doors Your words cut deeper than a knife Can't even look me in the eye So please just go Please just go Don't you stay Please just go Don't you stay You've got me on my knees I'm begging for sweet relief Each time you go You break a piece of my soul You cut me then stomp the blade And convince me you're all I need I'm seeing ghosts They've got their hands around my throat You cut me then stomp the blade And convince me you're all I need diff --git a/das-surya-review/lyrics/05-tiptoe.txt b/das-surya-review/lyrics/05-tiptoe.txt new file mode 100644 index 0000000..7c83334 --- /dev/null +++ b/das-surya-review/lyrics/05-tiptoe.txt @@ -0,0 +1 @@ +To your right is the Baguio Botanical Garden To your left is the Baguio Botanical Garden To your right is the Baguio Botanical Garden To your right is the Baguio Botanical Garden To your left is the Baguio Botanical Garden To your right is the Baguio Botanical Garden To your left is the Baguio Botanical Garden To your right is the Baguio Botanical Garden To your left is the Baguio Botanical Garden To your right is the Baguio Botanical Garden To your left is the Baguio Botanical Garden To your right is the Baguio Botanical Garden diff --git a/das-surya-review/lyrics/06-natures-call.txt b/das-surya-review/lyrics/06-natures-call.txt new file mode 100644 index 0000000..1db7a59 --- /dev/null +++ b/das-surya-review/lyrics/06-natures-call.txt @@ -0,0 +1 @@ +We are turning right to Session Road We are turning right to Session Road Are you still there? If so, we'd like to thank you for joining us in today's drive. Thank you for joining us on this drive. We are turning right to Session Road Are you still there? If so, we'd like to thank you for joining us in today's drive. diff --git a/guide-compressed/2026-01-27-guide-01-cover.jpg b/guide-compressed/2026-01-27-guide-01-cover.jpg deleted file mode 100644 index bcd4c29..0000000 Binary files a/guide-compressed/2026-01-27-guide-01-cover.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-02-rise.jpg b/guide-compressed/2026-01-27-guide-02-rise.jpg deleted file mode 100644 index b3bcef7..0000000 Binary files a/guide-compressed/2026-01-27-guide-02-rise.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-03-whatisit.jpg b/guide-compressed/2026-01-27-guide-03-whatisit.jpg deleted file mode 100644 index 2f2db84..0000000 Binary files a/guide-compressed/2026-01-27-guide-03-whatisit.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-04-trademark.jpg b/guide-compressed/2026-01-27-guide-04-trademark.jpg deleted file mode 100644 index 62f2725..0000000 Binary files a/guide-compressed/2026-01-27-guide-04-trademark.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-05-rebrand.jpg b/guide-compressed/2026-01-27-guide-05-rebrand.jpg deleted file mode 100644 index 0cc5c40..0000000 Binary files a/guide-compressed/2026-01-27-guide-05-rebrand.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-06-heist.jpg b/guide-compressed/2026-01-27-guide-06-heist.jpg deleted file mode 100644 index 40b359b..0000000 Binary files a/guide-compressed/2026-01-27-guide-06-heist.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-07-scam.jpg b/guide-compressed/2026-01-27-guide-07-scam.jpg deleted file mode 100644 index fca897c..0000000 Binary files a/guide-compressed/2026-01-27-guide-07-scam.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-08-security.jpg b/guide-compressed/2026-01-27-guide-08-security.jpg deleted file mode 100644 index 58fafd7..0000000 Binary files a/guide-compressed/2026-01-27-guide-08-security.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-09-portforward.jpg b/guide-compressed/2026-01-27-guide-09-portforward.jpg deleted file mode 100644 index 8f19c86..0000000 Binary files a/guide-compressed/2026-01-27-guide-09-portforward.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-10-injection.jpg b/guide-compressed/2026-01-27-guide-10-injection.jpg deleted file mode 100644 index cad73d1..0000000 Binary files a/guide-compressed/2026-01-27-guide-10-injection.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-11-exposed.jpg b/guide-compressed/2026-01-27-guide-11-exposed.jpg deleted file mode 100644 index 126a683..0000000 Binary files a/guide-compressed/2026-01-27-guide-11-exposed.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-12-fault.jpg b/guide-compressed/2026-01-27-guide-12-fault.jpg deleted file mode 100644 index b04967b..0000000 Binary files a/guide-compressed/2026-01-27-guide-12-fault.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-13-safe.jpg b/guide-compressed/2026-01-27-guide-13-safe.jpg deleted file mode 100644 index 76e38e4..0000000 Binary files a/guide-compressed/2026-01-27-guide-13-safe.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-14-checklist.jpg b/guide-compressed/2026-01-27-guide-14-checklist.jpg deleted file mode 100644 index 443f16e..0000000 Binary files a/guide-compressed/2026-01-27-guide-14-checklist.jpg and /dev/null differ diff --git a/guide-compressed/2026-01-27-guide-15-conclusion.jpg b/guide-compressed/2026-01-27-guide-15-conclusion.jpg deleted file mode 100644 index f71b191..0000000 Binary files a/guide-compressed/2026-01-27-guide-15-conclusion.jpg and /dev/null differ diff --git a/mcp-diagrams/ghl-mcp-apps-only/.env.example b/mcp-diagrams/ghl-mcp-apps-only/.env.example deleted file mode 100644 index 08cb1a8..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/.env.example +++ /dev/null @@ -1,11 +0,0 @@ -# GoHighLevel API Configuration -GHL_API_KEY=your_private_integration_api_key_here -GHL_BASE_URL=https://services.leadconnectorhq.com -GHL_LOCATION_ID=your_location_id_here - -# Server Configuration -MCP_SERVER_PORT=8000 -NODE_ENV=development - -# Optional: For AI features -OPENAI_API_KEY=your_openai_key_here_optional diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/agent-stats.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/agent-stats.html deleted file mode 100644 index ffbf138..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/agent-stats.html +++ /dev/null @@ -1,481 +0,0 @@ - - - - - - GHL Agent Leaderboard - - - - -
-
-
- Loading agent leaderboard... -
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/calendar-view.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/calendar-view.html deleted file mode 100644 index 13d2c93..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/calendar-view.html +++ /dev/null @@ -1,544 +0,0 @@ - - - - - - GHL Calendar View - - - - -
-
Loading calendar...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/campaign-stats.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/campaign-stats.html deleted file mode 100644 index b3ddb43..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/campaign-stats.html +++ /dev/null @@ -1,442 +0,0 @@ - - - - - - Campaign Performance Dashboard - - - - -
-
Loading campaign performance data...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/contact-grid.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/contact-grid.html deleted file mode 100644 index c1cbee7..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/contact-grid.html +++ /dev/null @@ -1,501 +0,0 @@ - - - - - - GHL Contact Grid - - - - -
-
Loading contacts...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/contact-timeline.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/contact-timeline.html deleted file mode 100644 index dbfba44..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/contact-timeline.html +++ /dev/null @@ -1,355 +0,0 @@ - - - - - - Contact Activity Timeline - - - - -
-
Loading timeline...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/invoice-preview.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/invoice-preview.html deleted file mode 100644 index 1b024ca..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/invoice-preview.html +++ /dev/null @@ -1,474 +0,0 @@ - - - - - - Invoice Preview - - - - -
-
Loading invoice...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/mcp-app.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/mcp-app.html deleted file mode 100644 index 72e960d..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/mcp-app.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - GHL Conversation - - - - -
-
Loading conversation...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/opportunity-card.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/opportunity-card.html deleted file mode 100644 index f3c7161..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/opportunity-card.html +++ /dev/null @@ -1,520 +0,0 @@ - - - - - - GHL Opportunity Card - - - - -
-
Loading opportunity...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/pipeline-board.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/pipeline-board.html deleted file mode 100644 index 88cbec5..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/pipeline-board.html +++ /dev/null @@ -1,533 +0,0 @@ - - - - - - GHL Pipeline Board - - - - -
-
Loading pipeline board...
-
- - - - - - - - - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/quick-book.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/quick-book.html deleted file mode 100644 index b25ad6a..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/quick-book.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - GHL Quick Booking - - - - -
-
Loading available slots...
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/workflow-status.html b/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/workflow-status.html deleted file mode 100644 index 6e4be47..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/app-ui/workflow-status.html +++ /dev/null @@ -1,352 +0,0 @@ - - - - - - GHL Workflow Status Monitor - - - - -
-
-
- Loading workflow status... -
-
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/apps/index.js b/mcp-diagrams/ghl-mcp-apps-only/dist/apps/index.js deleted file mode 100644 index 9117063..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/apps/index.js +++ /dev/null @@ -1,654 +0,0 @@ -/** - * MCP Apps Manager - * Manages rich UI components for GoHighLevel MCP Server - */ -import * as fs from 'fs'; -import * as path from 'path'; -import { fileURLToPath } from 'url'; -/** - * MCP Apps Manager class - * Registers app tools and handles structuredContent responses - */ -// ESM equivalent of __dirname -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -// Resolve UI build path - works regardless of working directory -function getUIBuildPath() { - // When compiled, this file is at dist/apps/index.js - // UI files are at dist/app-ui/ - const fromDist = path.resolve(__dirname, '..', 'app-ui'); - if (fs.existsSync(fromDist)) { - return fromDist; - } - // Fallback: try process.cwd() based paths - const appUiPath = path.join(process.cwd(), 'dist', 'app-ui'); - if (fs.existsSync(appUiPath)) { - return appUiPath; - } - // Default fallback - return fromDist; -} -export class MCPAppsManager { - ghlClient; - resourceHandlers = new Map(); - uiBuildPath; - constructor(ghlClient) { - this.ghlClient = ghlClient; - this.uiBuildPath = getUIBuildPath(); - process.stderr.write(`[MCP Apps] UI build path: ${this.uiBuildPath}\n`); - this.registerResourceHandlers(); - } - /** - * Register all UI resource handlers - */ - registerResourceHandlers() { - const resources = [ - // All 11 MCP Apps - { uri: 'ui://ghl/mcp-app', file: 'mcp-app.html' }, - { uri: 'ui://ghl/pipeline-board', file: 'pipeline-board.html' }, - { uri: 'ui://ghl/quick-book', file: 'quick-book.html' }, - { uri: 'ui://ghl/opportunity-card', file: 'opportunity-card.html' }, - { uri: 'ui://ghl/contact-grid', file: 'contact-grid.html' }, - { uri: 'ui://ghl/calendar-view', file: 'calendar-view.html' }, - { uri: 'ui://ghl/invoice-preview', file: 'invoice-preview.html' }, - { uri: 'ui://ghl/campaign-stats', file: 'campaign-stats.html' }, - { uri: 'ui://ghl/agent-stats', file: 'agent-stats.html' }, - { uri: 'ui://ghl/contact-timeline', file: 'contact-timeline.html' }, - { uri: 'ui://ghl/workflow-status', file: 'workflow-status.html' }, - ]; - for (const resource of resources) { - this.resourceHandlers.set(resource.uri, { - uri: resource.uri, - mimeType: 'text/html;profile=mcp-app', - getContent: () => this.loadUIResource(resource.file), - }); - } - } - /** - * Load UI resource from build directory - */ - loadUIResource(filename) { - const filePath = path.join(this.uiBuildPath, filename); - try { - return fs.readFileSync(filePath, 'utf-8'); - } - catch (error) { - process.stderr.write(`[MCP Apps] UI resource not found: ${filePath}\n`); - return this.getFallbackHTML(filename); - } - } - /** - * Generate fallback HTML when UI resource is not built - */ - getFallbackHTML(filename) { - const componentName = filename.replace('.html', ''); - return ` - - - - - - GHL ${componentName} - - - -
-

UI component "${componentName}" is loading...

-

Run npm run build:ui to build UI components.

-
- - - - `.trim(); - } - /** - * Get tool definitions for all app tools - */ - getToolDefinitions() { - return [ - // 1. Contact Grid - search and display contacts - { - name: 'view_contact_grid', - description: 'Display contact search results in a data grid with sorting and pagination. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - query: { type: 'string', description: 'Search query string' }, - limit: { type: 'number', description: 'Maximum results (default: 25)' } - } - }, - _meta: { - ui: { resourceUri: 'ui://ghl/contact-grid' } - } - }, - // 2. Pipeline Board - Kanban view of opportunities - { - name: 'view_pipeline_board', - description: 'Display a pipeline as an interactive Kanban board with opportunities. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - pipelineId: { type: 'string', description: 'Pipeline ID to display' } - }, - required: ['pipelineId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/pipeline-board' } - } - }, - // 3. Quick Book - appointment booking - { - name: 'view_quick_book', - description: 'Display a quick booking interface for scheduling appointments. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - calendarId: { type: 'string', description: 'Calendar ID for booking' }, - contactId: { type: 'string', description: 'Optional contact ID to pre-fill' } - }, - required: ['calendarId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/quick-book' } - } - }, - // 4. Opportunity Card - single opportunity details - { - name: 'view_opportunity_card', - description: 'Display a single opportunity with details, value, and stage info. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - opportunityId: { type: 'string', description: 'Opportunity ID to display' } - }, - required: ['opportunityId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/opportunity-card' } - } - }, - // 5. Calendar View - calendar with events - { - name: 'view_calendar', - description: 'Display a calendar with events and appointments. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - calendarId: { type: 'string', description: 'Calendar ID to display' }, - startDate: { type: 'string', description: 'Start date (ISO format)' }, - endDate: { type: 'string', description: 'End date (ISO format)' } - }, - required: ['calendarId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/calendar-view' } - } - }, - // 6. Invoice Preview - invoice details - { - name: 'view_invoice', - description: 'Display an invoice preview with line items and payment status. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - invoiceId: { type: 'string', description: 'Invoice ID to display' } - }, - required: ['invoiceId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/invoice-preview' } - } - }, - // 7. Campaign Stats - campaign performance metrics - { - name: 'view_campaign_stats', - description: 'Display campaign statistics and performance metrics. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - campaignId: { type: 'string', description: 'Campaign ID to display stats for' } - }, - required: ['campaignId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/campaign-stats' } - } - }, - // 8. Agent Stats - agent/user performance - { - name: 'view_agent_stats', - description: 'Display agent/user performance statistics and metrics. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - userId: { type: 'string', description: 'User/Agent ID to display stats for' }, - dateRange: { type: 'string', description: 'Date range (e.g., "last7days", "last30days")' } - } - }, - _meta: { - ui: { resourceUri: 'ui://ghl/agent-stats' } - } - }, - // 9. Contact Timeline - activity history for a contact - { - name: 'view_contact_timeline', - description: 'Display a contact\'s activity timeline with all interactions. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - contactId: { type: 'string', description: 'Contact ID to display timeline for' } - }, - required: ['contactId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/contact-timeline' } - } - }, - // 10. Workflow Status - workflow execution status - { - name: 'view_workflow_status', - description: 'Display workflow execution status and history. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: { - workflowId: { type: 'string', description: 'Workflow ID to display status for' } - }, - required: ['workflowId'] - }, - _meta: { - ui: { resourceUri: 'ui://ghl/workflow-status' } - } - }, - // 11. MCP App - generic/main dashboard - { - name: 'view_dashboard', - description: 'Display the main GHL dashboard overview. Returns a visual UI component.', - inputSchema: { - type: 'object', - properties: {} - }, - _meta: { - ui: { resourceUri: 'ui://ghl/mcp-app' } - } - }, - // 12. Update Opportunity - action tool for UI to update opportunities - { - name: 'update_opportunity', - description: 'Update an opportunity (move to stage, change value, status, etc.)', - inputSchema: { - type: 'object', - properties: { - opportunityId: { type: 'string', description: 'Opportunity ID to update' }, - pipelineStageId: { type: 'string', description: 'New stage ID (for moving)' }, - name: { type: 'string', description: 'Opportunity name' }, - monetaryValue: { type: 'number', description: 'Monetary value' }, - status: { type: 'string', enum: ['open', 'won', 'lost', 'abandoned'], description: 'Opportunity status' } - }, - required: ['opportunityId'] - } - } - ]; - } - /** - * Get app tool names for routing - */ - getAppToolNames() { - return [ - 'view_contact_grid', - 'view_pipeline_board', - 'view_quick_book', - 'view_opportunity_card', - 'view_calendar', - 'view_invoice', - 'view_campaign_stats', - 'view_agent_stats', - 'view_contact_timeline', - 'view_workflow_status', - 'view_dashboard', - 'update_opportunity' - ]; - } - /** - * Check if a tool is an app tool - */ - isAppTool(toolName) { - return this.getAppToolNames().includes(toolName); - } - /** - * Execute an app tool - */ - async executeTool(toolName, args) { - process.stderr.write(`[MCP Apps] Executing app tool: ${toolName}\n`); - switch (toolName) { - case 'view_contact_grid': - return await this.viewContactGrid(args.query, args.limit); - case 'view_pipeline_board': - return await this.viewPipelineBoard(args.pipelineId); - case 'view_quick_book': - return await this.viewQuickBook(args.calendarId, args.contactId); - case 'view_opportunity_card': - return await this.viewOpportunityCard(args.opportunityId); - case 'view_calendar': - return await this.viewCalendar(args.calendarId, args.startDate, args.endDate); - case 'view_invoice': - return await this.viewInvoice(args.invoiceId); - case 'view_campaign_stats': - return await this.viewCampaignStats(args.campaignId); - case 'view_agent_stats': - return await this.viewAgentStats(args.userId, args.dateRange); - case 'view_contact_timeline': - return await this.viewContactTimeline(args.contactId); - case 'view_workflow_status': - return await this.viewWorkflowStatus(args.workflowId); - case 'view_dashboard': - return await this.viewDashboard(); - case 'update_opportunity': - return await this.updateOpportunity(args); - default: - throw new Error(`Unknown app tool: ${toolName}`); - } - } - /** - * View contact grid (search results) - */ - async viewContactGrid(query, limit) { - const response = await this.ghlClient.searchContacts({ - locationId: this.ghlClient.getConfig().locationId, - query: query, - limit: limit || 25 - }); - if (!response.success) { - throw new Error(response.error?.message || 'Failed to search contacts'); - } - const data = response.data; - const resourceHandler = this.resourceHandlers.get('ui://ghl/contact-grid'); - return this.createAppResult(`Found ${data?.contacts?.length || 0} contacts`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View pipeline board (Kanban) - */ - async viewPipelineBoard(pipelineId) { - const [pipelinesResponse, opportunitiesResponse] = await Promise.all([ - this.ghlClient.getPipelines(), - this.ghlClient.searchOpportunities({ - location_id: this.ghlClient.getConfig().locationId, - pipeline_id: pipelineId - }) - ]); - if (!pipelinesResponse.success) { - throw new Error(pipelinesResponse.error?.message || 'Failed to get pipeline'); - } - const pipeline = pipelinesResponse.data?.pipelines?.find((p) => p.id === pipelineId); - const opportunities = opportunitiesResponse.data?.opportunities || []; - // Simplify opportunity data to only include fields the UI needs (reduces payload size) - const simplifiedOpportunities = opportunities.map((opp) => ({ - id: opp.id, - name: opp.name || 'Untitled', - pipelineStageId: opp.pipelineStageId, - status: opp.status || 'open', - monetaryValue: opp.monetaryValue || 0, - contact: opp.contact ? { - name: opp.contact.name || 'Unknown', - email: opp.contact.email, - phone: opp.contact.phone - } : { name: 'Unknown' }, - updatedAt: opp.updatedAt || opp.createdAt, - createdAt: opp.createdAt, - source: opp.source - })); - const data = { - pipeline, - opportunities: simplifiedOpportunities, - stages: pipeline?.stages || [] - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/pipeline-board'); - return this.createAppResult(`Pipeline: ${pipeline?.name || 'Unknown'} (${opportunities.length} opportunities)`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View quick book interface - */ - async viewQuickBook(calendarId, contactId) { - const [calendarResponse, contactResponse] = await Promise.all([ - this.ghlClient.getCalendar(calendarId), - contactId ? this.ghlClient.getContact(contactId) : Promise.resolve({ success: true, data: null }) - ]); - if (!calendarResponse.success) { - throw new Error(calendarResponse.error?.message || 'Failed to get calendar'); - } - const data = { - calendar: calendarResponse.data, - contact: contactResponse.data, - locationId: this.ghlClient.getConfig().locationId - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/quick-book'); - return this.createAppResult(`Quick booking for calendar: ${calendarResponse.data?.name || calendarId}`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View opportunity card - */ - async viewOpportunityCard(opportunityId) { - const response = await this.ghlClient.getOpportunity(opportunityId); - if (!response.success) { - throw new Error(response.error?.message || 'Failed to get opportunity'); - } - const opportunity = response.data; - const resourceHandler = this.resourceHandlers.get('ui://ghl/opportunity-card'); - return this.createAppResult(`Opportunity: ${opportunity?.name || opportunityId}`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), opportunity); - } - /** - * View calendar - */ - async viewCalendar(calendarId, startDate, endDate) { - const now = new Date(); - const start = startDate || new Date(now.getFullYear(), now.getMonth(), 1).toISOString(); - const end = endDate || new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString(); - const [calendarResponse, eventsResponse] = await Promise.all([ - this.ghlClient.getCalendar(calendarId), - this.ghlClient.getCalendarEvents({ - calendarId: calendarId, - startTime: start, - endTime: end, - locationId: this.ghlClient.getConfig().locationId - }) - ]); - if (!calendarResponse.success) { - throw new Error(calendarResponse.error?.message || 'Failed to get calendar'); - } - const calendar = calendarResponse.data; - const data = { - calendar: calendarResponse.data, - events: eventsResponse.data?.events || [], - startDate: start, - endDate: end - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/calendar-view'); - return this.createAppResult(`Calendar: ${calendar?.name || 'Unknown'} (${data.events.length} events)`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View campaign stats - */ - async viewCampaignStats(campaignId) { - // Get email campaigns - const response = await this.ghlClient.getEmailCampaigns({}); - const campaigns = response.data?.schedules || []; - const campaign = campaigns.find((c) => c.id === campaignId) || { id: campaignId }; - const data = { - campaign, - campaigns, - campaignId, - locationId: this.ghlClient.getConfig().locationId - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/campaign-stats'); - return this.createAppResult(`Campaign stats: ${campaign?.name || campaignId}`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View agent stats - */ - async viewAgentStats(userId, dateRange) { - // Get location info which may include user data - const locationResponse = await this.ghlClient.getLocationById(this.ghlClient.getConfig().locationId); - const data = { - userId, - dateRange: dateRange || 'last30days', - location: locationResponse.data, - locationId: this.ghlClient.getConfig().locationId - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/agent-stats'); - return this.createAppResult(userId ? `Agent stats: ${userId}` : 'Agent overview', resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View contact timeline - */ - async viewContactTimeline(contactId) { - const [contactResponse, notesResponse, tasksResponse] = await Promise.all([ - this.ghlClient.getContact(contactId), - this.ghlClient.getContactNotes(contactId), - this.ghlClient.getContactTasks(contactId) - ]); - if (!contactResponse.success) { - throw new Error(contactResponse.error?.message || 'Failed to get contact'); - } - const contact = contactResponse.data; - const data = { - contact: contactResponse.data, - notes: notesResponse.data || [], - tasks: tasksResponse.data || [] - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/contact-timeline'); - return this.createAppResult(`Timeline for ${contact?.firstName || ''} ${contact?.lastName || ''}`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View workflow status - */ - async viewWorkflowStatus(workflowId) { - const response = await this.ghlClient.getWorkflows({ - locationId: this.ghlClient.getConfig().locationId - }); - const workflows = response.data?.workflows || []; - const workflow = workflows.find((w) => w.id === workflowId) || { id: workflowId }; - const data = { - workflow, - workflows, - workflowId, - locationId: this.ghlClient.getConfig().locationId - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/workflow-status'); - return this.createAppResult(`Workflow: ${workflow?.name || workflowId}`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View main dashboard - */ - async viewDashboard() { - const [contactsResponse, pipelinesResponse, calendarsResponse] = await Promise.all([ - this.ghlClient.searchContacts({ locationId: this.ghlClient.getConfig().locationId, limit: 10 }), - this.ghlClient.getPipelines(), - this.ghlClient.getCalendars() - ]); - const data = { - recentContacts: contactsResponse.data?.contacts || [], - pipelines: pipelinesResponse.data?.pipelines || [], - calendars: calendarsResponse.data?.calendars || [], - locationId: this.ghlClient.getConfig().locationId - }; - const resourceHandler = this.resourceHandlers.get('ui://ghl/mcp-app'); - return this.createAppResult('GHL Dashboard Overview', resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), data); - } - /** - * View invoice - */ - async viewInvoice(invoiceId) { - const response = await this.ghlClient.getInvoice(invoiceId, { - altId: this.ghlClient.getConfig().locationId, - altType: 'location' - }); - if (!response.success) { - throw new Error(response.error?.message || 'Failed to get invoice'); - } - const invoice = response.data; - const resourceHandler = this.resourceHandlers.get('ui://ghl/invoice-preview'); - return this.createAppResult(`Invoice #${invoice?.invoiceNumber || invoiceId} - ${invoice?.status || 'Unknown status'}`, resourceHandler.uri, resourceHandler.mimeType, resourceHandler.getContent(), invoice); - } - /** - * Update opportunity (action tool for UI) - */ - async updateOpportunity(args) { - const { opportunityId, ...updates } = args; - // Build the update payload - const updatePayload = {}; - if (updates.pipelineStageId) - updatePayload.pipelineStageId = updates.pipelineStageId; - if (updates.name) - updatePayload.name = updates.name; - if (updates.monetaryValue !== undefined) - updatePayload.monetaryValue = updates.monetaryValue; - if (updates.status) - updatePayload.status = updates.status; - process.stderr.write(`[MCP Apps] Updating opportunity ${opportunityId}: ${JSON.stringify(updatePayload)}\n`); - const response = await this.ghlClient.updateOpportunity(opportunityId, updatePayload); - if (!response.success) { - throw new Error(response.error?.message || 'Failed to update opportunity'); - } - const opportunity = response.data; - return { - content: [{ type: 'text', text: `Updated opportunity: ${opportunity?.name || opportunityId}` }], - structuredContent: { - success: true, - opportunity: { - id: opportunity?.id, - name: opportunity?.name, - pipelineStageId: opportunity?.pipelineStageId, - monetaryValue: opportunity?.monetaryValue, - status: opportunity?.status - } - } - }; - } - /** - * Create app tool result with structuredContent - */ - createAppResult(textSummary, resourceUri, mimeType, htmlContent, data) { - // structuredContent is the data object that gets passed to ontoolresult - // The UI accesses it via result.structuredContent - return { - content: [{ type: 'text', text: textSummary }], - structuredContent: data - }; - } - /** - * Inject data into HTML as a script tag - */ - injectDataIntoHTML(html, data) { - const dataScript = ``; - // Insert before or at the beginning of - if (html.includes('')) { - return html.replace('', `${dataScript}`); - } - else if (html.includes('')) { - return html.replace('', `${dataScript}`); - } - else { - return dataScript + html; - } - } - /** - * Get resource handler by URI - */ - getResourceHandler(uri) { - return this.resourceHandlers.get(uri); - } - /** - * Get all registered resource URIs - */ - getResourceURIs() { - return Array.from(this.resourceHandlers.keys()); - } -} diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/clients/ghl-api-client.js b/mcp-diagrams/ghl-mcp-apps-only/dist/clients/ghl-api-client.js deleted file mode 100644 index 4e5b0de..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/clients/ghl-api-client.js +++ /dev/null @@ -1,5107 +0,0 @@ -/** - * GoHighLevel API Client - * Implements exact API endpoints from OpenAPI specifications v2021-07-28 (Contacts) and v2021-04-15 (Conversations) - */ -import axios from 'axios'; -/** - * GoHighLevel API Client - * Handles all API communication with GHL services - */ -export class GHLApiClient { - axiosInstance; - config; - constructor(config) { - this.config = config; - // Create axios instance with base configuration - this.axiosInstance = axios.create({ - baseURL: config.baseUrl, - headers: { - 'Authorization': `Bearer ${config.accessToken}`, - 'Version': config.version, - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }, - timeout: 30000 // 30 second timeout - }); - // Add request interceptor for logging - this.axiosInstance.interceptors.request.use((config) => { - process.stderr.write(`[GHL API] ${config.method?.toUpperCase()} ${config.url}\n`); - return config; - }, (error) => { - console.error('[GHL API] Request error:', error); - return Promise.reject(error); - }); - // Add response interceptor for error handling - this.axiosInstance.interceptors.response.use((response) => { - process.stderr.write(`[GHL API] Response ${response.status}: ${response.config.url}\n`); - return response; - }, (error) => { - console.error('[GHL API] Response error:', { - status: error.response?.status, - message: error.response?.data?.message, - url: error.config?.url - }); - return Promise.reject(this.handleApiError(error)); - }); - } - /** - * Handle API errors and convert to standardized format - */ - handleApiError(error) { - const status = error.response?.status || 500; - const message = error.response?.data?.message || error.message || 'Unknown error'; - const errorMessage = Array.isArray(message) ? message.join(', ') : message; - return new Error(`GHL API Error (${status}): ${errorMessage}`); - } - /** - * Wrap API responses in standardized format - */ - wrapResponse(data) { - return { - success: true, - data - }; - } - /** - * Create custom headers for different API versions - */ - getConversationHeaders() { - return { - 'Authorization': `Bearer ${this.config.accessToken}`, - 'Version': '2021-04-15', // Conversations API uses different version - 'Content-Type': 'application/json', - 'Accept': 'application/json' - }; - } - /** - * CONTACTS API METHODS - */ - /** - * Create a new contact - * POST /contacts/ - */ - async createContact(contactData) { - try { - // Ensure locationId is set - const payload = { - ...contactData, - locationId: contactData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/contacts/', payload); - return this.wrapResponse(response.data.contact); - } - catch (error) { - throw error; - } - } - /** - * Get contact by ID - * GET /contacts/{contactId} - */ - async getContact(contactId) { - try { - const response = await this.axiosInstance.get(`/contacts/${contactId}`); - return this.wrapResponse(response.data.contact); - } - catch (error) { - throw error; - } - } - /** - * Update existing contact - * PUT /contacts/{contactId} - */ - async updateContact(contactId, updates) { - try { - const response = await this.axiosInstance.put(`/contacts/${contactId}`, updates); - return this.wrapResponse(response.data.contact); - } - catch (error) { - throw error; - } - } - /** - * Delete contact - * DELETE /contacts/{contactId} - */ - async deleteContact(contactId) { - try { - const response = await this.axiosInstance.delete(`/contacts/${contactId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Search contacts with advanced filters - * POST /contacts/search - */ - async searchContacts(searchParams) { - try { - // Build minimal request body with only required/supported parameters - // Start with just locationId and pageLimit as per API requirements - const payload = { - locationId: searchParams.locationId || this.config.locationId, - pageLimit: searchParams.limit || 25 - }; - // Only add optional parameters if they have valid values - if (searchParams.query && searchParams.query.trim()) { - payload.query = searchParams.query.trim(); - } - if (searchParams.startAfterId && searchParams.startAfterId.trim()) { - payload.startAfterId = searchParams.startAfterId.trim(); - } - if (searchParams.startAfter && typeof searchParams.startAfter === 'number') { - payload.startAfter = searchParams.startAfter; - } - // Only add filters if we have valid filter values - if (searchParams.filters) { - const filters = {}; - let hasFilters = false; - if (searchParams.filters.email && typeof searchParams.filters.email === 'string' && searchParams.filters.email.trim()) { - filters.email = searchParams.filters.email.trim(); - hasFilters = true; - } - if (searchParams.filters.phone && typeof searchParams.filters.phone === 'string' && searchParams.filters.phone.trim()) { - filters.phone = searchParams.filters.phone.trim(); - hasFilters = true; - } - if (searchParams.filters.tags && Array.isArray(searchParams.filters.tags) && searchParams.filters.tags.length > 0) { - filters.tags = searchParams.filters.tags; - hasFilters = true; - } - if (searchParams.filters.dateAdded && typeof searchParams.filters.dateAdded === 'object') { - filters.dateAdded = searchParams.filters.dateAdded; - hasFilters = true; - } - // Only add filters object if we have actual filters - if (hasFilters) { - payload.filters = filters; - } - } - process.stderr.write(`[GHL API] Search contacts payload: ${JSON.stringify(payload, null, 2)}\n`); - const response = await this.axiosInstance.post('/contacts/search', payload); - return this.wrapResponse(response.data); - } - catch (error) { - const axiosError = error; - process.stderr.write(`[GHL API] Search contacts error: ${JSON.stringify({ - status: axiosError.response?.status, - statusText: axiosError.response?.statusText, - data: axiosError.response?.data, - message: axiosError.message - }, null, 2)}\n`); - const handledError = this.handleApiError(axiosError); - return { - success: false, - error: { - message: handledError.message, - statusCode: axiosError.response?.status || 500, - details: axiosError.response?.data - } - }; - } - } - /** - * Get duplicate contact by email or phone - * GET /contacts/search/duplicate - */ - async getDuplicateContact(email, phone) { - try { - const params = { - locationId: this.config.locationId - }; - if (email) - params.email = encodeURIComponent(email); - if (phone) - params.number = encodeURIComponent(phone); - const response = await this.axiosInstance.get('/contacts/search/duplicate', { params }); - return this.wrapResponse(response.data.contact || null); - } - catch (error) { - throw error; - } - } - /** - * Add tags to contact - * POST /contacts/{contactId}/tags - */ - async addContactTags(contactId, tags) { - try { - const payload = { tags }; - const response = await this.axiosInstance.post(`/contacts/${contactId}/tags`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Remove tags from contact - * DELETE /contacts/{contactId}/tags - */ - async removeContactTags(contactId, tags) { - try { - const payload = { tags }; - const response = await this.axiosInstance.delete(`/contacts/${contactId}/tags`, { data: payload }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * CONVERSATIONS API METHODS - */ - /** - * Search conversations with filters - * GET /conversations/search - */ - async searchConversations(searchParams) { - try { - // Ensure locationId is set - const params = { - ...searchParams, - locationId: searchParams.locationId || this.config.locationId - }; - const response = await this.axiosInstance.get('/conversations/search', { - params, - headers: this.getConversationHeaders() - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get conversation by ID - * GET /conversations/{conversationId} - */ - async getConversation(conversationId) { - try { - const response = await this.axiosInstance.get(`/conversations/${conversationId}`, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create a new conversation - * POST /conversations/ - */ - async createConversation(conversationData) { - try { - // Ensure locationId is set - const payload = { - ...conversationData, - locationId: conversationData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/conversations/', payload, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data.conversation); - } - catch (error) { - throw error; - } - } - /** - * Update conversation - * PUT /conversations/{conversationId} - */ - async updateConversation(conversationId, updates) { - try { - // Ensure locationId is set - const payload = { - ...updates, - locationId: updates.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/conversations/${conversationId}`, payload, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data.conversation); - } - catch (error) { - throw error; - } - } - /** - * Delete conversation - * DELETE /conversations/{conversationId} - */ - async deleteConversation(conversationId) { - try { - const response = await this.axiosInstance.delete(`/conversations/${conversationId}`, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get messages from a conversation - * GET /conversations/{conversationId}/messages - */ - async getConversationMessages(conversationId, options) { - try { - const params = {}; - if (options?.lastMessageId) - params.lastMessageId = options.lastMessageId; - if (options?.limit) - params.limit = options.limit; - if (options?.type) - params.type = options.type; - const response = await this.axiosInstance.get(`/conversations/${conversationId}/messages`, { - params, - headers: this.getConversationHeaders() - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get message by ID - * GET /conversations/messages/{id} - */ - async getMessage(messageId) { - try { - const response = await this.axiosInstance.get(`/conversations/messages/${messageId}`, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Send a new message (SMS, Email, etc.) - * POST /conversations/messages - */ - async sendMessage(messageData) { - try { - const response = await this.axiosInstance.post('/conversations/messages', messageData, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Send SMS message to a contact - * Convenience method for sending SMS - */ - async sendSMS(contactId, message, fromNumber) { - try { - const messageData = { - type: 'SMS', - contactId, - message, - fromNumber - }; - return await this.sendMessage(messageData); - } - catch (error) { - throw error; - } - } - /** - * Send Email message to a contact - * Convenience method for sending Email - */ - async sendEmail(contactId, subject, message, html, options) { - try { - const messageData = { - type: 'Email', - contactId, - subject, - message, - html, - ...options - }; - return await this.sendMessage(messageData); - } - catch (error) { - throw error; - } - } - /** - * BLOG API METHODS - */ - /** - * Get all blog sites for a location - * GET /blogs/site/all - */ - async getBlogSites(params) { - try { - // Ensure locationId is set - const queryParams = { - locationId: params.locationId || this.config.locationId, - skip: params.skip, - limit: params.limit, - ...(params.searchTerm && { searchTerm: params.searchTerm }) - }; - const response = await this.axiosInstance.get('/blogs/site/all', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get blog posts for a specific blog - * GET /blogs/posts/all - */ - async getBlogPosts(params) { - try { - // Ensure locationId is set - const queryParams = { - locationId: params.locationId || this.config.locationId, - blogId: params.blogId, - limit: params.limit, - offset: params.offset, - ...(params.searchTerm && { searchTerm: params.searchTerm }), - ...(params.status && { status: params.status }) - }; - const response = await this.axiosInstance.get('/blogs/posts/all', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create a new blog post - * POST /blogs/posts - */ - async createBlogPost(postData) { - try { - // Ensure locationId is set - const payload = { - ...postData, - locationId: postData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/blogs/posts', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update an existing blog post - * PUT /blogs/posts/{postId} - */ - async updateBlogPost(postId, postData) { - try { - // Ensure locationId is set - const payload = { - ...postData, - locationId: postData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/blogs/posts/${postId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get all blog authors for a location - * GET /blogs/authors - */ - async getBlogAuthors(params) { - try { - // Ensure locationId is set - const queryParams = { - locationId: params.locationId || this.config.locationId, - limit: params.limit, - offset: params.offset - }; - const response = await this.axiosInstance.get('/blogs/authors', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get all blog categories for a location - * GET /blogs/categories - */ - async getBlogCategories(params) { - try { - // Ensure locationId is set - const queryParams = { - locationId: params.locationId || this.config.locationId, - limit: params.limit, - offset: params.offset - }; - const response = await this.axiosInstance.get('/blogs/categories', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Check if a URL slug exists (for validation before creating/updating posts) - * GET /blogs/posts/url-slug-exists - */ - async checkUrlSlugExists(params) { - try { - // Ensure locationId is set - const queryParams = { - locationId: params.locationId || this.config.locationId, - urlSlug: params.urlSlug, - ...(params.postId && { postId: params.postId }) - }; - const response = await this.axiosInstance.get('/blogs/posts/url-slug-exists', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * TASKS API METHODS - */ - /** - * Get all tasks for a contact - * GET /contacts/{contactId}/tasks - */ - async getContactTasks(contactId) { - try { - const response = await this.axiosInstance.get(`/contacts/${contactId}/tasks`); - return this.wrapResponse(response.data.tasks); - } - catch (error) { - throw error; - } - } - /** - * Create task for contact - * POST /contacts/{contactId}/tasks - */ - async createContactTask(contactId, taskData) { - try { - const response = await this.axiosInstance.post(`/contacts/${contactId}/tasks`, taskData); - return this.wrapResponse(response.data.task); - } - catch (error) { - throw error; - } - } - /** - * NOTES API METHODS - */ - /** - * Get all notes for a contact - * GET /contacts/{contactId}/notes - */ - async getContactNotes(contactId) { - try { - const response = await this.axiosInstance.get(`/contacts/${contactId}/notes`); - return this.wrapResponse(response.data.notes); - } - catch (error) { - throw error; - } - } - /** - * Create note for contact - * POST /contacts/{contactId}/notes - */ - async createContactNote(contactId, noteData) { - try { - const response = await this.axiosInstance.post(`/contacts/${contactId}/notes`, noteData); - return this.wrapResponse(response.data.note); - } - catch (error) { - throw error; - } - } - /** - * ADDITIONAL CONTACT API METHODS - */ - /** - * Get a specific task for a contact - * GET /contacts/{contactId}/tasks/{taskId} - */ - async getContactTask(contactId, taskId) { - try { - const response = await this.axiosInstance.get(`/contacts/${contactId}/tasks/${taskId}`); - return this.wrapResponse(response.data.task); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update a task for a contact - * PUT /contacts/{contactId}/tasks/{taskId} - */ - async updateContactTask(contactId, taskId, updates) { - try { - const response = await this.axiosInstance.put(`/contacts/${contactId}/tasks/${taskId}`, updates); - return this.wrapResponse(response.data.task); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete a task for a contact - * DELETE /contacts/{contactId}/tasks/{taskId} - */ - async deleteContactTask(contactId, taskId) { - try { - const response = await this.axiosInstance.delete(`/contacts/${contactId}/tasks/${taskId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update task completion status - * PUT /contacts/{contactId}/tasks/{taskId}/completed - */ - async updateTaskCompletion(contactId, taskId, completed) { - try { - const response = await this.axiosInstance.put(`/contacts/${contactId}/tasks/${taskId}/completed`, { completed }); - return this.wrapResponse(response.data.task); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get a specific note for a contact - * GET /contacts/{contactId}/notes/{noteId} - */ - async getContactNote(contactId, noteId) { - try { - const response = await this.axiosInstance.get(`/contacts/${contactId}/notes/${noteId}`); - return this.wrapResponse(response.data.note); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update a note for a contact - * PUT /contacts/{contactId}/notes/{noteId} - */ - async updateContactNote(contactId, noteId, updates) { - try { - const response = await this.axiosInstance.put(`/contacts/${contactId}/notes/${noteId}`, updates); - return this.wrapResponse(response.data.note); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete a note for a contact - * DELETE /contacts/{contactId}/notes/{noteId} - */ - async deleteContactNote(contactId, noteId) { - try { - const response = await this.axiosInstance.delete(`/contacts/${contactId}/notes/${noteId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Upsert contact (create or update based on email/phone) - * POST /contacts/upsert - */ - async upsertContact(contactData) { - try { - const payload = { - ...contactData, - locationId: contactData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/contacts/upsert', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get contacts by business ID - * GET /contacts/business/{businessId} - */ - async getContactsByBusiness(businessId, params = {}) { - try { - const queryParams = { - limit: params.limit || 25, - skip: params.skip || 0, - ...(params.query && { query: params.query }) - }; - const response = await this.axiosInstance.get(`/contacts/business/${businessId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get contact appointments - * GET /contacts/{contactId}/appointments - */ - async getContactAppointments(contactId) { - try { - const response = await this.axiosInstance.get(`/contacts/${contactId}/appointments`); - return this.wrapResponse(response.data.events); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Bulk update contact tags - * POST /contacts/tags/bulk - */ - async bulkUpdateContactTags(contactIds, tags, operation, removeAllTags) { - try { - const payload = { - ids: contactIds, - tags, - operation, - ...(removeAllTags !== undefined && { removeAllTags }) - }; - const response = await this.axiosInstance.post('/contacts/tags/bulk', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Bulk update contact business - * POST /contacts/business/bulk - */ - async bulkUpdateContactBusiness(contactIds, businessId) { - try { - const payload = { - ids: contactIds, - businessId: businessId || null - }; - const response = await this.axiosInstance.post('/contacts/business/bulk', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Add contact followers - * POST /contacts/{contactId}/followers - */ - async addContactFollowers(contactId, followers) { - try { - const payload = { followers }; - const response = await this.axiosInstance.post(`/contacts/${contactId}/followers`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Remove contact followers - * DELETE /contacts/{contactId}/followers - */ - async removeContactFollowers(contactId, followers) { - try { - const payload = { followers }; - const response = await this.axiosInstance.delete(`/contacts/${contactId}/followers`, { data: payload }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Add contact to campaign - * POST /contacts/{contactId}/campaigns/{campaignId} - */ - async addContactToCampaign(contactId, campaignId) { - try { - const response = await this.axiosInstance.post(`/contacts/${contactId}/campaigns/${campaignId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Remove contact from campaign - * DELETE /contacts/{contactId}/campaigns/{campaignId} - */ - async removeContactFromCampaign(contactId, campaignId) { - try { - const response = await this.axiosInstance.delete(`/contacts/${contactId}/campaigns/${campaignId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Remove contact from all campaigns - * DELETE /contacts/{contactId}/campaigns - */ - async removeContactFromAllCampaigns(contactId) { - try { - const response = await this.axiosInstance.delete(`/contacts/${contactId}/campaigns`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Add contact to workflow - * POST /contacts/{contactId}/workflow/{workflowId} - */ - async addContactToWorkflow(contactId, workflowId, eventStartTime) { - try { - const payload = eventStartTime ? { eventStartTime } : {}; - const response = await this.axiosInstance.post(`/contacts/${contactId}/workflow/${workflowId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Remove contact from workflow - * DELETE /contacts/{contactId}/workflow/{workflowId} - */ - async removeContactFromWorkflow(contactId, workflowId, eventStartTime) { - try { - const payload = eventStartTime ? { eventStartTime } : {}; - const response = await this.axiosInstance.delete(`/contacts/${contactId}/workflow/${workflowId}`, { data: payload }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * UTILITY METHODS - */ - /** - * Test API connection and authentication - */ - async testConnection() { - try { - // Test with a simple GET request to check API connectivity - const response = await this.axiosInstance.get('/locations/' + this.config.locationId); - return this.wrapResponse({ - status: 'connected', - locationId: this.config.locationId - }); - } - catch (error) { - throw new Error(`GHL API connection test failed: ${error}`); - } - } - /** - * Update access token - */ - updateAccessToken(newToken) { - this.config.accessToken = newToken; - this.axiosInstance.defaults.headers['Authorization'] = `Bearer ${newToken}`; - process.stderr.write('[GHL API] Access token updated\n'); - } - /** - * Get current configuration - */ - getConfig() { - return { ...this.config }; - } - /** - * Generic request method for new endpoints - * Used by new tool modules that don't have specific client methods yet - */ - async makeRequest(method, path, body) { - try { - let response; - switch (method) { - case 'GET': - response = await this.axiosInstance.get(path); - break; - case 'POST': - response = await this.axiosInstance.post(path, body); - break; - case 'PUT': - response = await this.axiosInstance.put(path, body); - break; - case 'PATCH': - response = await this.axiosInstance.patch(path, body); - break; - case 'DELETE': - response = await this.axiosInstance.delete(path); - break; - } - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * OPPORTUNITIES API METHODS - */ - /** - * Search opportunities with advanced filters - * GET /opportunities/search - */ - async searchOpportunities(searchParams) { - try { - // Build query parameters with exact API naming (underscores) - const params = { - location_id: searchParams.location_id || this.config.locationId - }; - // Add optional search parameters only if they have values - if (searchParams.q && searchParams.q.trim()) { - params.q = searchParams.q.trim(); - } - if (searchParams.pipeline_id) { - params.pipeline_id = searchParams.pipeline_id; - } - if (searchParams.pipeline_stage_id) { - params.pipeline_stage_id = searchParams.pipeline_stage_id; - } - if (searchParams.contact_id) { - params.contact_id = searchParams.contact_id; - } - if (searchParams.status) { - params.status = searchParams.status; - } - if (searchParams.assigned_to) { - params.assigned_to = searchParams.assigned_to; - } - if (searchParams.campaignId) { - params.campaignId = searchParams.campaignId; - } - if (searchParams.id) { - params.id = searchParams.id; - } - if (searchParams.order) { - params.order = searchParams.order; - } - if (searchParams.endDate) { - params.endDate = searchParams.endDate; - } - if (searchParams.startAfter) { - params.startAfter = searchParams.startAfter; - } - if (searchParams.startAfterId) { - params.startAfterId = searchParams.startAfterId; - } - if (searchParams.date) { - params.date = searchParams.date; - } - if (searchParams.country) { - params.country = searchParams.country; - } - if (searchParams.page) { - params.page = searchParams.page; - } - if (searchParams.limit) { - params.limit = searchParams.limit; - } - if (searchParams.getTasks !== undefined) { - params.getTasks = searchParams.getTasks; - } - if (searchParams.getNotes !== undefined) { - params.getNotes = searchParams.getNotes; - } - if (searchParams.getCalendarEvents !== undefined) { - params.getCalendarEvents = searchParams.getCalendarEvents; - } - process.stderr.write(`[GHL API] Search opportunities params: ${JSON.stringify(params, null, 2)}\n`); - const response = await this.axiosInstance.get('/opportunities/search', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - const axiosError = error; - process.stderr.write(`[GHL API] Search opportunities error: ${JSON.stringify({ - status: axiosError.response?.status, - statusText: axiosError.response?.statusText, - data: axiosError.response?.data, - message: axiosError.message - }, null, 2)}\n`); - throw this.handleApiError(axiosError); - } - } - /** - * Get all pipelines for a location - * GET /opportunities/pipelines - */ - async getPipelines(locationId) { - try { - const params = { - locationId: locationId || this.config.locationId - }; - const response = await this.axiosInstance.get('/opportunities/pipelines', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get opportunity by ID - * GET /opportunities/{id} - */ - async getOpportunity(opportunityId) { - try { - const response = await this.axiosInstance.get(`/opportunities/${opportunityId}`); - return this.wrapResponse(response.data.opportunity); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create a new opportunity - * POST /opportunities/ - */ - async createOpportunity(opportunityData) { - try { - // Ensure locationId is set - const payload = { - ...opportunityData, - locationId: opportunityData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/opportunities/', payload); - return this.wrapResponse(response.data.opportunity); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update existing opportunity - * PUT /opportunities/{id} - */ - async updateOpportunity(opportunityId, updates) { - try { - const response = await this.axiosInstance.put(`/opportunities/${opportunityId}`, updates); - return this.wrapResponse(response.data.opportunity); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update opportunity status - * PUT /opportunities/{id}/status - */ - async updateOpportunityStatus(opportunityId, status) { - try { - const payload = { status }; - const response = await this.axiosInstance.put(`/opportunities/${opportunityId}/status`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Upsert opportunity (create or update) - * POST /opportunities/upsert - */ - async upsertOpportunity(opportunityData) { - try { - // Ensure locationId is set - const payload = { - ...opportunityData, - locationId: opportunityData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/opportunities/upsert', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete opportunity - * DELETE /opportunities/{id} - */ - async deleteOpportunity(opportunityId) { - try { - const response = await this.axiosInstance.delete(`/opportunities/${opportunityId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Add followers to opportunity - * POST /opportunities/{id}/followers - */ - async addOpportunityFollowers(opportunityId, followers) { - try { - const payload = { followers }; - const response = await this.axiosInstance.post(`/opportunities/${opportunityId}/followers`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Remove followers from opportunity - * DELETE /opportunities/{id}/followers - */ - async removeOpportunityFollowers(opportunityId, followers) { - try { - const payload = { followers }; - const response = await this.axiosInstance.delete(`/opportunities/${opportunityId}/followers`, { data: payload }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * CALENDAR & APPOINTMENTS API METHODS - */ - /** - * Get all calendar groups in a location - * GET /calendars/groups - */ - async getCalendarGroups(locationId) { - try { - const params = { - locationId: locationId || this.config.locationId - }; - const response = await this.axiosInstance.get('/calendars/groups', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create a new calendar group - * POST /calendars/groups - */ - async createCalendarGroup(groupData) { - try { - const payload = { - ...groupData, - locationId: groupData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/calendars/groups', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get all calendars in a location - * GET /calendars/ - */ - async getCalendars(params) { - try { - const queryParams = { - locationId: params?.locationId || this.config.locationId, - ...(params?.groupId && { groupId: params.groupId }), - ...(params?.showDrafted !== undefined && { showDrafted: params.showDrafted }) - }; - const response = await this.axiosInstance.get('/calendars/', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create a new calendar - * POST /calendars/ - */ - async createCalendar(calendarData) { - try { - const payload = { - ...calendarData, - locationId: calendarData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/calendars/', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get calendar by ID - * GET /calendars/{calendarId} - */ - async getCalendar(calendarId) { - try { - const response = await this.axiosInstance.get(`/calendars/${calendarId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update calendar by ID - * PUT /calendars/{calendarId} - */ - async updateCalendar(calendarId, updates) { - try { - const response = await this.axiosInstance.put(`/calendars/${calendarId}`, updates); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete calendar by ID - * DELETE /calendars/{calendarId} - */ - async deleteCalendar(calendarId) { - try { - const response = await this.axiosInstance.delete(`/calendars/${calendarId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get calendar events/appointments - * GET /calendars/events - */ - async getCalendarEvents(eventParams) { - try { - const params = { - locationId: eventParams.locationId || this.config.locationId, - startTime: eventParams.startTime, - endTime: eventParams.endTime, - ...(eventParams.userId && { userId: eventParams.userId }), - ...(eventParams.calendarId && { calendarId: eventParams.calendarId }), - ...(eventParams.groupId && { groupId: eventParams.groupId }) - }; - const response = await this.axiosInstance.get('/calendars/events', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get blocked slots - * GET /calendars/blocked-slots - */ - async getBlockedSlots(eventParams) { - try { - const params = { - locationId: eventParams.locationId || this.config.locationId, - startTime: eventParams.startTime, - endTime: eventParams.endTime, - ...(eventParams.userId && { userId: eventParams.userId }), - ...(eventParams.calendarId && { calendarId: eventParams.calendarId }), - ...(eventParams.groupId && { groupId: eventParams.groupId }) - }; - const response = await this.axiosInstance.get('/calendars/blocked-slots', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get free slots for a calendar - * GET /calendars/{calendarId}/free-slots - */ - async getFreeSlots(slotParams) { - try { - const params = { - startDate: slotParams.startDate, - endDate: slotParams.endDate, - ...(slotParams.timezone && { timezone: slotParams.timezone }), - ...(slotParams.userId && { userId: slotParams.userId }), - ...(slotParams.userIds && { userIds: slotParams.userIds }), - ...(slotParams.enableLookBusy !== undefined && { enableLookBusy: slotParams.enableLookBusy }) - }; - const response = await this.axiosInstance.get(`/calendars/${slotParams.calendarId}/free-slots`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create a new appointment - * POST /calendars/events/appointments - */ - async createAppointment(appointmentData) { - try { - const payload = { - ...appointmentData, - locationId: appointmentData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/calendars/events/appointments', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get appointment by ID - * GET /calendars/events/appointments/{eventId} - */ - async getAppointment(appointmentId) { - try { - const response = await this.axiosInstance.get(`/calendars/events/appointments/${appointmentId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update appointment by ID - * PUT /calendars/events/appointments/{eventId} - */ - async updateAppointment(appointmentId, updates) { - try { - const response = await this.axiosInstance.put(`/calendars/events/appointments/${appointmentId}`, updates); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete appointment by ID - * DELETE /calendars/events/appointments/{eventId} - */ - async deleteAppointment(appointmentId) { - try { - const response = await this.axiosInstance.delete(`/calendars/events/appointments/${appointmentId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update block slot by ID - * PUT /calendars/events/block-slots/{eventId} - */ - async updateBlockSlot(blockSlotId, updates) { - try { - const response = await this.axiosInstance.put(`/calendars/events/block-slots/${blockSlotId}`, updates); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * EMAIL API METHODS - */ - async getEmailCampaigns(params) { - try { - const response = await this.axiosInstance.get('/emails/schedule', { - params: { - locationId: this.config.locationId, - ...params - } - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - async createEmailTemplate(params) { - try { - const response = await this.axiosInstance.post('/emails/builder', { - locationId: this.config.locationId, - type: 'html', - ...params - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - async getEmailTemplates(params) { - try { - const response = await this.axiosInstance.get('/emails/builder', { - params: { - locationId: this.config.locationId, - ...params - } - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - async updateEmailTemplate(params) { - try { - const { templateId, ...data } = params; - const response = await this.axiosInstance.post('/emails/builder/data', { - locationId: this.config.locationId, - templateId, - ...data, - editorType: 'html' - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - async deleteEmailTemplate(params) { - try { - const { templateId } = params; - const response = await this.axiosInstance.delete(`/emails/builder/${this.config.locationId}/${templateId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * LOCATION API METHODS - */ - /** - * Search locations/sub-accounts - * GET /locations/search - */ - async searchLocations(params = {}) { - try { - const queryParams = { - skip: params.skip || 0, - limit: params.limit || 10, - order: params.order || 'asc', - ...(params.companyId && { companyId: params.companyId }), - ...(params.email && { email: params.email }) - }; - const response = await this.axiosInstance.get('/locations/search', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get location by ID - * GET /locations/{locationId} - */ - async getLocationById(locationId) { - try { - const response = await this.axiosInstance.get(`/locations/${locationId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create a new location/sub-account - * POST /locations/ - */ - async createLocation(locationData) { - try { - const response = await this.axiosInstance.post('/locations/', locationData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update location/sub-account - * PUT /locations/{locationId} - */ - async updateLocation(locationId, updates) { - try { - const response = await this.axiosInstance.put(`/locations/${locationId}`, updates); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete location/sub-account - * DELETE /locations/{locationId} - */ - async deleteLocation(locationId, deleteTwilioAccount) { - try { - const response = await this.axiosInstance.delete(`/locations/${locationId}`, { - params: { deleteTwilioAccount } - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * LOCATION TAGS API METHODS - */ - /** - * Get location tags - * GET /locations/{locationId}/tags - */ - async getLocationTags(locationId) { - try { - const response = await this.axiosInstance.get(`/locations/${locationId}/tags`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create location tag - * POST /locations/{locationId}/tags - */ - async createLocationTag(locationId, tagData) { - try { - const response = await this.axiosInstance.post(`/locations/${locationId}/tags`, tagData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get location tag by ID - * GET /locations/{locationId}/tags/{tagId} - */ - async getLocationTag(locationId, tagId) { - try { - const response = await this.axiosInstance.get(`/locations/${locationId}/tags/${tagId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update location tag - * PUT /locations/{locationId}/tags/{tagId} - */ - async updateLocationTag(locationId, tagId, tagData) { - try { - const response = await this.axiosInstance.put(`/locations/${locationId}/tags/${tagId}`, tagData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete location tag - * DELETE /locations/{locationId}/tags/{tagId} - */ - async deleteLocationTag(locationId, tagId) { - try { - const response = await this.axiosInstance.delete(`/locations/${locationId}/tags/${tagId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * LOCATION TASKS API METHODS - */ - /** - * Search location tasks - * POST /locations/{locationId}/tasks/search - */ - async searchLocationTasks(locationId, searchParams) { - try { - const response = await this.axiosInstance.post(`/locations/${locationId}/tasks/search`, searchParams); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * CUSTOM FIELDS API METHODS - */ - /** - * Get custom fields for location - * GET /locations/{locationId}/customFields - */ - async getLocationCustomFields(locationId, model) { - try { - const params = {}; - if (model) - params.model = model; - const response = await this.axiosInstance.get(`/locations/${locationId}/customFields`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create custom field for location - * POST /locations/{locationId}/customFields - */ - async createLocationCustomField(locationId, fieldData) { - try { - const response = await this.axiosInstance.post(`/locations/${locationId}/customFields`, fieldData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get custom field by ID - * GET /locations/{locationId}/customFields/{id} - */ - async getLocationCustomField(locationId, customFieldId) { - try { - const response = await this.axiosInstance.get(`/locations/${locationId}/customFields/${customFieldId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update custom field - * PUT /locations/{locationId}/customFields/{id} - */ - async updateLocationCustomField(locationId, customFieldId, fieldData) { - try { - const response = await this.axiosInstance.put(`/locations/${locationId}/customFields/${customFieldId}`, fieldData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete custom field - * DELETE /locations/{locationId}/customFields/{id} - */ - async deleteLocationCustomField(locationId, customFieldId) { - try { - const response = await this.axiosInstance.delete(`/locations/${locationId}/customFields/${customFieldId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Upload file to custom fields - * POST /locations/{locationId}/customFields/upload - */ - async uploadLocationCustomFieldFile(locationId, uploadData) { - try { - // Note: This endpoint expects multipart/form-data but we'll handle it as JSON for now - // In a real implementation, you'd use FormData for file uploads - const response = await this.axiosInstance.post(`/locations/${locationId}/customFields/upload`, uploadData, { headers: { 'Content-Type': 'multipart/form-data' } }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * CUSTOM VALUES API METHODS - */ - /** - * Get custom values for location - * GET /locations/{locationId}/customValues - */ - async getLocationCustomValues(locationId) { - try { - const response = await this.axiosInstance.get(`/locations/${locationId}/customValues`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create custom value for location - * POST /locations/{locationId}/customValues - */ - async createLocationCustomValue(locationId, valueData) { - try { - const response = await this.axiosInstance.post(`/locations/${locationId}/customValues`, valueData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get custom value by ID - * GET /locations/{locationId}/customValues/{id} - */ - async getLocationCustomValue(locationId, customValueId) { - try { - const response = await this.axiosInstance.get(`/locations/${locationId}/customValues/${customValueId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update custom value - * PUT /locations/{locationId}/customValues/{id} - */ - async updateLocationCustomValue(locationId, customValueId, valueData) { - try { - const response = await this.axiosInstance.put(`/locations/${locationId}/customValues/${customValueId}`, valueData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete custom value - * DELETE /locations/{locationId}/customValues/{id} - */ - async deleteLocationCustomValue(locationId, customValueId) { - try { - const response = await this.axiosInstance.delete(`/locations/${locationId}/customValues/${customValueId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * TEMPLATES API METHODS - */ - /** - * Get location templates (SMS/Email) - * GET /locations/{locationId}/templates - */ - async getLocationTemplates(locationId, params) { - try { - const queryParams = { - originId: params.originId, - deleted: params.deleted || false, - skip: params.skip || 0, - limit: params.limit || 25, - ...(params.type && { type: params.type }) - }; - const response = await this.axiosInstance.get(`/locations/${locationId}/templates`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete location template - * DELETE /locations/{locationId}/templates/{id} - */ - async deleteLocationTemplate(locationId, templateId) { - try { - const response = await this.axiosInstance.delete(`/locations/${locationId}/templates/${templateId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * TIMEZONES API METHODS - */ - /** - * Get available timezones - * GET /locations/{locationId}/timezones - */ - async getTimezones(locationId) { - try { - const endpoint = locationId ? `/locations/${locationId}/timezones` : '/locations/timezones'; - const response = await this.axiosInstance.get(endpoint); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * EMAIL ISV (VERIFICATION) API METHODS - */ - /** - * Verify email address or contact - * POST /email/verify - */ - async verifyEmail(locationId, verificationData) { - try { - const params = { - locationId: locationId - }; - const response = await this.axiosInstance.post('/email/verify', verificationData, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * ADDITIONAL CONVERSATION/MESSAGE API METHODS - */ - /** - * Get email message by ID - * GET /conversations/messages/email/{id} - */ - async getEmailMessage(emailMessageId) { - try { - const response = await this.axiosInstance.get(`/conversations/messages/email/${emailMessageId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Cancel scheduled email message - * DELETE /conversations/messages/email/{emailMessageId}/schedule - */ - async cancelScheduledEmail(emailMessageId) { - try { - const response = await this.axiosInstance.delete(`/conversations/messages/email/${emailMessageId}/schedule`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Add inbound message manually - * POST /conversations/messages/inbound - */ - async addInboundMessage(messageData) { - try { - const response = await this.axiosInstance.post('/conversations/messages/inbound', messageData, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Add outbound call manually - * POST /conversations/messages/outbound - */ - async addOutboundCall(messageData) { - try { - const response = await this.axiosInstance.post('/conversations/messages/outbound', messageData, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Cancel scheduled message - * DELETE /conversations/messages/{messageId}/schedule - */ - async cancelScheduledMessage(messageId) { - try { - const response = await this.axiosInstance.delete(`/conversations/messages/${messageId}/schedule`, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Upload file attachments for messages - * POST /conversations/messages/upload - */ - async uploadMessageAttachments(uploadData) { - try { - const response = await this.axiosInstance.post('/conversations/messages/upload', uploadData, { - headers: { - ...this.getConversationHeaders(), - 'Content-Type': 'multipart/form-data' - } - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update message status - * PUT /conversations/messages/{messageId}/status - */ - async updateMessageStatus(messageId, statusData) { - try { - const response = await this.axiosInstance.put(`/conversations/messages/${messageId}/status`, statusData, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get message recording - * GET /conversations/messages/{messageId}/locations/{locationId}/recording - */ - async getMessageRecording(messageId, locationId) { - try { - const locId = locationId || this.config.locationId; - const response = await this.axiosInstance.get(`/conversations/messages/${messageId}/locations/${locId}/recording`, { - headers: this.getConversationHeaders(), - responseType: 'arraybuffer' - }); - const recordingResponse = { - audioData: response.data, - contentType: response.headers['content-type'] || 'audio/x-wav', - contentDisposition: response.headers['content-disposition'] || 'attachment; filename=audio.wav' - }; - return this.wrapResponse(recordingResponse); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get message transcription - * GET /conversations/locations/{locationId}/messages/{messageId}/transcription - */ - async getMessageTranscription(messageId, locationId) { - try { - const locId = locationId || this.config.locationId; - const response = await this.axiosInstance.get(`/conversations/locations/${locId}/messages/${messageId}/transcription`, { headers: this.getConversationHeaders() }); - return this.wrapResponse({ transcriptions: response.data }); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Download message transcription - * GET /conversations/locations/{locationId}/messages/{messageId}/transcription/download - */ - async downloadMessageTranscription(messageId, locationId) { - try { - const locId = locationId || this.config.locationId; - const response = await this.axiosInstance.get(`/conversations/locations/${locId}/messages/${messageId}/transcription/download`, { - headers: this.getConversationHeaders(), - responseType: 'text' - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Live chat typing indicator - * POST /conversations/providers/live-chat/typing - */ - async liveChatTyping(typingData) { - try { - const response = await this.axiosInstance.post('/conversations/providers/live-chat/typing', typingData, { headers: this.getConversationHeaders() }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ============================================================================ - // SOCIAL MEDIA POSTING API METHODS - // ============================================================================ - // ===== POST MANAGEMENT ===== - /** - * Search/List Social Media Posts - */ - async searchSocialPosts(searchData) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.post(`/social-media-posting/${locationId}/posts/list`, searchData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create Social Media Post - */ - async createSocialPost(postData) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.post(`/social-media-posting/${locationId}/posts`, postData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get Social Media Post by ID - */ - async getSocialPost(postId) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.get(`/social-media-posting/${locationId}/posts/${postId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update Social Media Post - */ - async updateSocialPost(postId, updateData) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.put(`/social-media-posting/${locationId}/posts/${postId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete Social Media Post - */ - async deleteSocialPost(postId) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.delete(`/social-media-posting/${locationId}/posts/${postId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Bulk Delete Social Media Posts - */ - async bulkDeleteSocialPosts(deleteData) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.post(`/social-media-posting/${locationId}/posts/bulk-delete`, deleteData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - // ===== ACCOUNT MANAGEMENT ===== - /** - * Get Social Media Accounts and Groups - */ - async getSocialAccounts() { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.get(`/social-media-posting/${locationId}/accounts`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete Social Media Account - */ - async deleteSocialAccount(accountId, companyId, userId) { - try { - const locationId = this.config.locationId; - const params = {}; - if (companyId) - params.companyId = companyId; - if (userId) - params.userId = userId; - const response = await this.axiosInstance.delete(`/social-media-posting/${locationId}/accounts/${accountId}`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - // ===== CSV OPERATIONS ===== - /** - * Upload CSV for Social Media Posts - */ - async uploadSocialCSV(csvData) { - try { - const locationId = this.config.locationId; - // Note: This would typically use FormData for file upload - const response = await this.axiosInstance.post(`/social-media-posting/${locationId}/csv`, csvData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get CSV Upload Status - */ - async getSocialCSVUploadStatus(skip, limit, includeUsers, userId) { - try { - const locationId = this.config.locationId; - const params = {}; - if (skip !== undefined) - params.skip = skip.toString(); - if (limit !== undefined) - params.limit = limit.toString(); - if (includeUsers !== undefined) - params.includeUsers = includeUsers.toString(); - if (userId) - params.userId = userId; - const response = await this.axiosInstance.get(`/social-media-posting/${locationId}/csv`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Set Accounts for CSV Import - */ - async setSocialCSVAccounts(accountsData) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.post(`/social-media-posting/${locationId}/set-accounts`, accountsData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get CSV Posts - */ - async getSocialCSVPosts(csvId, skip, limit) { - try { - const locationId = this.config.locationId; - const params = {}; - if (skip !== undefined) - params.skip = skip.toString(); - if (limit !== undefined) - params.limit = limit.toString(); - const response = await this.axiosInstance.get(`/social-media-posting/${locationId}/csv/${csvId}`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Start CSV Finalization - */ - async finalizeSocialCSV(csvId, finalizeData) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.patch(`/social-media-posting/${locationId}/csv/${csvId}`, finalizeData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete CSV Import - */ - async deleteSocialCSV(csvId) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.delete(`/social-media-posting/${locationId}/csv/${csvId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete CSV Post - */ - async deleteSocialCSVPost(csvId, postId) { - try { - const locationId = this.config.locationId; - const response = await this.axiosInstance.delete(`/social-media-posting/${locationId}/csv/${csvId}/post/${postId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - // ===== CATEGORIES & TAGS ===== - /** - * Get Social Media Categories - */ - async getSocialCategories(searchText, limit, skip) { - // TODO: Implement this method properly - throw new Error('Method not yet implemented'); - } - // TODO: Implement remaining social media API methods - async getSocialCategory(categoryId) { - throw new Error('Method not yet implemented'); - } - async getSocialTags(searchText, limit, skip) { - throw new Error('Method not yet implemented'); - } - async getSocialTagsByIds(tagData) { - throw new Error('Method not yet implemented'); - } - async startSocialOAuth(platform, userId, page, reconnect) { - throw new Error('Method not yet implemented'); - } - async getGoogleBusinessLocations(accountId) { - throw new Error('Method not yet implemented'); - } - async setGoogleBusinessLocations(accountId, locationData) { - throw new Error('Method not yet implemented'); - } - async getFacebookPages(accountId) { - throw new Error('Method not yet implemented'); - } - async attachFacebookPages(accountId, pageData) { - throw new Error('Method not yet implemented'); - } - async getInstagramAccounts(accountId) { - throw new Error('Method not yet implemented'); - } - async attachInstagramAccounts(accountId, accountData) { - throw new Error('Method not yet implemented'); - } - async getLinkedInAccounts(accountId) { - throw new Error('Method not yet implemented'); - } - async attachLinkedInAccounts(accountId, accountData) { - throw new Error('Method not yet implemented'); - } - async getTwitterProfile(accountId) { - throw new Error('Method not yet implemented'); - } - async attachTwitterProfile(accountId, profileData) { - throw new Error('Method not yet implemented'); - } - async getTikTokProfile(accountId) { - throw new Error('Method not yet implemented'); - } - async attachTikTokProfile(accountId, profileData) { - throw new Error('Method not yet implemented'); - } - async getTikTokBusinessProfile(accountId) { - throw new Error('Method not yet implemented'); - } - // ===== MISSING CALENDAR GROUPS MANAGEMENT METHODS ===== - /** - * Validate calendar group slug - * GET /calendars/groups/slug/validate - */ - async validateCalendarGroupSlug(slug, locationId) { - try { - const params = { - locationId: locationId || this.config.locationId, - slug - }; - const response = await this.axiosInstance.get('/calendars/groups/slug/validate', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update calendar group by ID - * PUT /calendars/groups/{groupId} - */ - async updateCalendarGroup(groupId, updateData) { - try { - const response = await this.axiosInstance.put(`/calendars/groups/${groupId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete calendar group by ID - * DELETE /calendars/groups/{groupId} - */ - async deleteCalendarGroup(groupId) { - try { - const response = await this.axiosInstance.delete(`/calendars/groups/${groupId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Disable calendar group - * POST /calendars/groups/{groupId}/status - */ - async disableCalendarGroup(groupId, isActive) { - try { - const payload = { isActive }; - const response = await this.axiosInstance.post(`/calendars/groups/${groupId}/status`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== APPOINTMENT NOTES METHODS ===== - /** - * Get appointment notes - * GET /calendars/events/appointments/{appointmentId}/notes - */ - async getAppointmentNotes(appointmentId, limit = 10, offset = 0) { - try { - const params = { limit, offset }; - const response = await this.axiosInstance.get(`/calendars/events/appointments/${appointmentId}/notes`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create appointment note - * POST /calendars/events/appointments/{appointmentId}/notes - */ - async createAppointmentNote(appointmentId, noteData) { - try { - const response = await this.axiosInstance.post(`/calendars/events/appointments/${appointmentId}/notes`, noteData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update appointment note - * PUT /calendars/events/appointments/{appointmentId}/notes/{noteId} - */ - async updateAppointmentNote(appointmentId, noteId, updateData) { - try { - const response = await this.axiosInstance.put(`/calendars/events/appointments/${appointmentId}/notes/${noteId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete appointment note - * DELETE /calendars/events/appointments/{appointmentId}/notes/{noteId} - */ - async deleteAppointmentNote(appointmentId, noteId) { - try { - const response = await this.axiosInstance.delete(`/calendars/events/appointments/${appointmentId}/notes/${noteId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== CALENDAR RESOURCES METHODS ===== - /** - * Get calendar resources - * GET /calendars/resources/{resourceType} - */ - async getCalendarResources(resourceType, limit = 20, skip = 0, locationId) { - try { - const params = { - locationId: locationId || this.config.locationId, - limit, - skip - }; - const response = await this.axiosInstance.get(`/calendars/resources/${resourceType}`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create calendar resource - * POST /calendars/resources/{resourceType} - */ - async createCalendarResource(resourceType, resourceData) { - try { - const payload = { - ...resourceData, - locationId: resourceData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post(`/calendars/resources/${resourceType}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get calendar resource by ID - * GET /calendars/resources/{resourceType}/{resourceId} - */ - async getCalendarResource(resourceType, resourceId) { - try { - const response = await this.axiosInstance.get(`/calendars/resources/${resourceType}/${resourceId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update calendar resource - * PUT /calendars/resources/{resourceType}/{resourceId} - */ - async updateCalendarResource(resourceType, resourceId, updateData) { - try { - const response = await this.axiosInstance.put(`/calendars/resources/${resourceType}/${resourceId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete calendar resource - * DELETE /calendars/resources/{resourceType}/{resourceId} - */ - async deleteCalendarResource(resourceType, resourceId) { - try { - const response = await this.axiosInstance.delete(`/calendars/resources/${resourceType}/${resourceId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== CALENDAR NOTIFICATIONS METHODS ===== - /** - * Get calendar notifications - * GET /calendars/{calendarId}/notifications - */ - async getCalendarNotifications(calendarId, queryParams) { - try { - const params = { - ...queryParams - }; - const response = await this.axiosInstance.get(`/calendars/${calendarId}/notifications`, { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create calendar notifications - * POST /calendars/{calendarId}/notifications - */ - async createCalendarNotifications(calendarId, notifications) { - try { - const payload = { notifications }; - const response = await this.axiosInstance.post(`/calendars/${calendarId}/notifications`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get calendar notification by ID - * GET /calendars/{calendarId}/notifications/{notificationId} - */ - async getCalendarNotification(calendarId, notificationId) { - try { - const response = await this.axiosInstance.get(`/calendars/${calendarId}/notifications/${notificationId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update calendar notification - * PUT /calendars/{calendarId}/notifications/{notificationId} - */ - async updateCalendarNotification(calendarId, notificationId, updateData) { - try { - const response = await this.axiosInstance.put(`/calendars/${calendarId}/notifications/${notificationId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete calendar notification - * DELETE /calendars/{calendarId}/notifications/{notificationId} - */ - async deleteCalendarNotification(calendarId, notificationId) { - try { - const response = await this.axiosInstance.delete(`/calendars/${calendarId}/notifications/${notificationId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get blocked slots by location - * GET /calendars/blocked-slots - */ - async getBlockedSlotsByLocation(slotParams) { - try { - const params = new URLSearchParams({ - locationId: slotParams.locationId, - startTime: slotParams.startTime, - endTime: slotParams.endTime, - ...(slotParams.userId && { userId: slotParams.userId }), - ...(slotParams.calendarId && { calendarId: slotParams.calendarId }), - ...(slotParams.groupId && { groupId: slotParams.groupId }) - }); - const response = await this.axiosInstance.get(`/calendars/blocked-slots?${params}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create a new block slot - * POST /calendars/blocked-slots - */ - async createBlockSlot(blockSlotData) { - try { - const payload = { - ...blockSlotData, - locationId: blockSlotData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/calendars/blocked-slots', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== MEDIA LIBRARY API METHODS ===== - /** - * Get list of files and folders from media library - * GET /medias/files - */ - async getMediaFiles(params) { - try { - const queryParams = new URLSearchParams({ - sortBy: params.sortBy, - sortOrder: params.sortOrder, - altType: params.altType, - altId: params.altId, - ...(params.offset !== undefined && { offset: params.offset.toString() }), - ...(params.limit !== undefined && { limit: params.limit.toString() }), - ...(params.type && { type: params.type }), - ...(params.query && { query: params.query }), - ...(params.parentId && { parentId: params.parentId }) - }); - const response = await this.axiosInstance.get(`/medias/files?${queryParams}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Upload file to media library - * POST /medias/upload-file - */ - async uploadMediaFile(uploadData) { - try { - const formData = new FormData(); - // Handle file upload (either direct file or hosted file URL) - if (uploadData.hosted && uploadData.fileUrl) { - formData.append('hosted', 'true'); - formData.append('fileUrl', uploadData.fileUrl); - } - else if (uploadData.file) { - formData.append('hosted', 'false'); - formData.append('file', uploadData.file); - } - else { - throw new Error('Either file or fileUrl (with hosted=true) must be provided'); - } - // Add optional fields - if (uploadData.name) { - formData.append('name', uploadData.name); - } - if (uploadData.parentId) { - formData.append('parentId', uploadData.parentId); - } - const response = await this.axiosInstance.post('/medias/upload-file', formData, { - headers: { - 'Content-Type': 'multipart/form-data', - } - }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete file or folder from media library - * DELETE /medias/{id} - */ - async deleteMediaFile(deleteParams) { - try { - const queryParams = new URLSearchParams({ - altType: deleteParams.altType, - altId: deleteParams.altId - }); - const response = await this.axiosInstance.delete(`/medias/${deleteParams.id}?${queryParams}`); - return this.wrapResponse({ success: true, message: 'Media file deleted successfully' }); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== CUSTOM OBJECTS API METHODS ===== - /** - * Get all objects for a location - * GET /objects/ - */ - async getObjectsByLocation(locationId) { - try { - const params = { - locationId: locationId || this.config.locationId - }; - const response = await this.axiosInstance.get('/objects/', { params }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create custom object schema - * POST /objects/ - */ - async createObjectSchema(schemaData) { - try { - const payload = { - ...schemaData, - locationId: schemaData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/objects/', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get object schema by key/id - * GET /objects/{key} - */ - async getObjectSchema(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId, - ...(params.fetchProperties !== undefined && { fetchProperties: params.fetchProperties.toString() }) - }; - const response = await this.axiosInstance.get(`/objects/${params.key}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update object schema by key/id - * PUT /objects/{key} - */ - async updateObjectSchema(key, updateData) { - try { - const payload = { - ...updateData, - locationId: updateData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/objects/${key}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create object record - * POST /objects/{schemaKey}/records - */ - async createObjectRecord(schemaKey, recordData) { - try { - const payload = { - ...recordData, - locationId: recordData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post(`/objects/${schemaKey}/records`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get object record by id - * GET /objects/{schemaKey}/records/{id} - */ - async getObjectRecord(schemaKey, recordId) { - try { - const response = await this.axiosInstance.get(`/objects/${schemaKey}/records/${recordId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update object record - * PUT /objects/{schemaKey}/records/{id} - */ - async updateObjectRecord(schemaKey, recordId, updateData) { - try { - const queryParams = { - locationId: updateData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/objects/${schemaKey}/records/${recordId}`, updateData, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete object record - * DELETE /objects/{schemaKey}/records/{id} - */ - async deleteObjectRecord(schemaKey, recordId) { - try { - const response = await this.axiosInstance.delete(`/objects/${schemaKey}/records/${recordId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Search object records - * POST /objects/{schemaKey}/records/search - */ - async searchObjectRecords(schemaKey, searchData) { - try { - const payload = { - ...searchData, - locationId: searchData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post(`/objects/${schemaKey}/records/search`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== ASSOCIATIONS API METHODS ===== - /** - * Get all associations for a location - * GET /associations/ - */ - async getAssociations(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId, - skip: params.skip.toString(), - limit: params.limit.toString() - }; - const response = await this.axiosInstance.get('/associations/', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create association - * POST /associations/ - */ - async createAssociation(associationData) { - try { - const payload = { - ...associationData, - locationId: associationData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/associations/', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get association by ID - * GET /associations/{associationId} - */ - async getAssociationById(associationId) { - try { - const response = await this.axiosInstance.get(`/associations/${associationId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update association - * PUT /associations/{associationId} - */ - async updateAssociation(associationId, updateData) { - try { - const response = await this.axiosInstance.put(`/associations/${associationId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete association - * DELETE /associations/{associationId} - */ - async deleteAssociation(associationId) { - try { - const response = await this.axiosInstance.delete(`/associations/${associationId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get association by key name - * GET /associations/key/{key_name} - */ - async getAssociationByKey(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId - }; - const response = await this.axiosInstance.get(`/associations/key/${params.keyName}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get association by object key - * GET /associations/objectKey/{objectKey} - */ - async getAssociationByObjectKey(params) { - try { - const queryParams = params.locationId ? { - locationId: params.locationId - } : {}; - const response = await this.axiosInstance.get(`/associations/objectKey/${params.objectKey}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create relation between entities - * POST /associations/relations - */ - async createRelation(relationData) { - try { - const payload = { - ...relationData, - locationId: relationData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/associations/relations', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get relations by record ID - * GET /associations/relations/{recordId} - */ - async getRelationsByRecord(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId, - skip: params.skip.toString(), - limit: params.limit.toString(), - ...(params.associationIds && { associationIds: params.associationIds }) - }; - const response = await this.axiosInstance.get(`/associations/relations/${params.recordId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete relation - * DELETE /associations/relations/{relationId} - */ - async deleteRelation(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId - }; - const response = await this.axiosInstance.delete(`/associations/relations/${params.relationId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== CUSTOM FIELDS V2 API METHODS ===== - /** - * Get custom field or folder by ID - * GET /custom-fields/{id} - */ - async getCustomFieldV2ById(id) { - try { - const response = await this.axiosInstance.get(`/custom-fields/${id}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create custom field - * POST /custom-fields/ - */ - async createCustomFieldV2(fieldData) { - try { - const payload = { - ...fieldData, - locationId: fieldData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/custom-fields/', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update custom field by ID - * PUT /custom-fields/{id} - */ - async updateCustomFieldV2(id, fieldData) { - try { - const payload = { - ...fieldData, - locationId: fieldData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/custom-fields/${id}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete custom field by ID - * DELETE /custom-fields/{id} - */ - async deleteCustomFieldV2(id) { - try { - const response = await this.axiosInstance.delete(`/custom-fields/${id}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get custom fields by object key - * GET /custom-fields/object-key/{objectKey} - */ - async getCustomFieldsV2ByObjectKey(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId - }; - const response = await this.axiosInstance.get(`/custom-fields/object-key/${params.objectKey}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Create custom field folder - * POST /custom-fields/folder - */ - async createCustomFieldV2Folder(folderData) { - try { - const payload = { - ...folderData, - locationId: folderData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post('/custom-fields/folder', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Update custom field folder name - * PUT /custom-fields/folder/{id} - */ - async updateCustomFieldV2Folder(id, folderData) { - try { - const payload = { - ...folderData, - locationId: folderData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/custom-fields/folder/${id}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Delete custom field folder - * DELETE /custom-fields/folder/{id} - */ - async deleteCustomFieldV2Folder(params) { - try { - const queryParams = { - locationId: params.locationId || this.config.locationId - }; - const response = await this.axiosInstance.delete(`/custom-fields/folder/${params.id}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== WORKFLOWS API METHODS ===== - /** - * Get all workflows for a location - * GET /workflows/ - */ - async getWorkflows(request) { - try { - const queryParams = { - locationId: request.locationId || this.config.locationId - }; - const response = await this.axiosInstance.get('/workflows/', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - // ===== SURVEYS API METHODS ===== - /** - * Get all surveys for a location - * GET /surveys/ - */ - async getSurveys(request) { - try { - const queryParams = { - locationId: request.locationId || this.config.locationId - }; - if (request.skip !== undefined) { - queryParams.skip = request.skip.toString(); - } - if (request.limit !== undefined) { - queryParams.limit = request.limit.toString(); - } - if (request.type) { - queryParams.type = request.type; - } - const response = await this.axiosInstance.get('/surveys/', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw this.handleApiError(error); - } - } - /** - * Get survey submissions with filtering and pagination - * GET /surveys/submissions - */ - async getSurveySubmissions(request) { - try { - const locationId = request.locationId || this.config.locationId; - const params = new URLSearchParams(); - if (request.page) - params.append('page', request.page.toString()); - if (request.limit) - params.append('limit', request.limit.toString()); - if (request.surveyId) - params.append('surveyId', request.surveyId); - if (request.q) - params.append('q', request.q); - if (request.startAt) - params.append('startAt', request.startAt); - if (request.endAt) - params.append('endAt', request.endAt); - const response = await this.axiosInstance.get(`/locations/${locationId}/surveys/submissions?${params.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - // ===== STORE API METHODS ===== - /** - * SHIPPING ZONES API METHODS - */ - /** - * Create a new shipping zone - * POST /store/shipping-zone - */ - async createShippingZone(zoneData) { - try { - const payload = { - ...zoneData, - altId: zoneData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/store/shipping-zone', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List all shipping zones - * GET /store/shipping-zone - */ - async listShippingZones(params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - if (params.withShippingRate !== undefined) - queryParams.append('withShippingRate', params.withShippingRate.toString()); - const response = await this.axiosInstance.get(`/store/shipping-zone?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get a specific shipping zone by ID - * GET /store/shipping-zone/{shippingZoneId} - */ - async getShippingZone(shippingZoneId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - if (params.withShippingRate !== undefined) - queryParams.append('withShippingRate', params.withShippingRate.toString()); - const response = await this.axiosInstance.get(`/store/shipping-zone/${shippingZoneId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a shipping zone - * PUT /store/shipping-zone/{shippingZoneId} - */ - async updateShippingZone(shippingZoneId, updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/store/shipping-zone/${shippingZoneId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a shipping zone - * DELETE /store/shipping-zone/{shippingZoneId} - */ - async deleteShippingZone(shippingZoneId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.delete(`/store/shipping-zone/${shippingZoneId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * SHIPPING RATES API METHODS - */ - /** - * Get available shipping rates for an order - * POST /store/shipping-zone/shipping-rates - */ - async getAvailableShippingRates(rateData) { - try { - const payload = { - ...rateData, - altId: rateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/store/shipping-zone/shipping-rates', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create a new shipping rate for a zone - * POST /store/shipping-zone/{shippingZoneId}/shipping-rate - */ - async createShippingRate(shippingZoneId, rateData) { - try { - const payload = { - ...rateData, - altId: rateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/store/shipping-zone/${shippingZoneId}/shipping-rate`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List shipping rates for a zone - * GET /store/shipping-zone/{shippingZoneId}/shipping-rate - */ - async listShippingRates(shippingZoneId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - const response = await this.axiosInstance.get(`/store/shipping-zone/${shippingZoneId}/shipping-rate?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get a specific shipping rate - * GET /store/shipping-zone/{shippingZoneId}/shipping-rate/{shippingRateId} - */ - async getShippingRate(shippingZoneId, shippingRateId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.get(`/store/shipping-zone/${shippingZoneId}/shipping-rate/${shippingRateId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a shipping rate - * PUT /store/shipping-zone/{shippingZoneId}/shipping-rate/{shippingRateId} - */ - async updateShippingRate(shippingZoneId, shippingRateId, updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/store/shipping-zone/${shippingZoneId}/shipping-rate/${shippingRateId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a shipping rate - * DELETE /store/shipping-zone/{shippingZoneId}/shipping-rate/{shippingRateId} - */ - async deleteShippingRate(shippingZoneId, shippingRateId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.delete(`/store/shipping-zone/${shippingZoneId}/shipping-rate/${shippingRateId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * SHIPPING CARRIERS API METHODS - */ - /** - * Create a new shipping carrier - * POST /store/shipping-carrier - */ - async createShippingCarrier(carrierData) { - try { - const payload = { - ...carrierData, - altId: carrierData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/store/shipping-carrier', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List all shipping carriers - * GET /store/shipping-carrier - */ - async listShippingCarriers(params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.get(`/store/shipping-carrier?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get a specific shipping carrier by ID - * GET /store/shipping-carrier/{shippingCarrierId} - */ - async getShippingCarrier(shippingCarrierId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.get(`/store/shipping-carrier/${shippingCarrierId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a shipping carrier - * PUT /store/shipping-carrier/{shippingCarrierId} - */ - async updateShippingCarrier(shippingCarrierId, updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/store/shipping-carrier/${shippingCarrierId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a shipping carrier - * DELETE /store/shipping-carrier/{shippingCarrierId} - */ - async deleteShippingCarrier(shippingCarrierId, params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.delete(`/store/shipping-carrier/${shippingCarrierId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * STORE SETTINGS API METHODS - */ - /** - * Create or update store settings - * POST /store/store-setting - */ - async createStoreSetting(settingData) { - try { - const payload = { - ...settingData, - altId: settingData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/store/store-setting', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get store settings - * GET /store/store-setting - */ - async getStoreSetting(params) { - try { - const altId = params.altId || this.config.locationId; - const queryParams = new URLSearchParams({ - altId, - altType: 'location' - }); - const response = await this.axiosInstance.get(`/store/store-setting?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * PRODUCTS API METHODS - */ - /** - * Create a new product - * POST /products/ - */ - async createProduct(productData) { - try { - const response = await this.axiosInstance.post('/products/', productData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a product by ID - * PUT /products/{productId} - */ - async updateProduct(productId, updateData) { - try { - const response = await this.axiosInstance.put(`/products/${productId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get a product by ID - * GET /products/{productId} - */ - async getProduct(productId, locationId) { - try { - const queryParams = new URLSearchParams({ - locationId: locationId || this.config.locationId - }); - const response = await this.axiosInstance.get(`/products/${productId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List products - * GET /products/ - */ - async listProducts(params) { - try { - const queryParams = new URLSearchParams({ - locationId: params.locationId || this.config.locationId - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - if (params.search) - queryParams.append('search', params.search); - if (params.collectionIds?.length) - queryParams.append('collectionIds', params.collectionIds.join(',')); - if (params.collectionSlug) - queryParams.append('collectionSlug', params.collectionSlug); - if (params.expand?.length) - params.expand.forEach(item => queryParams.append('expand', item)); - if (params.productIds?.length) - params.productIds.forEach(id => queryParams.append('productIds', id)); - if (params.storeId) - queryParams.append('storeId', params.storeId); - if (params.includedInStore !== undefined) - queryParams.append('includedInStore', params.includedInStore.toString()); - if (params.availableInStore !== undefined) - queryParams.append('availableInStore', params.availableInStore.toString()); - if (params.sortOrder) - queryParams.append('sortOrder', params.sortOrder); - const response = await this.axiosInstance.get(`/products/?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a product by ID - * DELETE /products/{productId} - */ - async deleteProduct(productId, locationId) { - try { - const queryParams = new URLSearchParams({ - locationId: locationId || this.config.locationId - }); - const response = await this.axiosInstance.delete(`/products/${productId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Bulk update products - * POST /products/bulk-update - */ - async bulkUpdateProducts(updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/products/bulk-update', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create a price for a product - * POST /products/{productId}/price - */ - async createPrice(productId, priceData) { - try { - const payload = { - ...priceData, - locationId: priceData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.post(`/products/${productId}/price`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a price by ID - * PUT /products/{productId}/price/{priceId} - */ - async updatePrice(productId, priceId, updateData) { - try { - const payload = { - ...updateData, - locationId: updateData.locationId || this.config.locationId - }; - const response = await this.axiosInstance.put(`/products/${productId}/price/${priceId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get a price by ID - * GET /products/{productId}/price/{priceId} - */ - async getPrice(productId, priceId, locationId) { - try { - const queryParams = new URLSearchParams({ - locationId: locationId || this.config.locationId - }); - const response = await this.axiosInstance.get(`/products/${productId}/price/${priceId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List prices for a product - * GET /products/{productId}/price - */ - async listPrices(productId, params) { - try { - const queryParams = new URLSearchParams({ - locationId: params.locationId || this.config.locationId - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - if (params.ids) - queryParams.append('ids', params.ids); - const response = await this.axiosInstance.get(`/products/${productId}/price?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a price by ID - * DELETE /products/{productId}/price/{priceId} - */ - async deletePrice(productId, priceId, locationId) { - try { - const queryParams = new URLSearchParams({ - locationId: locationId || this.config.locationId - }); - const response = await this.axiosInstance.delete(`/products/${productId}/price/${priceId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List inventory - * GET /products/inventory - */ - async listInventory(params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location' - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - if (params.search) - queryParams.append('search', params.search); - const response = await this.axiosInstance.get(`/products/inventory?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update inventory - * POST /products/inventory - */ - async updateInventory(updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/products/inventory', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get product store stats - * GET /products/store/{storeId}/stats - */ - async getProductStoreStats(storeId, params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location' - }); - if (params.search) - queryParams.append('search', params.search); - if (params.collectionIds) - queryParams.append('collectionIds', params.collectionIds); - const response = await this.axiosInstance.get(`/products/store/${storeId}/stats?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update product store status - * POST /products/store/{storeId} - */ - async updateProductStore(storeId, updateData) { - try { - const response = await this.axiosInstance.post(`/products/store/${storeId}`, updateData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create a product collection - * POST /products/collections - */ - async createProductCollection(collectionData) { - try { - const payload = { - ...collectionData, - altId: collectionData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/products/collections', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a product collection - * PUT /products/collections/{collectionId} - */ - async updateProductCollection(collectionId, updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/products/collections/${collectionId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get a product collection by ID - * GET /products/collections/{collectionId} - */ - async getProductCollection(collectionId) { - try { - const response = await this.axiosInstance.get(`/products/collections/${collectionId}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List product collections - * GET /products/collections - */ - async listProductCollections(params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location' - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - if (params.collectionIds) - queryParams.append('collectionIds', params.collectionIds); - if (params.name) - queryParams.append('name', params.name); - const response = await this.axiosInstance.get(`/products/collections?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a product collection - * DELETE /products/collections/{collectionId} - */ - async deleteProductCollection(collectionId, params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location' - }); - const response = await this.axiosInstance.delete(`/products/collections/${collectionId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List product reviews - * GET /products/reviews - */ - async listProductReviews(params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location' - }); - if (params.limit) - queryParams.append('limit', params.limit.toString()); - if (params.offset) - queryParams.append('offset', params.offset.toString()); - if (params.sortField) - queryParams.append('sortField', params.sortField); - if (params.sortOrder) - queryParams.append('sortOrder', params.sortOrder); - if (params.rating) - queryParams.append('rating', params.rating.toString()); - if (params.startDate) - queryParams.append('startDate', params.startDate); - if (params.endDate) - queryParams.append('endDate', params.endDate); - if (params.productId) - queryParams.append('productId', params.productId); - if (params.storeId) - queryParams.append('storeId', params.storeId); - const response = await this.axiosInstance.get(`/products/reviews?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get reviews count - * GET /products/reviews/count - */ - async getReviewsCount(params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location' - }); - if (params.rating) - queryParams.append('rating', params.rating.toString()); - if (params.startDate) - queryParams.append('startDate', params.startDate); - if (params.endDate) - queryParams.append('endDate', params.endDate); - if (params.productId) - queryParams.append('productId', params.productId); - if (params.storeId) - queryParams.append('storeId', params.storeId); - const response = await this.axiosInstance.get(`/products/reviews/count?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update a product review - * PUT /products/reviews/{reviewId} - */ - async updateProductReview(reviewId, updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/products/reviews/${reviewId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete a product review - * DELETE /products/reviews/{reviewId} - */ - async deleteProductReview(reviewId, params) { - try { - const queryParams = new URLSearchParams({ - altId: params.altId || this.config.locationId, - altType: 'location', - productId: params.productId - }); - const response = await this.axiosInstance.delete(`/products/reviews/${reviewId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Bulk update product reviews - * POST /products/reviews/bulk-update - */ - async bulkUpdateProductReviews(updateData) { - try { - const payload = { - ...updateData, - altId: updateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/products/reviews/bulk-update', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * PAYMENTS API METHODS - */ - /** - * Create white-label integration provider - * POST /payments/integrations/provider/whitelabel - */ - async createWhiteLabelIntegrationProvider(data) { - try { - const response = await this.axiosInstance.post('/payments/integrations/provider/whitelabel', data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List white-label integration providers - * GET /payments/integrations/provider/whitelabel - */ - async listWhiteLabelIntegrationProviders(params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/integrations/provider/whitelabel?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List orders - * GET /payments/orders - */ - async listOrders(params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/orders?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get order by ID - * GET /payments/orders/{orderId} - */ - async getOrderById(orderId, params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null && key !== 'orderId') { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/orders/${orderId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create order fulfillment - * POST /payments/orders/{orderId}/fulfillments - */ - async createOrderFulfillment(orderId, data) { - try { - const response = await this.axiosInstance.post(`/payments/orders/${orderId}/fulfillments`, data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List order fulfillments - * GET /payments/orders/{orderId}/fulfillments - */ - async listOrderFulfillments(orderId, params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null && key !== 'orderId') { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/orders/${orderId}/fulfillments?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List transactions - * GET /payments/transactions - */ - async listTransactions(params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/transactions?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get transaction by ID - * GET /payments/transactions/{transactionId} - */ - async getTransactionById(transactionId, params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null && key !== 'transactionId') { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/transactions/${transactionId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List subscriptions - * GET /payments/subscriptions - */ - async listSubscriptions(params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/subscriptions?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get subscription by ID - * GET /payments/subscriptions/{subscriptionId} - */ - async getSubscriptionById(subscriptionId, params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null && key !== 'subscriptionId') { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/subscriptions/${subscriptionId}?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List coupons - * GET /payments/coupon/list - */ - async listCoupons(params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/coupon/list?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create coupon - * POST /payments/coupon - */ - async createCoupon(data) { - try { - const response = await this.axiosInstance.post('/payments/coupon', data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update coupon - * PUT /payments/coupon - */ - async updateCoupon(data) { - try { - const response = await this.axiosInstance.put('/payments/coupon', data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete coupon - * DELETE /payments/coupon - */ - async deleteCoupon(data) { - try { - const response = await this.axiosInstance.delete('/payments/coupon', { data }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get coupon - * GET /payments/coupon - */ - async getCoupon(params) { - try { - const queryParams = new URLSearchParams(); - Object.entries(params).forEach(([key, value]) => { - if (value !== undefined && value !== null) { - queryParams.append(key, value.toString()); - } - }); - const response = await this.axiosInstance.get(`/payments/coupon?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create custom provider integration - * POST /payments/custom-provider/provider - */ - async createCustomProviderIntegration(locationId, data) { - try { - const queryParams = new URLSearchParams({ locationId }); - const response = await this.axiosInstance.post(`/payments/custom-provider/provider?${queryParams.toString()}`, data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete custom provider integration - * DELETE /payments/custom-provider/provider - */ - async deleteCustomProviderIntegration(locationId) { - try { - const queryParams = new URLSearchParams({ locationId }); - const response = await this.axiosInstance.delete(`/payments/custom-provider/provider?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get custom provider config - * GET /payments/custom-provider/connect - */ - async getCustomProviderConfig(locationId) { - try { - const queryParams = new URLSearchParams({ locationId }); - const response = await this.axiosInstance.get(`/payments/custom-provider/connect?${queryParams.toString()}`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create custom provider config - * POST /payments/custom-provider/connect - */ - async createCustomProviderConfig(locationId, data) { - try { - const queryParams = new URLSearchParams({ locationId }); - const response = await this.axiosInstance.post(`/payments/custom-provider/connect?${queryParams.toString()}`, data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Disconnect custom provider config - * POST /payments/custom-provider/disconnect - */ - async disconnectCustomProviderConfig(locationId, data) { - try { - const queryParams = new URLSearchParams({ locationId }); - const response = await this.axiosInstance.post(`/payments/custom-provider/disconnect?${queryParams.toString()}`, data); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - // ============================================================================= - // INVOICES API METHODS - // ============================================================================= - /** - * Create invoice template - * POST /invoices/template - */ - async createInvoiceTemplate(templateData) { - try { - const payload = { - ...templateData, - altId: templateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/invoices/template', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List invoice templates - * GET /invoices/template - */ - async listInvoiceTemplates(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location', - limit: params?.limit || '10', - offset: params?.offset || '0', - ...(params?.status && { status: params.status }), - ...(params?.startAt && { startAt: params.startAt }), - ...(params?.endAt && { endAt: params.endAt }), - ...(params?.search && { search: params.search }), - ...(params?.paymentMode && { paymentMode: params.paymentMode }) - }; - const response = await this.axiosInstance.get('/invoices/template', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get invoice template by ID - * GET /invoices/template/{templateId} - */ - async getInvoiceTemplate(templateId, params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.get(`/invoices/template/${templateId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice template - * PUT /invoices/template/{templateId} - */ - async updateInvoiceTemplate(templateId, templateData) { - try { - const payload = { - ...templateData, - altId: templateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/invoices/template/${templateId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete invoice template - * DELETE /invoices/template/{templateId} - */ - async deleteInvoiceTemplate(templateId, params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.delete(`/invoices/template/${templateId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice template late fees configuration - * PATCH /invoices/template/{templateId}/late-fees-configuration - */ - async updateInvoiceTemplateLateFeesConfiguration(templateId, configData) { - try { - const payload = { - ...configData, - altId: configData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.patch(`/invoices/template/${templateId}/late-fees-configuration`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice template payment methods configuration - * PATCH /invoices/template/{templateId}/payment-methods-configuration - */ - async updateInvoiceTemplatePaymentMethodsConfiguration(templateId, configData) { - try { - const payload = { - ...configData, - altId: configData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.patch(`/invoices/template/${templateId}/payment-methods-configuration`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create invoice schedule - * POST /invoices/schedule - */ - async createInvoiceSchedule(scheduleData) { - try { - const payload = { - ...scheduleData, - altId: scheduleData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/invoices/schedule', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List invoice schedules - * GET /invoices/schedule - */ - async listInvoiceSchedules(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location', - limit: params?.limit || '10', - offset: params?.offset || '0', - ...(params?.status && { status: params.status }), - ...(params?.startAt && { startAt: params.startAt }), - ...(params?.endAt && { endAt: params.endAt }), - ...(params?.search && { search: params.search }), - ...(params?.paymentMode && { paymentMode: params.paymentMode }) - }; - const response = await this.axiosInstance.get('/invoices/schedule', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get invoice schedule by ID - * GET /invoices/schedule/{scheduleId} - */ - async getInvoiceSchedule(scheduleId, params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.get(`/invoices/schedule/${scheduleId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice schedule - * PUT /invoices/schedule/{scheduleId} - */ - async updateInvoiceSchedule(scheduleId, scheduleData) { - try { - const payload = { - ...scheduleData, - altId: scheduleData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/invoices/schedule/${scheduleId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete invoice schedule - * DELETE /invoices/schedule/{scheduleId} - */ - async deleteInvoiceSchedule(scheduleId, params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.delete(`/invoices/schedule/${scheduleId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update and schedule recurring invoice - * POST /invoices/schedule/{scheduleId}/updateAndSchedule - */ - async updateAndScheduleInvoiceSchedule(scheduleId) { - try { - const response = await this.axiosInstance.post(`/invoices/schedule/${scheduleId}/updateAndSchedule`); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Schedule an invoice schedule - * POST /invoices/schedule/{scheduleId}/schedule - */ - async scheduleInvoiceSchedule(scheduleId, scheduleData) { - try { - const payload = { - ...scheduleData, - altId: scheduleData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/schedule/${scheduleId}/schedule`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Manage auto payment for schedule invoice - * POST /invoices/schedule/{scheduleId}/auto-payment - */ - async autoPaymentInvoiceSchedule(scheduleId, paymentData) { - try { - const payload = { - ...paymentData, - altId: paymentData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/schedule/${scheduleId}/auto-payment`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Cancel scheduled invoice - * POST /invoices/schedule/{scheduleId}/cancel - */ - async cancelInvoiceSchedule(scheduleId, cancelData) { - try { - const payload = { - ...cancelData, - altId: cancelData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/schedule/${scheduleId}/cancel`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create or update text2pay invoice - * POST /invoices/text2pay - */ - async text2PayInvoice(invoiceData) { - try { - const payload = { - ...invoiceData, - altId: invoiceData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/invoices/text2pay', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Generate invoice number - * GET /invoices/generate-invoice-number - */ - async generateInvoiceNumber(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.get('/invoices/generate-invoice-number', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Get invoice by ID - * GET /invoices/{invoiceId} - */ - async getInvoice(invoiceId, params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.get(`/invoices/${invoiceId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice - * PUT /invoices/{invoiceId} - */ - async updateInvoice(invoiceId, invoiceData) { - try { - const payload = { - ...invoiceData, - altId: invoiceData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/invoices/${invoiceId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete invoice - * DELETE /invoices/{invoiceId} - */ - async deleteInvoice(invoiceId, params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.delete(`/invoices/${invoiceId}`, { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice late fees configuration - * PATCH /invoices/{invoiceId}/late-fees-configuration - */ - async updateInvoiceLateFeesConfiguration(invoiceId, configData) { - try { - const payload = { - ...configData, - altId: configData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.patch(`/invoices/${invoiceId}/late-fees-configuration`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Void invoice - * POST /invoices/{invoiceId}/void - */ - async voidInvoice(invoiceId, voidData) { - try { - const payload = { - ...voidData, - altId: voidData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/${invoiceId}/void`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Send invoice - * POST /invoices/{invoiceId}/send - */ - async sendInvoice(invoiceId, sendData) { - try { - const payload = { - ...sendData, - altId: sendData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/${invoiceId}/send`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Record manual payment for invoice - * POST /invoices/{invoiceId}/record-payment - */ - async recordInvoicePayment(invoiceId, paymentData) { - try { - const payload = { - ...paymentData, - altId: paymentData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/${invoiceId}/record-payment`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update invoice last visited at - * PATCH /invoices/stats/last-visited-at - */ - async updateInvoiceLastVisitedAt(statsData) { - try { - const response = await this.axiosInstance.patch('/invoices/stats/last-visited-at', statsData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create new estimate - * POST /invoices/estimate - */ - async createEstimate(estimateData) { - try { - const payload = { - ...estimateData, - altId: estimateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/invoices/estimate', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update estimate - * PUT /invoices/estimate/{estimateId} - */ - async updateEstimate(estimateId, estimateData) { - try { - const payload = { - ...estimateData, - altId: estimateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/invoices/estimate/${estimateId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete estimate - * DELETE /invoices/estimate/{estimateId} - */ - async deleteEstimate(estimateId, deleteData) { - try { - const payload = { - ...deleteData, - altId: deleteData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.delete(`/invoices/estimate/${estimateId}`, { data: payload }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Generate estimate number - * GET /invoices/estimate/number/generate - */ - async generateEstimateNumber(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.get('/invoices/estimate/number/generate', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Send estimate - * POST /invoices/estimate/{estimateId}/send - */ - async sendEstimate(estimateId, sendData) { - try { - const payload = { - ...sendData, - altId: sendData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/estimate/${estimateId}/send`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create invoice from estimate - * POST /invoices/estimate/{estimateId}/invoice - */ - async createInvoiceFromEstimate(estimateId, invoiceData) { - try { - const payload = { - ...invoiceData, - altId: invoiceData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post(`/invoices/estimate/${estimateId}/invoice`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List estimates - * GET /invoices/estimate/list - */ - async listEstimates(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location', - limit: params?.limit || '10', - offset: params?.offset || '0', - ...(params?.startAt && { startAt: params.startAt }), - ...(params?.endAt && { endAt: params.endAt }), - ...(params?.search && { search: params.search }), - ...(params?.status && { status: params.status }), - ...(params?.contactId && { contactId: params.contactId }) - }; - const response = await this.axiosInstance.get('/invoices/estimate/list', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update estimate last visited at - * PATCH /invoices/estimate/stats/last-visited-at - */ - async updateEstimateLastVisitedAt(statsData) { - try { - const response = await this.axiosInstance.patch('/invoices/estimate/stats/last-visited-at', statsData); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List estimate templates - * GET /invoices/estimate/template - */ - async listEstimateTemplates(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location', - limit: params?.limit || '10', - offset: params?.offset || '0', - ...(params?.search && { search: params.search }) - }; - const response = await this.axiosInstance.get('/invoices/estimate/template', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create estimate template - * POST /invoices/estimate/template - */ - async createEstimateTemplate(templateData) { - try { - const payload = { - ...templateData, - altId: templateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/invoices/estimate/template', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Update estimate template - * PUT /invoices/estimate/template/{templateId} - */ - async updateEstimateTemplate(templateId, templateData) { - try { - const payload = { - ...templateData, - altId: templateData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.put(`/invoices/estimate/template/${templateId}`, payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Delete estimate template - * DELETE /invoices/estimate/template/{templateId} - */ - async deleteEstimateTemplate(templateId, deleteData) { - try { - const payload = { - ...deleteData, - altId: deleteData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.delete(`/invoices/estimate/template/${templateId}`, { data: payload }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Preview estimate template - * GET /invoices/estimate/template/preview - */ - async previewEstimateTemplate(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location', - templateId: params?.templateId || '' - }; - const response = await this.axiosInstance.get('/invoices/estimate/template/preview', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * Create invoice - * POST /invoices/ - */ - async createInvoice(invoiceData) { - try { - const payload = { - ...invoiceData, - altId: invoiceData.altId || this.config.locationId, - altType: 'location' - }; - const response = await this.axiosInstance.post('/invoices/', payload); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } - /** - * List invoices - * GET /invoices/ - */ - async listInvoices(params) { - try { - const queryParams = { - altId: params?.altId || this.config.locationId, - altType: 'location', - limit: params?.limit || '10', - offset: params?.offset || '0', - ...(params?.status && { status: params.status }), - ...(params?.startAt && { startAt: params.startAt }), - ...(params?.endAt && { endAt: params.endAt }), - ...(params?.search && { search: params.search }), - ...(params?.paymentMode && { paymentMode: params.paymentMode }), - ...(params?.contactId && { contactId: params.contactId }), - ...(params?.sortField && { sortField: params.sortField }), - ...(params?.sortOrder && { sortOrder: params.sortOrder }) - }; - const response = await this.axiosInstance.get('/invoices/', { params: queryParams }); - return this.wrapResponse(response.data); - } - catch (error) { - throw error; - } - } -} diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/server.js b/mcp-diagrams/ghl-mcp-apps-only/dist/server.js deleted file mode 100644 index 87611bd..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/server.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * GoHighLevel MCP Apps Server (Slimmed Down) - * Only includes MCP Apps - no other tools - */ -import { Server } from '@modelcontextprotocol/sdk/server/index.js'; -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, McpError } from '@modelcontextprotocol/sdk/types.js'; -import * as dotenv from 'dotenv'; -import { GHLApiClient } from './clients/ghl-api-client.js'; -import { MCPAppsManager } from './apps/index.js'; -// Load environment variables -dotenv.config(); -/** - * MCP Apps Only Server - */ -class GHLMCPAppsServer { - server; - ghlClient; - mcpAppsManager; - constructor() { - // Initialize MCP server with capabilities - this.server = new Server({ - name: 'ghl-mcp-apps-only', - version: '1.0.0', - }, { - capabilities: { - tools: {}, - resources: {}, - }, - }); - // Initialize GHL API client - this.ghlClient = this.initializeGHLClient(); - // Initialize MCP Apps Manager - this.mcpAppsManager = new MCPAppsManager(this.ghlClient); - this.setupHandlers(); - this.setupErrorHandling(); - } - /** - * Initialize the GHL API client with config from environment - */ - initializeGHLClient() { - const config = { - accessToken: process.env.GHL_API_KEY || '', - locationId: process.env.GHL_LOCATION_ID || '', - baseUrl: process.env.GHL_BASE_URL || 'https://services.leadconnectorhq.com', - version: '2021-07-28' - }; - if (!config.accessToken) { - process.stderr.write('Warning: GHL_API_KEY not set in environment\n'); - } - if (!config.locationId) { - process.stderr.write('Warning: GHL_LOCATION_ID not set in environment\n'); - } - return new GHLApiClient(config); - } - /** - * Setup request handlers - */ - setupHandlers() { - // List tools - only MCP App tools - this.server.setRequestHandler(ListToolsRequestSchema, async () => { - const appTools = this.mcpAppsManager.getToolDefinitions(); - process.stderr.write(`[MCP Apps Only] Listing ${appTools.length} app tools\n`); - return { tools: appTools }; - }); - // List resources - MCP App UI resources - this.server.setRequestHandler(ListResourcesRequestSchema, async () => { - const resourceUris = this.mcpAppsManager.getResourceURIs(); - const resources = resourceUris.map(uri => { - const handler = this.mcpAppsManager.getResourceHandler(uri); - return { - uri: uri, - name: uri, - mimeType: handler?.mimeType || 'text/html;profile=mcp-app' - }; - }); - process.stderr.write(`[MCP Apps Only] Listing ${resources.length} UI resources\n`); - return { resources }; - }); - // Read resource - serve UI HTML - this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { - const uri = request.params.uri; - process.stderr.write(`[MCP Apps Only] Reading resource: ${uri}\n`); - const handler = this.mcpAppsManager.getResourceHandler(uri); - if (!handler) { - throw new McpError(ErrorCode.InvalidRequest, `Resource not found: ${uri}`); - } - return { - contents: [{ - uri: uri, - mimeType: handler.mimeType, - text: handler.getContent() - }] - }; - }); - // Call tool - execute MCP App tools - this.server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - process.stderr.write(`[MCP Apps Only] Calling tool: ${name}\n`); - if (!this.mcpAppsManager.isAppTool(name)) { - throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); - } - try { - const result = await this.mcpAppsManager.executeTool(name, args || {}); - return result; - } - catch (error) { - process.stderr.write(`[MCP Apps Only] Tool error: ${error.message}\n`); - throw new McpError(ErrorCode.InternalError, error.message); - } - }); - } - /** - * Setup error handling - */ - setupErrorHandling() { - this.server.onerror = (error) => { - process.stderr.write(`[MCP Apps Only] Server error: ${error}\n`); - }; - process.on('SIGINT', async () => { - await this.server.close(); - process.exit(0); - }); - } - /** - * Start the server - */ - async run() { - const transport = new StdioServerTransport(); - await this.server.connect(transport); - process.stderr.write('[MCP Apps Only] Server started - Apps only mode\n'); - } -} -// Start server -const server = new GHLMCPAppsServer(); -server.run().catch((error) => { - process.stderr.write(`Failed to start server: ${error}\n`); - process.exit(1); -}); diff --git a/mcp-diagrams/ghl-mcp-apps-only/dist/types/ghl-types.js b/mcp-diagrams/ghl-mcp-apps-only/dist/types/ghl-types.js deleted file mode 100644 index 8fdf1f5..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/dist/types/ghl-types.js +++ /dev/null @@ -1,5 +0,0 @@ -/** - * TypeScript interfaces for GoHighLevel API integration - * Based on official OpenAPI specifications v2021-07-28 (Contacts) and v2021-04-15 (Conversations) - */ -export {}; diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/calendar-widget-CUbShwNj.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/calendar-widget-CUbShwNj.js deleted file mode 100644 index d5bfbd1..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/calendar-widget-CUbShwNj.js +++ /dev/null @@ -1 +0,0 @@ -import{j as t,A as k,r as j,f as M,R as C,a as A}from"./styles-CphAgR3l.js";function R({data:c}){const{calendar:g,events:a,startDate:p}=c,[d,s]=j.useState("month"),[i,n]=j.useState(new Date(p)),y=e=>{const r=e.getFullYear(),l=e.getMonth(),x=new Date(r,l,1),m=new Date(r,l+1,0),h=[],N=x.getDay();for(let o=N-1;o>=0;o--)h.push(new Date(r,l,-o));for(let o=1;o<=m.getDate();o++)h.push(new Date(r,l,o));const T=42-h.length;for(let o=1;o<=T;o++)h.push(new Date(r,l+1,o));return h},v=e=>{const r=e.toISOString().split("T")[0];return a.filter(l=>l.startTime?l.startTime.split("T")[0]===r:!1)},b=e=>{const r=new Date;return e.toDateString()===r.toDateString()},D=e=>e.getMonth()===i.getMonth(),f=e=>{const r=new Date(i);r.setMonth(r.getMonth()+e),n(r)},w=y(i),S=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];return t.jsxs("div",{className:"ghl-app",children:[t.jsxs("div",{className:"ghl-card",children:[t.jsx("div",{className:"ghl-card-header",children:t.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[t.jsxs("div",{children:[t.jsx("h2",{style:{fontSize:18,fontWeight:600},children:g?.name||"Calendar"}),t.jsxs("p",{className:"ghl-text-sm ghl-text-muted",children:[a.length," events"]})]}),t.jsx("div",{className:"ghl-flex ghl-gap-2",children:["month","week","day"].map(e=>t.jsx("button",{className:`ghl-btn ghl-btn-sm ${d===e?"ghl-btn-primary":"ghl-btn-secondary"}`,onClick:()=>s(e),children:e.charAt(0).toUpperCase()+e.slice(1)},e))})]})}),t.jsx("div",{style:{padding:"12px 16px",borderBottom:"1px solid var(--ghl-border)"},children:t.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[t.jsx("button",{className:"ghl-btn ghl-btn-secondary ghl-btn-sm",onClick:()=>f(-1),children:"← Prev"}),t.jsx("span",{className:"ghl-font-semibold",children:i.toLocaleDateString("en-US",{month:"long",year:"numeric"})}),t.jsx("button",{className:"ghl-btn ghl-btn-secondary ghl-btn-sm",onClick:()=>f(1),children:"Next →"})]})}),t.jsxs("div",{className:"ghl-card-body",style:{padding:0},children:[d==="month"&&t.jsxs("div",{children:[t.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(7, 1fr)",borderBottom:"1px solid var(--ghl-border)"},children:S.map(e=>t.jsx("div",{style:{padding:8,textAlign:"center",fontWeight:600,fontSize:12,color:"var(--ghl-text-secondary)",background:"var(--ghl-bg-secondary)"},children:e},e))}),t.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(7, 1fr)"},children:w.map((e,r)=>{const l=v(e),x=D(e),m=b(e);return t.jsxs("div",{style:{minHeight:80,padding:4,borderRight:(r+1)%7!==0?"1px solid var(--ghl-border)":"none",borderBottom:"1px solid var(--ghl-border)",background:m?"rgba(79, 70, 229, 0.05)":"transparent",opacity:x?1:.4},children:[t.jsx("div",{style:{width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,fontWeight:m?600:400,background:m?"var(--ghl-primary)":"transparent",color:m?"white":"inherit",marginBottom:4},children:e.getDate()}),l.slice(0,2).map(h=>t.jsx("div",{style:{fontSize:10,padding:"2px 4px",marginBottom:2,borderRadius:3,background:u(h.appointmentStatus),color:"white",whiteSpace:"nowrap",overflow:"hidden",textOverflow:"ellipsis"},children:h.title||"Appointment"},h.id)),l.length>2&&t.jsxs("div",{className:"ghl-text-sm ghl-text-muted",style:{fontSize:10},children:["+",l.length-2," more"]})]},r)})})]}),d==="week"&&t.jsx(B,{events:a,currentDate:i}),d==="day"&&t.jsx(E,{events:a,currentDate:i})]})]}),t.jsxs("div",{className:"ghl-card",style:{marginTop:16},children:[t.jsx("div",{className:"ghl-card-header",children:t.jsx("h3",{className:"ghl-font-semibold",children:"Upcoming Events"})}),t.jsx("div",{className:"ghl-card-body",style:{padding:0},children:a.length===0?t.jsx("div",{className:"ghl-empty",children:t.jsx("p",{children:"No upcoming events"})}):t.jsx("div",{children:a.slice(0,5).map(e=>t.jsxs("div",{style:{padding:"12px 16px",borderBottom:"1px solid var(--ghl-border)",display:"flex",alignItems:"center",gap:12},children:[t.jsx("div",{style:{width:4,height:40,borderRadius:2,background:u(e.appointmentStatus)}}),t.jsxs("div",{style:{flex:1},children:[t.jsx("div",{className:"ghl-font-medium",children:e.title||"Appointment"}),e.contact&&t.jsx("div",{className:"ghl-text-sm ghl-text-muted",children:e.contact.name||`${e.contact.firstName||""} ${e.contact.lastName||""}`})]}),t.jsxs("div",{style:{textAlign:"right"},children:[t.jsx("div",{className:"ghl-text-sm",children:M(e.startTime)}),e.startTime&&t.jsx("div",{className:"ghl-text-sm ghl-text-muted",children:new Date(e.startTime).toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit"})})]})]},e.id))})})]})]})}function B({events:c,currentDate:g}){const a=new Date(g);a.setDate(g.getDate()-g.getDay());const p=Array.from({length:7},(d,s)=>{const i=new Date(a);return i.setDate(a.getDate()+s),i});return t.jsx("div",{style:{display:"grid",gridTemplateColumns:"repeat(7, 1fr)"},children:p.map((d,s)=>{const i=c.filter(n=>n.startTime?n.startTime.split("T")[0]===d.toISOString().split("T")[0]:!1);return t.jsxs("div",{style:{borderRight:s<6?"1px solid var(--ghl-border)":"none",minHeight:200},children:[t.jsxs("div",{style:{padding:8,textAlign:"center",borderBottom:"1px solid var(--ghl-border)",background:"var(--ghl-bg-secondary)"},children:[t.jsx("div",{className:"ghl-text-sm ghl-text-muted",children:d.toLocaleDateString("en-US",{weekday:"short"})}),t.jsx("div",{className:"ghl-font-semibold",children:d.getDate()})]}),t.jsx("div",{style:{padding:4},children:i.map(n=>t.jsxs("div",{style:{padding:6,marginBottom:4,borderRadius:4,background:u(n.appointmentStatus),color:"white",fontSize:11},children:[t.jsx("div",{style:{fontWeight:500},children:n.title||"Appointment"}),n.startTime&&t.jsx("div",{style:{opacity:.8},children:new Date(n.startTime).toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit"})})]},n.id))})]},s)})})}function E({events:c,currentDate:g}){const a=Array.from({length:24},(s,i)=>i),p=g.toISOString().split("T")[0],d=c.filter(s=>s.startTime?.startsWith(p));return t.jsx("div",{style:{maxHeight:400,overflowY:"auto"},children:a.map(s=>{const i=d.filter(n=>n.startTime?new Date(n.startTime).getHours()===s:!1);return t.jsxs("div",{style:{display:"flex",borderBottom:"1px solid var(--ghl-border)",minHeight:48},children:[t.jsx("div",{style:{width:60,padding:8,fontSize:12,color:"var(--ghl-text-muted)",borderRight:"1px solid var(--ghl-border)"},children:s===0?"12 AM":s<12?`${s} AM`:s===12?"12 PM":`${s-12} PM`}),t.jsx("div",{style:{flex:1,padding:4},children:i.map(n=>t.jsx("div",{style:{padding:6,borderRadius:4,background:u(n.appointmentStatus),color:"white",fontSize:12,marginBottom:2},children:n.title||"Appointment"},n.id))})]},s)})})}function u(c){return{confirmed:"#22c55e",cancelled:"#ef4444",pending:"#f59e0b",completed:"#3b82f6","no-show":"#9ca3af"}[c||""]||"#4f46e5"}function W(){return t.jsx(k,{children:c=>t.jsx(R,{data:c})})}C.createRoot(document.getElementById("root")).render(A.createElement(W)); diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/contact-card-CFJe96SR.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/contact-card-CFJe96SR.js deleted file mode 100644 index 51518e5..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/contact-card-CFJe96SR.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e,A as h,g as n,f as d,R as m,a as g}from"./styles-CphAgR3l.js";function o({contact:s}){const a=s.name||`${s.firstName||""} ${s.lastName||""}`.trim()||"Unknown Contact",i=n(s.firstName,s.lastName),r=()=>{const l=[s.address1,s.city,s.state,s.postalCode,s.country].filter(Boolean);return l.length>0?l.join(", "):null};return e.jsx("div",{className:"ghl-app",children:e.jsxs("div",{className:"ghl-card",children:[e.jsx("div",{className:"ghl-card-header",children:e.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-4",children:[e.jsx("div",{className:"ghl-avatar ghl-avatar-lg",style:{background:x(a)},children:i}),e.jsxs("div",{children:[e.jsx("h2",{style:{fontSize:20,fontWeight:600,marginBottom:4},children:a}),s.companyName&&e.jsx("p",{className:"ghl-text-secondary",children:s.companyName})]})]})}),e.jsxs("div",{className:"ghl-card-body",children:[e.jsxs("div",{className:"ghl-grid ghl-grid-2",style:{gap:16},children:[s.email&&e.jsxs("div",{children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:4},children:"Email"}),e.jsx("a",{href:`mailto:${s.email}`,style:{color:"var(--ghl-primary)",textDecoration:"none"},children:s.email})]}),s.phone&&e.jsxs("div",{children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:4},children:"Phone"}),e.jsx("a",{href:`tel:${s.phone}`,style:{color:"var(--ghl-primary)",textDecoration:"none"},children:s.phone})]}),s.website&&e.jsxs("div",{children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:4},children:"Website"}),e.jsx("a",{href:s.website,target:"_blank",rel:"noopener noreferrer",style:{color:"var(--ghl-primary)",textDecoration:"none"},children:s.website})]}),s.source&&e.jsxs("div",{children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:4},children:"Source"}),e.jsx("span",{children:s.source})]}),r()&&e.jsxs("div",{style:{gridColumn:"span 2"},children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:4},children:"Address"}),e.jsx("span",{children:r()})]})]}),s.tags&&s.tags.length>0&&e.jsxs("div",{style:{marginTop:16},children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:8},children:"Tags"}),e.jsx("div",{className:"ghl-flex ghl-gap-2",style:{flexWrap:"wrap"},children:s.tags.map((l,t)=>e.jsx("span",{className:"ghl-badge ghl-badge-primary",children:l},t))})]}),s.customFields&&s.customFields.length>0&&e.jsxs("div",{style:{marginTop:16},children:[e.jsx("label",{className:"ghl-text-sm ghl-text-muted",style:{display:"block",marginBottom:8},children:"Custom Fields"}),e.jsx("div",{className:"ghl-grid ghl-grid-2",style:{gap:12},children:s.customFields.slice(0,6).map(l=>e.jsxs("div",{children:[e.jsxs("span",{className:"ghl-text-sm ghl-text-muted",children:[l.key,": "]}),e.jsx("span",{children:String(l.value)})]},l.id))})]})]}),e.jsx("div",{className:"ghl-card-footer",children:e.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-text-sm ghl-text-muted",children:[e.jsxs("span",{children:["Added: ",d(s.dateAdded)]}),e.jsxs("span",{children:["Updated: ",d(s.dateUpdated)]})]})})]})})}function x(s){let a=0;for(let r=0;re.jsx(o,{contact:s})})}m.createRoot(document.getElementById("root")).render(g.createElement(c)); diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/contact-grid-C_Uxn-WJ.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/contact-grid-C_Uxn-WJ.js deleted file mode 100644 index fc803fa..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/contact-grid-C_Uxn-WJ.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e,A as k,r as g,g as w,f as A,R as $,a as z}from"./styles-CphAgR3l.js";function D({data:a}){const[l,o]=g.useState("name"),[n,y]=g.useState("asc"),[c,b]=g.useState(1),[d,x]=g.useState(new Set),j=10,p=a.contacts||[],v=[...p].sort((s,t)=>{let i,r;switch(l){case"name":i=s.name||`${s.firstName||""} ${s.lastName||""}`.trim(),r=t.name||`${t.firstName||""} ${t.lastName||""}`.trim();break;case"email":i=s.email||"",r=t.email||"";break;case"dateAdded":i=s.dateAdded||"",r=t.dateAdded||"";break;default:return 0}const m=i.localeCompare(r);return n==="asc"?m:-m}),u=Math.ceil(v.length/j),h=v.slice((c-1)*j,c*j),N=s=>{l===s?y(n==="asc"?"desc":"asc"):(o(s),y("asc"))},C=s=>{const t=new Set(d);t.has(s)?t.delete(s):t.add(s),x(t)},S=()=>{d.size===h.length?x(new Set):x(new Set(h.map(s=>s.id)))},f=({field:s})=>e.jsx("span",{style:{marginLeft:4,opacity:l===s?1:.3},children:l===s&&n==="desc"?"↓":"↑"});return p.length===0?e.jsx("div",{className:"ghl-app",children:e.jsxs("div",{className:"ghl-empty",children:[e.jsx("div",{className:"ghl-empty-icon",children:"👥"}),e.jsx("p",{children:"No contacts found"})]})}):e.jsx("div",{className:"ghl-app",children:e.jsxs("div",{className:"ghl-card",children:[e.jsx("div",{className:"ghl-card-header",children:e.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[e.jsxs("div",{children:[e.jsx("h2",{style:{fontSize:18,fontWeight:600},children:"Contacts"}),e.jsxs("p",{className:"ghl-text-sm ghl-text-muted",children:[a.total||p.length," total contacts"]})]}),d.size>0&&e.jsx("div",{className:"ghl-flex ghl-gap-2",children:e.jsxs("span",{className:"ghl-text-sm ghl-text-secondary",children:[d.size," selected"]})})]})}),e.jsx("div",{style:{overflowX:"auto"},children:e.jsxs("table",{className:"ghl-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{style:{width:40},children:e.jsx("input",{type:"checkbox",checked:d.size===h.length&&h.length>0,onChange:S})}),e.jsxs("th",{onClick:()=>N("name"),style:{cursor:"pointer"},children:["Contact ",e.jsx(f,{field:"name"})]}),e.jsxs("th",{onClick:()=>N("email"),style:{cursor:"pointer"},children:["Email ",e.jsx(f,{field:"email"})]}),e.jsx("th",{children:"Phone"}),e.jsx("th",{children:"Tags"}),e.jsxs("th",{onClick:()=>N("dateAdded"),style:{cursor:"pointer"},children:["Added ",e.jsx(f,{field:"dateAdded"})]})]})}),e.jsx("tbody",{children:h.map(s=>{const t=s.name||`${s.firstName||""} ${s.lastName||""}`.trim()||"Unknown",i=w(s.firstName,s.lastName);return e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx("input",{type:"checkbox",checked:d.has(s.id),onChange:()=>C(s.id)})}),e.jsx("td",{children:e.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-2",children:[e.jsx("div",{className:"ghl-avatar ghl-avatar-sm",style:{background:P(t)},children:i}),e.jsxs("div",{children:[e.jsx("div",{className:"ghl-font-medium",children:t}),s.companyName&&e.jsx("div",{className:"ghl-text-sm ghl-text-muted",children:s.companyName})]})]})}),e.jsx("td",{children:s.email?e.jsx("a",{href:`mailto:${s.email}`,style:{color:"var(--ghl-primary)",textDecoration:"none"},children:s.email}):e.jsx("span",{className:"ghl-text-muted",children:"-"})}),e.jsx("td",{children:s.phone?e.jsx("a",{href:`tel:${s.phone}`,style:{color:"var(--ghl-primary)",textDecoration:"none"},children:s.phone}):e.jsx("span",{className:"ghl-text-muted",children:"-"})}),e.jsx("td",{children:e.jsxs("div",{className:"ghl-flex ghl-gap-2",style:{flexWrap:"wrap",maxWidth:200},children:[(s.tags||[]).slice(0,3).map((r,m)=>e.jsx("span",{className:"ghl-badge ghl-badge-primary",children:r},m)),(s.tags||[]).length>3&&e.jsxs("span",{className:"ghl-badge",children:["+",s.tags.length-3]})]})}),e.jsx("td",{className:"ghl-text-muted",children:A(s.dateAdded)})]},s.id)})})]})}),u>1&&e.jsx("div",{className:"ghl-card-footer",children:e.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[e.jsxs("span",{className:"ghl-text-sm ghl-text-muted",children:["Page ",c," of ",u]}),e.jsxs("div",{className:"ghl-flex ghl-gap-2",children:[e.jsx("button",{className:"ghl-btn ghl-btn-secondary ghl-btn-sm",disabled:c===1,onClick:()=>b(s=>s-1),children:"Previous"}),e.jsx("button",{className:"ghl-btn ghl-btn-secondary ghl-btn-sm",disabled:c===u,onClick:()=>b(s=>s+1),children:"Next"})]})]})})]})})}function P(a){let l=0;for(let n=0;ne.jsx(D,{data:a})})}$.createRoot(document.getElementById("root")).render(z.createElement(E)); diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/conversation-thread-DBGTC45D.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/conversation-thread-DBGTC45D.js deleted file mode 100644 index 0931e30..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/conversation-thread-DBGTC45D.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e,A as x,r as h,R as g,a as u}from"./styles-CphAgR3l.js";function m({data:t}){const{conversation:n,messages:c}=t,l=h.useRef(null),d=n.contactName||n.contact?.name||`${n.contact?.firstName||""} ${n.contact?.lastName||""}`.trim()||"Unknown Contact";h.useEffect(()=>{l.current?.scrollIntoView({behavior:"smooth"})},[]);const r=[...c||[]].sort((a,s)=>{const o=a.dateAdded?new Date(a.dateAdded).getTime():0,p=s.dateAdded?new Date(s.dateAdded).getTime():0;return o-p}),i=new Map;for(const a of r){const s=a.dateAdded?new Date(a.dateAdded).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}):"Unknown Date";i.has(s)||i.set(s,[]),i.get(s).push(a)}return e.jsx("div",{className:"ghl-app",style:{height:"100%",display:"flex",flexDirection:"column"},children:e.jsxs("div",{className:"ghl-card",style:{flex:1,display:"flex",flexDirection:"column",maxHeight:600},children:[e.jsx("div",{className:"ghl-card-header",children:e.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-4",children:[e.jsx("div",{style:{width:44,height:44,borderRadius:"50%",background:"var(--ghl-primary)",display:"flex",alignItems:"center",justifyContent:"center",color:"white",fontWeight:600},children:d.charAt(0).toUpperCase()}),e.jsxs("div",{children:[e.jsx("h2",{style:{fontSize:16,fontWeight:600,marginBottom:2},children:d}),e.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-2",children:[n.contact?.phone&&e.jsx("span",{className:"ghl-text-sm ghl-text-muted",children:n.contact.phone}),n.type&&e.jsx("span",{className:"ghl-badge",children:n.type})]})]})]})}),e.jsx("div",{style:{flex:1,overflowY:"auto",padding:16,background:"var(--ghl-bg-secondary)"},children:r.length===0?e.jsxs("div",{className:"ghl-empty",children:[e.jsx("div",{className:"ghl-empty-icon",children:"💬"}),e.jsx("p",{children:"No messages in this conversation"})]}):e.jsxs(e.Fragment,{children:[Array.from(i.entries()).map(([a,s])=>e.jsxs("div",{children:[e.jsxs("div",{style:{textAlign:"center",margin:"16px 0",position:"relative"},children:[e.jsx("span",{style:{background:"var(--ghl-bg-secondary)",padding:"4px 12px",fontSize:12,color:"var(--ghl-text-muted)",position:"relative",zIndex:1},children:a}),e.jsx("div",{style:{position:"absolute",top:"50%",left:0,right:0,height:1,background:"var(--ghl-border)",zIndex:0}})]}),s.map(o=>e.jsx(f,{message:o},o.id))]},a)),e.jsx("div",{ref:l})]})}),e.jsx("div",{className:"ghl-card-footer",children:e.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-2",children:[e.jsxs("div",{style:{flex:1,padding:"10px 14px",background:"var(--ghl-bg)",border:"1px solid var(--ghl-border)",borderRadius:20,fontSize:14,color:"var(--ghl-text-muted)"},children:["Reply to ",d,"..."]}),e.jsx("button",{className:"ghl-btn ghl-btn-primary",style:{borderRadius:20,padding:"10px 20px"},children:"Send"})]})})]})})}function f({message:t}){const n=t.direction==="outbound",c=r=>r?new Date(r).toLocaleTimeString("en-US",{hour:"numeric",minute:"2-digit"}):"",l=r=>{switch(r){case"delivered":return"✓✓";case"sent":return"✓";case"read":return"✓✓";case"failed":return"✕";default:return""}},d=r=>{switch(r){case"SMS":return"📱";case"Email":return"📧";case"WhatsApp":return"💬";case"FB":return"👤";case"GMB":return"🏢";case"Call":return"📞";default:return""}};return e.jsx("div",{style:{display:"flex",justifyContent:n?"flex-end":"flex-start",marginBottom:8},children:e.jsxs("div",{style:{maxWidth:"75%",background:n?"var(--ghl-primary)":"var(--ghl-bg)",color:n?"white":"var(--ghl-text)",padding:"10px 14px",borderRadius:n?"18px 18px 4px 18px":"18px 18px 18px 4px",boxShadow:"var(--ghl-shadow)"},children:[t.type&&e.jsxs("div",{style:{fontSize:10,marginBottom:4,opacity:.7},children:[d(t.type)," ",t.type]}),e.jsx("div",{style:{wordBreak:"break-word",whiteSpace:"pre-wrap"},children:t.body||e.jsx("span",{style:{opacity:.6,fontStyle:"italic"},children:"[No content]"})}),t.attachments&&t.attachments.length>0&&e.jsx("div",{style:{marginTop:8},children:t.attachments.map((r,i)=>e.jsx("div",{style:{padding:"6px 10px",background:n?"rgba(255,255,255,0.1)":"var(--ghl-bg-secondary)",borderRadius:8,fontSize:12,marginTop:4},children:"📎 Attachment"},i))}),e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"flex-end",gap:6,marginTop:6,fontSize:11,opacity:.7},children:[e.jsx("span",{children:c(t.dateAdded)}),n&&t.status&&e.jsx("span",{style:{color:t.status==="failed"?"#ef4444":"inherit"},children:l(t.status)})]})]})})}function y(){return e.jsx(x,{children:t=>e.jsx(m,{data:t})})}g.createRoot(document.getElementById("root")).render(u.createElement(y)); diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/invoice-preview-DphRvjHB.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/invoice-preview-DphRvjHB.js deleted file mode 100644 index 5394987..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/invoice-preview-DphRvjHB.js +++ /dev/null @@ -1 +0,0 @@ -import{j as s,A as c,c as i,f as d,b as a,R as m,a as x}from"./styles-CphAgR3l.js";function g({invoice:e}){const h=i(e.status||""),l=e.currency||"USD",n=t=>{if(!t)return null;const r=[t.address,t.city,t.state,t.postalCode,t.country].filter(Boolean);return r.length>0?r.join(", "):null};return s.jsx("div",{className:"ghl-app",children:s.jsxs("div",{className:"ghl-card",children:[s.jsx("div",{className:"ghl-card-header",style:{background:"var(--ghl-bg)"},children:s.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[s.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-4",children:[e.businessDetails?.logoUrl&&s.jsx("img",{src:e.businessDetails.logoUrl,alt:"Logo",style:{height:48,width:"auto",objectFit:"contain"}}),s.jsxs("div",{children:[s.jsx("h1",{style:{fontSize:24,fontWeight:700,color:"var(--ghl-text)"},children:"INVOICE"}),s.jsxs("p",{className:"ghl-text-muted",children:["#",e.invoiceNumber||e._id||e.id]})]})]}),s.jsx("div",{className:`ghl-badge ghl-badge-${h}`,style:{fontSize:14,padding:"6px 16px"},children:e.status?.toUpperCase()||"DRAFT"})]})}),s.jsxs("div",{className:"ghl-card-body",children:[s.jsxs("div",{className:"ghl-grid ghl-grid-2",style:{marginBottom:24},children:[s.jsxs("div",{children:[s.jsx("h3",{className:"ghl-text-sm ghl-text-muted",style:{marginBottom:8},children:"FROM"}),e.businessDetails?s.jsxs("div",{children:[s.jsx("div",{className:"ghl-font-semibold",children:e.businessDetails.name}),n(e.businessDetails)&&s.jsx("div",{className:"ghl-text-sm ghl-text-secondary",style:{marginTop:4},children:n(e.businessDetails)}),e.businessDetails.email&&s.jsx("div",{className:"ghl-text-sm ghl-text-secondary",children:e.businessDetails.email}),e.businessDetails.phone&&s.jsx("div",{className:"ghl-text-sm ghl-text-secondary",children:e.businessDetails.phone})]}):s.jsx("span",{className:"ghl-text-muted",children:"Not specified"})]}),s.jsxs("div",{children:[s.jsx("h3",{className:"ghl-text-sm ghl-text-muted",style:{marginBottom:8},children:"BILL TO"}),e.contactDetails?s.jsxs("div",{children:[s.jsx("div",{className:"ghl-font-semibold",children:e.contactDetails.name||e.contactDetails.companyName}),e.contactDetails.companyName&&e.contactDetails.name&&s.jsx("div",{className:"ghl-text-sm ghl-text-secondary",children:e.contactDetails.companyName}),n(e.contactDetails)&&s.jsx("div",{className:"ghl-text-sm ghl-text-secondary",style:{marginTop:4},children:n(e.contactDetails)}),e.contactDetails.email&&s.jsx("div",{className:"ghl-text-sm ghl-text-secondary",children:e.contactDetails.email})]}):s.jsx("span",{className:"ghl-text-muted",children:"Not specified"})]})]}),s.jsxs("div",{className:"ghl-grid ghl-grid-3",style:{marginBottom:24},children:[s.jsxs("div",{children:[s.jsx("span",{className:"ghl-text-sm ghl-text-muted",children:"Issue Date"}),s.jsx("div",{className:"ghl-font-medium",children:d(e.issueDate)})]}),s.jsxs("div",{children:[s.jsx("span",{className:"ghl-text-sm ghl-text-muted",children:"Due Date"}),s.jsx("div",{className:"ghl-font-medium",children:d(e.dueDate)})]}),e.paidAt&&s.jsxs("div",{children:[s.jsx("span",{className:"ghl-text-sm ghl-text-muted",children:"Paid Date"}),s.jsx("div",{className:"ghl-font-medium",style:{color:"var(--ghl-success)"},children:d(e.paidAt)})]})]}),s.jsx("div",{style:{marginBottom:24},children:s.jsxs("table",{className:"ghl-table",children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{style:{width:"50%"},children:"Item"}),s.jsx("th",{style:{textAlign:"center"},children:"Qty"}),s.jsx("th",{style:{textAlign:"right"},children:"Price"}),s.jsx("th",{style:{textAlign:"right"},children:"Amount"})]})}),s.jsx("tbody",{children:e.invoiceItems&&e.invoiceItems.length>0?e.invoiceItems.map((t,r)=>s.jsxs("tr",{children:[s.jsxs("td",{children:[s.jsx("div",{className:"ghl-font-medium",children:t.name||"Item"}),t.description&&s.jsx("div",{className:"ghl-text-sm ghl-text-muted",children:t.description})]}),s.jsx("td",{style:{textAlign:"center"},children:t.quantity||1}),s.jsx("td",{style:{textAlign:"right"},children:a(t.price,l)}),s.jsx("td",{style:{textAlign:"right"},children:a(t.amount,l)})]},r)):s.jsx("tr",{children:s.jsx("td",{colSpan:4,className:"ghl-text-muted",style:{textAlign:"center"},children:"No items"})})})]})}),s.jsx("div",{style:{display:"flex",justifyContent:"flex-end"},children:s.jsxs("div",{style:{width:280},children:[s.jsxs("div",{className:"ghl-flex ghl-justify-between",style:{padding:"8px 0"},children:[s.jsx("span",{className:"ghl-text-muted",children:"Subtotal"}),s.jsx("span",{children:a(e.subTotal,l)})]}),e.discount&&e.discount>0&&s.jsxs("div",{className:"ghl-flex ghl-justify-between",style:{padding:"8px 0"},children:[s.jsx("span",{className:"ghl-text-muted",children:"Discount"}),s.jsxs("span",{style:{color:"var(--ghl-success)"},children:["-",a(e.discount,l)]})]}),e.taxAmount&&e.taxAmount>0&&s.jsxs("div",{className:"ghl-flex ghl-justify-between",style:{padding:"8px 0"},children:[s.jsx("span",{className:"ghl-text-muted",children:"Tax"}),s.jsx("span",{children:a(e.taxAmount,l)})]}),s.jsxs("div",{className:"ghl-flex ghl-justify-between",style:{padding:"12px 0",marginTop:8,borderTop:"2px solid var(--ghl-border)"},children:[s.jsx("span",{className:"ghl-font-semibold",children:"Total"}),s.jsx("span",{className:"ghl-font-semibold",style:{fontSize:18},children:a(e.totalAmount,l)})]}),e.amountDue!==void 0&&e.amountDue!==e.totalAmount&&s.jsxs("div",{className:"ghl-flex ghl-justify-between",style:{padding:"12px 16px",marginTop:8,background:e.amountDue===0?"rgba(34, 197, 94, 0.1)":"rgba(239, 68, 68, 0.1)",borderRadius:"var(--ghl-radius)"},children:[s.jsx("span",{className:"ghl-font-semibold",children:"Amount Due"}),s.jsx("span",{className:"ghl-font-semibold",style:{fontSize:18,color:e.amountDue===0?"var(--ghl-success)":"var(--ghl-danger)"},children:a(e.amountDue,l)})]}),e.amountPaid!==void 0&&e.amountPaid>0&&s.jsxs("div",{className:"ghl-flex ghl-justify-between",style:{padding:"8px 0",marginTop:8},children:[s.jsx("span",{className:"ghl-text-muted",children:"Amount Paid"}),s.jsx("span",{style:{color:"var(--ghl-success)"},children:a(e.amountPaid,l)})]})]})})]}),s.jsx("div",{className:"ghl-card-footer",children:s.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center ghl-text-sm ghl-text-muted",children:[s.jsxs("span",{children:["Created: ",d(e.createdAt),e.updatedAt&&` | Updated: ${d(e.updatedAt)}`]}),e.sentAt&&s.jsxs("span",{children:["Sent: ",d(e.sentAt)]})]})})]})})}function o(){return s.jsx(c,{children:e=>s.jsx(g,{invoice:e})})}m.createRoot(document.getElementById("root")).render(x.createElement(o)); diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/opportunity-kanban-CSzRcmdW.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/opportunity-kanban-CSzRcmdW.js deleted file mode 100644 index e71da81..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/opportunity-kanban-CSzRcmdW.js +++ /dev/null @@ -1 +0,0 @@ -import{j as e,A as u,b as g,f as p,R as v,a as j}from"./styles-CphAgR3l.js";function f({data:s}){const{pipeline:n,opportunities:l,stages:h}=s,c=[...h||[]].sort((t,a)=>(t.position||0)-(a.position||0)),r=new Map;for(const t of c)r.set(t.id,[]);for(const t of l||[]){const a=r.get(t.pipelineStageId||"");a&&a.push(t)}const m=t=>{const a=r.get(t)||[],i=a.length,d=a.reduce((o,x)=>o+(x.monetaryValue||0),0);return{count:i,value:d}};return n?e.jsxs("div",{className:"ghl-app",children:[e.jsxs("div",{style:{marginBottom:16},children:[e.jsx("h2",{style:{fontSize:20,fontWeight:600,marginBottom:4},children:n.name}),e.jsxs("p",{className:"ghl-text-sm ghl-text-muted",children:[l?.length||0," opportunities | ",c.length," stages"]})]}),e.jsx("div",{style:{display:"flex",gap:16,overflowX:"auto",paddingBottom:16},children:c.map(t=>{const{count:a,value:i}=m(t.id),d=r.get(t.id)||[];return e.jsxs("div",{style:{flex:"0 0 280px",display:"flex",flexDirection:"column",maxHeight:500},children:[e.jsxs("div",{style:{padding:"12px 16px",background:"var(--ghl-bg-secondary)",borderRadius:"var(--ghl-radius) var(--ghl-radius) 0 0",border:"1px solid var(--ghl-border)",borderBottom:"none"},children:[e.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[e.jsx("span",{className:"ghl-font-semibold",children:t.name}),e.jsx("span",{className:"ghl-badge",children:a})]}),i>0&&e.jsx("div",{className:"ghl-text-sm ghl-text-muted",style:{marginTop:4},children:g(i)})]}),e.jsx("div",{style:{flex:1,padding:8,background:"var(--ghl-bg-tertiary)",borderRadius:"0 0 var(--ghl-radius) var(--ghl-radius)",border:"1px solid var(--ghl-border)",borderTop:"none",overflowY:"auto",minHeight:200},children:d.length===0?e.jsx("div",{style:{padding:20,textAlign:"center",color:"var(--ghl-text-muted)",fontSize:13},children:"No opportunities"}):e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:8},children:d.map(o=>e.jsx(b,{opportunity:o},o.id))})})]},t.id)})}),e.jsx("div",{className:"ghl-card",style:{marginTop:16},children:e.jsx("div",{className:"ghl-card-body",children:e.jsxs("div",{className:"ghl-flex ghl-justify-between",children:[e.jsxs("div",{children:[e.jsx("span",{className:"ghl-text-muted",children:"Total Opportunities"}),e.jsx("div",{className:"ghl-font-semibold",style:{fontSize:20},children:l?.length||0})]}),e.jsxs("div",{style:{textAlign:"right"},children:[e.jsx("span",{className:"ghl-text-muted",children:"Total Pipeline Value"}),e.jsx("div",{className:"ghl-font-semibold",style:{fontSize:20,color:"var(--ghl-success)"},children:g(l?.reduce((t,a)=>t+(a.monetaryValue||0),0)||0)})]})]})})})]}):e.jsx("div",{className:"ghl-app",children:e.jsxs("div",{className:"ghl-empty",children:[e.jsx("div",{className:"ghl-empty-icon",children:"📊"}),e.jsx("p",{children:"Pipeline not found"})]})})}function b({opportunity:s}){const n=s.contact?.name||`${s.contact?.firstName||""} ${s.contact?.lastName||""}`.trim()||"Unknown Contact",l={open:"var(--ghl-primary)",won:"var(--ghl-success)",lost:"var(--ghl-danger)",abandoned:"var(--ghl-warning)"};return e.jsxs("div",{style:{background:"var(--ghl-bg)",borderRadius:"var(--ghl-radius)",padding:12,boxShadow:"var(--ghl-shadow)",border:"1px solid var(--ghl-border)"},children:[e.jsx("div",{className:"ghl-font-medium",style:{marginBottom:8},children:s.name}),e.jsxs("div",{className:"ghl-flex ghl-items-center ghl-gap-2",style:{marginBottom:8},children:[e.jsx("span",{style:{width:24,height:24,borderRadius:"50%",background:"var(--ghl-bg-tertiary)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:10},children:"👤"}),e.jsx("span",{className:"ghl-text-sm",children:n})]}),e.jsxs("div",{className:"ghl-flex ghl-justify-between ghl-items-center",children:[s.monetaryValue?e.jsx("span",{className:"ghl-font-semibold",style:{color:"var(--ghl-success)"},children:g(s.monetaryValue)}):e.jsx("span",{className:"ghl-text-muted ghl-text-sm",children:"No value"}),s.status&&e.jsx("span",{className:"ghl-badge",style:{background:`${l[s.status]||"var(--ghl-bg-tertiary)"}20`,color:l[s.status]||"var(--ghl-text-muted)"},children:s.status})]}),s.dateAdded&&e.jsxs("div",{className:"ghl-text-sm ghl-text-muted",style:{marginTop:8},children:["Added ",p(s.dateAdded)]})]})}function y(){return e.jsx(u,{children:s=>e.jsx(f,{data:s})})}v.createRoot(document.getElementById("root")).render(j.createElement(y)); diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/style-BaFxk78P.css b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/style-BaFxk78P.css deleted file mode 100644 index e8750e8..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/style-BaFxk78P.css +++ /dev/null @@ -1 +0,0 @@ -:root{--ghl-primary: #4f46e5;--ghl-primary-hover: #4338ca;--ghl-success: #22c55e;--ghl-warning: #f59e0b;--ghl-danger: #ef4444;--ghl-info: #3b82f6;--ghl-bg: #ffffff;--ghl-bg-secondary: #f9fafb;--ghl-bg-tertiary: #f3f4f6;--ghl-text: #111827;--ghl-text-secondary: #6b7280;--ghl-text-muted: #9ca3af;--ghl-border: #e5e7eb;--ghl-border-dark: #d1d5db;--ghl-shadow: 0 1px 3px rgba(0, 0, 0, .1);--ghl-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, .1);--ghl-radius: 8px;--ghl-radius-lg: 12px}*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:14px;line-height:1.5;color:var(--ghl-text);background:var(--ghl-bg)}.ghl-app{padding:16px;max-width:100%;overflow-x:hidden}.ghl-card{background:var(--ghl-bg);border:1px solid var(--ghl-border);border-radius:var(--ghl-radius-lg);box-shadow:var(--ghl-shadow);overflow:hidden}.ghl-card-header{padding:16px;border-bottom:1px solid var(--ghl-border);background:var(--ghl-bg-secondary)}.ghl-card-body{padding:16px}.ghl-card-footer{padding:12px 16px;border-top:1px solid var(--ghl-border);background:var(--ghl-bg-secondary)}.ghl-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:8px 16px;font-size:14px;font-weight:500;border-radius:var(--ghl-radius);border:1px solid transparent;cursor:pointer;transition:all .15s ease}.ghl-btn-primary{background:var(--ghl-primary);color:#fff}.ghl-btn-primary:hover{background:var(--ghl-primary-hover)}.ghl-btn-secondary{background:var(--ghl-bg);color:var(--ghl-text);border-color:var(--ghl-border)}.ghl-btn-secondary:hover{background:var(--ghl-bg-secondary)}.ghl-btn-sm{padding:4px 10px;font-size:12px}.ghl-badge{display:inline-flex;align-items:center;padding:2px 8px;font-size:12px;font-weight:500;border-radius:9999px;background:var(--ghl-bg-tertiary);color:var(--ghl-text-secondary)}.ghl-badge-primary{background:#4f46e51a;color:var(--ghl-primary)}.ghl-badge-success{background:#22c55e1a;color:var(--ghl-success)}.ghl-badge-warning{background:#f59e0b1a;color:var(--ghl-warning)}.ghl-badge-danger{background:#ef44441a;color:var(--ghl-danger)}.ghl-avatar{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;background:var(--ghl-primary);color:#fff;font-weight:600;font-size:16px}.ghl-avatar-lg{width:64px;height:64px;font-size:24px}.ghl-avatar-sm{width:32px;height:32px;font-size:12px}.ghl-table{width:100%;border-collapse:collapse}.ghl-table th,.ghl-table td{padding:12px;text-align:left;border-bottom:1px solid var(--ghl-border)}.ghl-table th{font-weight:600;background:var(--ghl-bg-secondary);color:var(--ghl-text-secondary);font-size:12px;text-transform:uppercase;letter-spacing:.05em}.ghl-table tr:hover{background:var(--ghl-bg-secondary)}.ghl-grid{display:grid;gap:16px}.ghl-grid-2{grid-template-columns:repeat(2,1fr)}.ghl-grid-3{grid-template-columns:repeat(3,1fr)}.ghl-grid-4{grid-template-columns:repeat(4,1fr)}.ghl-flex{display:flex}.ghl-flex-col{flex-direction:column}.ghl-items-center{align-items:center}.ghl-justify-between{justify-content:space-between}.ghl-gap-2{gap:8px}.ghl-gap-4{gap:16px}.ghl-text-sm{font-size:12px}.ghl-text-lg{font-size:18px}.ghl-text-muted{color:var(--ghl-text-muted)}.ghl-text-secondary{color:var(--ghl-text-secondary)}.ghl-font-medium{font-weight:500}.ghl-font-semibold{font-weight:600}.ghl-status-paid{color:var(--ghl-success)}.ghl-status-pending{color:var(--ghl-warning)}.ghl-status-overdue{color:var(--ghl-danger)}.ghl-status-draft{color:var(--ghl-text-muted)}.ghl-loading{display:flex;align-items:center;justify-content:center;padding:40px;color:var(--ghl-text-muted)}.ghl-spinner{width:24px;height:24px;border:2px solid var(--ghl-border);border-top-color:var(--ghl-primary);border-radius:50%;animation:spin .8s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.ghl-empty{text-align:center;padding:40px;color:var(--ghl-text-muted)}.ghl-empty-icon{font-size:48px;margin-bottom:16px;opacity:.5} diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/styles-CphAgR3l.js b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/styles-CphAgR3l.js deleted file mode 100644 index 356d2c8..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/assets/styles-CphAgR3l.js +++ /dev/null @@ -1,9 +0,0 @@ -(function(){const P=document.createElement("link").relList;if(P&&P.supports&&P.supports("modulepreload"))return;for(const X of document.querySelectorAll('link[rel="modulepreload"]'))o(X);new MutationObserver(X=>{for(const L of X)if(L.type==="childList")for(const vl of L.addedNodes)vl.tagName==="LINK"&&vl.rel==="modulepreload"&&o(vl)}).observe(document,{childList:!0,subtree:!0});function w(X){const L={};return X.integrity&&(L.integrity=X.integrity),X.referrerPolicy&&(L.referrerPolicy=X.referrerPolicy),X.crossOrigin==="use-credentials"?L.credentials="include":X.crossOrigin==="anonymous"?L.credentials="omit":L.credentials="same-origin",L}function o(X){if(X.ep)return;X.ep=!0;const L=w(X);fetch(X.href,L)}})();function rs(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var ni={exports:{}},C={};var ds;function wd(){if(ds)return C;ds=1;var r=Symbol.for("react.transitional.element"),P=Symbol.for("react.portal"),w=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),X=Symbol.for("react.profiler"),L=Symbol.for("react.consumer"),vl=Symbol.for("react.context"),Ol=Symbol.for("react.forward_ref"),p=Symbol.for("react.suspense"),A=Symbol.for("react.memo"),W=Symbol.for("react.lazy"),R=Symbol.for("react.activity"),sl=Symbol.iterator;function wl(v){return v===null||typeof v!="object"?null:(v=sl&&v[sl]||v["@@iterator"],typeof v=="function"?v:null)}var Bl={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},ql=Object.assign,Dt={};function Wl(v,E,O){this.props=v,this.context=E,this.refs=Dt,this.updater=O||Bl}Wl.prototype.isReactComponent={},Wl.prototype.setState=function(v,E){if(typeof v!="object"&&typeof v!="function"&&v!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,v,E,"setState")},Wl.prototype.forceUpdate=function(v){this.updater.enqueueForceUpdate(this,v,"forceUpdate")};function Wt(){}Wt.prototype=Wl.prototype;function Nl(v,E,O){this.props=v,this.context=E,this.refs=Dt,this.updater=O||Bl}var nt=Nl.prototype=new Wt;nt.constructor=Nl,ql(nt,Wl.prototype),nt.isPureReactComponent=!0;var Tt=Array.isArray;function Gl(){}var K={H:null,A:null,T:null,S:null},Xl=Object.prototype.hasOwnProperty;function Et(v,E,O){var D=O.ref;return{$$typeof:r,type:v,key:E,ref:D!==void 0?D:null,props:O}}function ju(v,E){return Et(v.type,E,v.props)}function At(v){return typeof v=="object"&&v!==null&&v.$$typeof===r}function Ql(v){var E={"=":"=0",":":"=2"};return"$"+v.replace(/[=:]/g,function(O){return E[O]})}var Tu=/\/+/g;function Ut(v,E){return typeof v=="object"&&v!==null&&v.key!=null?Ql(""+v.key):E.toString(36)}function St(v){switch(v.status){case"fulfilled":return v.value;case"rejected":throw v.reason;default:switch(typeof v.status=="string"?v.then(Gl,Gl):(v.status="pending",v.then(function(E){v.status==="pending"&&(v.status="fulfilled",v.value=E)},function(E){v.status==="pending"&&(v.status="rejected",v.reason=E)})),v.status){case"fulfilled":return v.value;case"rejected":throw v.reason}}throw v}function b(v,E,O,D,Y){var Q=typeof v;(Q==="undefined"||Q==="boolean")&&(v=null);var I=!1;if(v===null)I=!0;else switch(Q){case"bigint":case"string":case"number":I=!0;break;case"object":switch(v.$$typeof){case r:case P:I=!0;break;case W:return I=v._init,b(I(v._payload),E,O,D,Y)}}if(I)return Y=Y(v),I=D===""?"."+Ut(v,0):D,Tt(Y)?(O="",I!=null&&(O=I.replace(Tu,"$&/")+"/"),b(Y,E,O,"",function(Oa){return Oa})):Y!=null&&(At(Y)&&(Y=ju(Y,O+(Y.key==null||v&&v.key===Y.key?"":(""+Y.key).replace(Tu,"$&/")+"/")+I)),E.push(Y)),1;I=0;var Cl=D===""?".":D+":";if(Tt(v))for(var ol=0;ol>>1,fl=b[ul];if(0>>1;ulX(O,q))DX(Y,O)?(b[ul]=Y,b[D]=q,ul=D):(b[ul]=O,b[E]=q,ul=E);else if(DX(Y,q))b[ul]=Y,b[D]=q,ul=D;else break l}}return _}function X(b,_){var q=b.sortIndex-_.sortIndex;return q!==0?q:b.id-_.id}if(r.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var L=performance;r.unstable_now=function(){return L.now()}}else{var vl=Date,Ol=vl.now();r.unstable_now=function(){return vl.now()-Ol}}var p=[],A=[],W=1,R=null,sl=3,wl=!1,Bl=!1,ql=!1,Dt=!1,Wl=typeof setTimeout=="function"?setTimeout:null,Wt=typeof clearTimeout=="function"?clearTimeout:null,Nl=typeof setImmediate<"u"?setImmediate:null;function nt(b){for(var _=w(A);_!==null;){if(_.callback===null)o(A);else if(_.startTime<=b)o(A),_.sortIndex=_.expirationTime,P(p,_);else break;_=w(A)}}function Tt(b){if(ql=!1,nt(b),!Bl)if(w(p)!==null)Bl=!0,Gl||(Gl=!0,Ql());else{var _=w(A);_!==null&&St(Tt,_.startTime-b)}}var Gl=!1,K=-1,Xl=5,Et=-1;function ju(){return Dt?!0:!(r.unstable_now()-Etb&&ju());){var ul=R.callback;if(typeof ul=="function"){R.callback=null,sl=R.priorityLevel;var fl=ul(R.expirationTime<=b);if(b=r.unstable_now(),typeof fl=="function"){R.callback=fl,nt(b),_=!0;break t}R===w(p)&&o(p),nt(b)}else o(p);R=w(p)}if(R!==null)_=!0;else{var v=w(A);v!==null&&St(Tt,v.startTime-b),_=!1}}break l}finally{R=null,sl=q,wl=!1}_=void 0}}finally{_?Ql():Gl=!1}}}var Ql;if(typeof Nl=="function")Ql=function(){Nl(At)};else if(typeof MessageChannel<"u"){var Tu=new MessageChannel,Ut=Tu.port2;Tu.port1.onmessage=At,Ql=function(){Ut.postMessage(null)}}else Ql=function(){Wl(At,0)};function St(b,_){K=Wl(function(){b(r.unstable_now())},_)}r.unstable_IdlePriority=5,r.unstable_ImmediatePriority=1,r.unstable_LowPriority=4,r.unstable_NormalPriority=3,r.unstable_Profiling=null,r.unstable_UserBlockingPriority=2,r.unstable_cancelCallback=function(b){b.callback=null},r.unstable_forceFrameRate=function(b){0>b||125ul?(b.sortIndex=q,P(A,b),w(p)===null&&b===w(A)&&(ql?(Wt(K),K=-1):ql=!0,St(Tt,q-ul))):(b.sortIndex=fl,P(p,b),Bl||wl||(Bl=!0,Gl||(Gl=!0,Ql()))),b},r.unstable_shouldYield=ju,r.unstable_wrapCallback=function(b){var _=sl;return function(){var q=sl;sl=_;try{return b.apply(this,arguments)}finally{sl=q}}}})(ii)),ii}var Ss;function $d(){return Ss||(Ss=1,ci.exports=Wd()),ci.exports}var yi={exports:{}},Rl={};var gs;function Fd(){if(gs)return Rl;gs=1;var r=si();function P(p){var A="https://react.dev/errors/"+p;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(P){console.error(P)}}return r(),yi.exports=Fd(),yi.exports}var zs;function Id(){if(zs)return be;zs=1;var r=$d(),P=si(),w=kd();function o(l){var t="https://react.dev/errors/"+l;if(1fl||(l.current=ul[fl],ul[fl]=null,fl--)}function O(l,t){fl++,ul[fl]=l.current,l.current=t}var D=v(null),Y=v(null),Q=v(null),I=v(null);function Cl(l,t){switch(O(Q,t),O(Y,l),O(D,null),t.nodeType){case 9:case 11:l=(l=t.documentElement)&&(l=l.namespaceURI)?Bv(l):0;break;default:if(l=t.tagName,t=t.namespaceURI)t=Bv(t),l=Gv(t,l);else switch(l){case"svg":l=1;break;case"math":l=2;break;default:l=0}}E(D),O(D,l)}function ol(){E(D),E(Y),E(Q)}function Oa(l){l.memoizedState!==null&&O(I,l);var t=D.current,u=Gv(t,l.type);t!==u&&(O(Y,l),O(D,u))}function Ee(l){Y.current===l&&(E(D),E(Y)),I.current===l&&(E(I),he._currentValue=q)}var jn,mi;function Eu(l){if(jn===void 0)try{throw Error()}catch(u){var t=u.stack.trim().match(/\n( *(at )?)/);jn=t&&t[1]||"",mi=-1)":-1e||i[a]!==d[e]){var g=` -`+i[a].replace(" at new "," at ");return l.displayName&&g.includes("")&&(g=g.replace("",l.displayName)),g}while(1<=a&&0<=e);break}}}finally{Zn=!1,Error.prepareStackTrace=u}return(u=l?l.displayName||l.name:"")?Eu(u):""}function _s(l,t){switch(l.tag){case 26:case 27:case 5:return Eu(l.type);case 16:return Eu("Lazy");case 13:return l.child!==t&&t!==null?Eu("Suspense Fallback"):Eu("Suspense");case 19:return Eu("SuspenseList");case 0:case 15:return Vn(l.type,!1);case 11:return Vn(l.type.render,!1);case 1:return Vn(l.type,!0);case 31:return Eu("Activity");default:return""}}function di(l){try{var t="",u=null;do t+=_s(l,u),u=l,l=l.return;while(l);return t}catch(a){return` -Error generating stack: `+a.message+` -`+a.stack}}var xn=Object.prototype.hasOwnProperty,Ln=r.unstable_scheduleCallback,Kn=r.unstable_cancelCallback,Os=r.unstable_shouldYield,Ms=r.unstable_requestPaint,$l=r.unstable_now,Ds=r.unstable_getCurrentPriorityLevel,hi=r.unstable_ImmediatePriority,oi=r.unstable_UserBlockingPriority,Ae=r.unstable_NormalPriority,Us=r.unstable_LowPriority,Si=r.unstable_IdlePriority,ps=r.log,Hs=r.unstable_setDisableYieldValue,Ma=null,Fl=null;function $t(l){if(typeof ps=="function"&&Hs(l),Fl&&typeof Fl.setStrictMode=="function")try{Fl.setStrictMode(Ma,l)}catch{}}var kl=Math.clz32?Math.clz32:qs,Ns=Math.log,Rs=Math.LN2;function qs(l){return l>>>=0,l===0?32:31-(Ns(l)/Rs|0)|0}var re=256,_e=262144,Oe=4194304;function Au(l){var t=l&42;if(t!==0)return t;switch(l&-l){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return l&261888;case 262144:case 524288:case 1048576:case 2097152:return l&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return l&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return l}}function Me(l,t,u){var a=l.pendingLanes;if(a===0)return 0;var e=0,n=l.suspendedLanes,f=l.pingedLanes;l=l.warmLanes;var c=a&134217727;return c!==0?(a=c&~n,a!==0?e=Au(a):(f&=c,f!==0?e=Au(f):u||(u=c&~l,u!==0&&(e=Au(u))))):(c=a&~n,c!==0?e=Au(c):f!==0?e=Au(f):u||(u=a&~l,u!==0&&(e=Au(u)))),e===0?0:t!==0&&t!==e&&(t&n)===0&&(n=e&-e,u=t&-t,n>=u||n===32&&(u&4194048)!==0)?t:e}function Da(l,t){return(l.pendingLanes&~(l.suspendedLanes&~l.pingedLanes)&t)===0}function Cs(l,t){switch(l){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function gi(){var l=Oe;return Oe<<=1,(Oe&62914560)===0&&(Oe=4194304),l}function Jn(l){for(var t=[],u=0;31>u;u++)t.push(l);return t}function Ua(l,t){l.pendingLanes|=t,t!==268435456&&(l.suspendedLanes=0,l.pingedLanes=0,l.warmLanes=0)}function Ys(l,t,u,a,e,n){var f=l.pendingLanes;l.pendingLanes=u,l.suspendedLanes=0,l.pingedLanes=0,l.warmLanes=0,l.expiredLanes&=u,l.entangledLanes&=u,l.errorRecoveryDisabledLanes&=u,l.shellSuspendCounter=0;var c=l.entanglements,i=l.expirationTimes,d=l.hiddenUpdates;for(u=f&~u;0"u")return null;try{return l.activeElement||l.body}catch{return l.body}}var Zs=/[\n"\\]/g;function ct(l){return l.replace(Zs,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function In(l,t,u,a,e,n,f,c){l.name="",f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"?l.type=f:l.removeAttribute("type"),t!=null?f==="number"?(t===0&&l.value===""||l.value!=t)&&(l.value=""+ft(t)):l.value!==""+ft(t)&&(l.value=""+ft(t)):f!=="submit"&&f!=="reset"||l.removeAttribute("value"),t!=null?Pn(l,f,ft(t)):u!=null?Pn(l,f,ft(u)):a!=null&&l.removeAttribute("value"),e==null&&n!=null&&(l.defaultChecked=!!n),e!=null&&(l.checked=e&&typeof e!="function"&&typeof e!="symbol"),c!=null&&typeof c!="function"&&typeof c!="symbol"&&typeof c!="boolean"?l.name=""+ft(c):l.removeAttribute("name")}function Hi(l,t,u,a,e,n,f,c){if(n!=null&&typeof n!="function"&&typeof n!="symbol"&&typeof n!="boolean"&&(l.type=n),t!=null||u!=null){if(!(n!=="submit"&&n!=="reset"||t!=null)){kn(l);return}u=u!=null?""+ft(u):"",t=t!=null?""+ft(t):u,c||t===l.value||(l.value=t),l.defaultValue=t}a=a??e,a=typeof a!="function"&&typeof a!="symbol"&&!!a,l.checked=c?l.checked:!!a,l.defaultChecked=!!a,f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"&&(l.name=f),kn(l)}function Pn(l,t,u){t==="number"&&pe(l.ownerDocument)===l||l.defaultValue===""+u||(l.defaultValue=""+u)}function Ju(l,t,u,a){if(l=l.options,t){t={};for(var e=0;e"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ef=!1;if(Nt)try{var Ra={};Object.defineProperty(Ra,"passive",{get:function(){ef=!0}}),window.addEventListener("test",Ra,Ra),window.removeEventListener("test",Ra,Ra)}catch{ef=!1}var kt=null,nf=null,Ne=null;function Gi(){if(Ne)return Ne;var l,t=nf,u=t.length,a,e="value"in kt?kt.value:kt.textContent,n=e.length;for(l=0;l=Ya),xi=" ",Li=!1;function Ki(l,t){switch(l){case"keyup":return om.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ji(l){return l=l.detail,typeof l=="object"&&"data"in l?l.data:null}var Fu=!1;function gm(l,t){switch(l){case"compositionend":return Ji(t);case"keypress":return t.which!==32?null:(Li=!0,xi);case"textInput":return l=t.data,l===xi&&Li?null:l;default:return null}}function bm(l,t){if(Fu)return l==="compositionend"||!sf&&Ki(l,t)?(l=Gi(),Ne=nf=kt=null,Fu=!1,l):null;switch(l){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:u,offset:t-l};l=a}l:{for(;u;){if(u.nextSibling){u=u.nextSibling;break l}u=u.parentNode}u=void 0}u=l0(u)}}function u0(l,t){return l&&t?l===t?!0:l&&l.nodeType===3?!1:t&&t.nodeType===3?u0(l,t.parentNode):"contains"in l?l.contains(t):l.compareDocumentPosition?!!(l.compareDocumentPosition(t)&16):!1:!1}function a0(l){l=l!=null&&l.ownerDocument!=null&&l.ownerDocument.defaultView!=null?l.ownerDocument.defaultView:window;for(var t=pe(l.document);t instanceof l.HTMLIFrameElement;){try{var u=typeof t.contentWindow.location.href=="string"}catch{u=!1}if(u)l=t.contentWindow;else break;t=pe(l.document)}return t}function hf(l){var t=l&&l.nodeName&&l.nodeName.toLowerCase();return t&&(t==="input"&&(l.type==="text"||l.type==="search"||l.type==="tel"||l.type==="url"||l.type==="password")||t==="textarea"||l.contentEditable==="true")}var Mm=Nt&&"documentMode"in document&&11>=document.documentMode,ku=null,of=null,Qa=null,Sf=!1;function e0(l,t,u){var a=u.window===u?u.document:u.nodeType===9?u:u.ownerDocument;Sf||ku==null||ku!==pe(a)||(a=ku,"selectionStart"in a&&hf(a)?a={start:a.selectionStart,end:a.selectionEnd}:(a=(a.ownerDocument&&a.ownerDocument.defaultView||window).getSelection(),a={anchorNode:a.anchorNode,anchorOffset:a.anchorOffset,focusNode:a.focusNode,focusOffset:a.focusOffset}),Qa&&Xa(Qa,a)||(Qa=a,a=On(of,"onSelect"),0>=f,e-=f,rt=1<<32-kl(t)+e|u<G?(x=U,U=null):x=U.sibling;var F=h(s,U,m[G],z);if(F===null){U===null&&(U=x);break}l&&U&&F.alternate===null&&t(s,U),y=n(F,y,G),$===null?H=F:$.sibling=F,$=F,U=x}if(G===m.length)return u(s,U),J&&qt(s,G),H;if(U===null){for(;GG?(x=U,U=null):x=U.sibling;var zu=h(s,U,F.value,z);if(zu===null){U===null&&(U=x);break}l&&U&&zu.alternate===null&&t(s,U),y=n(zu,y,G),$===null?H=zu:$.sibling=zu,$=zu,U=x}if(F.done)return u(s,U),J&&qt(s,G),H;if(U===null){for(;!F.done;G++,F=m.next())F=T(s,F.value,z),F!==null&&(y=n(F,y,G),$===null?H=F:$.sibling=F,$=F);return J&&qt(s,G),H}for(U=a(U);!F.done;G++,F=m.next())F=S(U,s,G,F.value,z),F!==null&&(l&&F.alternate!==null&&U.delete(F.key===null?G:F.key),y=n(F,y,G),$===null?H=F:$.sibling=F,$=F);return l&&U.forEach(function(Jd){return t(s,Jd)}),J&&qt(s,G),H}function nl(s,y,m,z){if(typeof m=="object"&&m!==null&&m.type===ql&&m.key===null&&(m=m.props.children),typeof m=="object"&&m!==null){switch(m.$$typeof){case wl:l:{for(var H=m.key;y!==null;){if(y.key===H){if(H=m.type,H===ql){if(y.tag===7){u(s,y.sibling),z=e(y,m.props.children),z.return=s,s=z;break l}}else if(y.elementType===H||typeof H=="object"&&H!==null&&H.$$typeof===Xl&&qu(H)===y.type){u(s,y.sibling),z=e(y,m.props),Ka(z,m),z.return=s,s=z;break l}u(s,y);break}else t(s,y);y=y.sibling}m.type===ql?(z=Uu(m.props.children,s.mode,z,m.key),z.return=s,s=z):(z=Ze(m.type,m.key,m.props,null,s.mode,z),Ka(z,m),z.return=s,s=z)}return f(s);case Bl:l:{for(H=m.key;y!==null;){if(y.key===H)if(y.tag===4&&y.stateNode.containerInfo===m.containerInfo&&y.stateNode.implementation===m.implementation){u(s,y.sibling),z=e(y,m.children||[]),z.return=s,s=z;break l}else{u(s,y);break}else t(s,y);y=y.sibling}z=rf(m,s.mode,z),z.return=s,s=z}return f(s);case Xl:return m=qu(m),nl(s,y,m,z)}if(St(m))return M(s,y,m,z);if(Ql(m)){if(H=Ql(m),typeof H!="function")throw Error(o(150));return m=H.call(m),N(s,y,m,z)}if(typeof m.then=="function")return nl(s,y,We(m),z);if(m.$$typeof===Nl)return nl(s,y,Le(s,m),z);$e(s,m)}return typeof m=="string"&&m!==""||typeof m=="number"||typeof m=="bigint"?(m=""+m,y!==null&&y.tag===6?(u(s,y.sibling),z=e(y,m),z.return=s,s=z):(u(s,y),z=Af(m,s.mode,z),z.return=s,s=z),f(s)):u(s,y)}return function(s,y,m,z){try{La=0;var H=nl(s,y,m,z);return ia=null,H}catch(U){if(U===ca||U===Je)throw U;var $=Pl(29,U,null,s.mode);return $.lanes=z,$.return=s,$}}}var Yu=D0(!0),U0=D0(!1),uu=!1;function Yf(l){l.updateQueue={baseState:l.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Bf(l,t){l=l.updateQueue,t.updateQueue===l&&(t.updateQueue={baseState:l.baseState,firstBaseUpdate:l.firstBaseUpdate,lastBaseUpdate:l.lastBaseUpdate,shared:l.shared,callbacks:null})}function au(l){return{lane:l,tag:0,payload:null,callback:null,next:null}}function eu(l,t,u){var a=l.updateQueue;if(a===null)return null;if(a=a.shared,(k&2)!==0){var e=a.pending;return e===null?t.next=t:(t.next=e.next,e.next=t),a.pending=t,t=je(l),s0(l,null,u),t}return Qe(l,a,t,u),je(l)}function Ja(l,t,u){if(t=t.updateQueue,t!==null&&(t=t.shared,(u&4194048)!==0)){var a=t.lanes;a&=l.pendingLanes,u|=a,t.lanes=u,zi(l,u)}}function Gf(l,t){var u=l.updateQueue,a=l.alternate;if(a!==null&&(a=a.updateQueue,u===a)){var e=null,n=null;if(u=u.firstBaseUpdate,u!==null){do{var f={lane:u.lane,tag:u.tag,payload:u.payload,callback:null,next:null};n===null?e=n=f:n=n.next=f,u=u.next}while(u!==null);n===null?e=n=t:n=n.next=t}else e=n=t;u={baseState:a.baseState,firstBaseUpdate:e,lastBaseUpdate:n,shared:a.shared,callbacks:a.callbacks},l.updateQueue=u;return}l=u.lastBaseUpdate,l===null?u.firstBaseUpdate=t:l.next=t,u.lastBaseUpdate=t}var Xf=!1;function wa(){if(Xf){var l=fa;if(l!==null)throw l}}function Wa(l,t,u,a){Xf=!1;var e=l.updateQueue;uu=!1;var n=e.firstBaseUpdate,f=e.lastBaseUpdate,c=e.shared.pending;if(c!==null){e.shared.pending=null;var i=c,d=i.next;i.next=null,f===null?n=d:f.next=d,f=i;var g=l.alternate;g!==null&&(g=g.updateQueue,c=g.lastBaseUpdate,c!==f&&(c===null?g.firstBaseUpdate=d:c.next=d,g.lastBaseUpdate=i))}if(n!==null){var T=e.baseState;f=0,g=d=i=null,c=n;do{var h=c.lane&-536870913,S=h!==c.lane;if(S?(V&h)===h:(a&h)===h){h!==0&&h===na&&(Xf=!0),g!==null&&(g=g.next={lane:0,tag:c.tag,payload:c.payload,callback:null,next:null});l:{var M=l,N=c;h=t;var nl=u;switch(N.tag){case 1:if(M=N.payload,typeof M=="function"){T=M.call(nl,T,h);break l}T=M;break l;case 3:M.flags=M.flags&-65537|128;case 0:if(M=N.payload,h=typeof M=="function"?M.call(nl,T,h):M,h==null)break l;T=R({},T,h);break l;case 2:uu=!0}}h=c.callback,h!==null&&(l.flags|=64,S&&(l.flags|=8192),S=e.callbacks,S===null?e.callbacks=[h]:S.push(h))}else S={lane:h,tag:c.tag,payload:c.payload,callback:c.callback,next:null},g===null?(d=g=S,i=T):g=g.next=S,f|=h;if(c=c.next,c===null){if(c=e.shared.pending,c===null)break;S=c,c=S.next,S.next=null,e.lastBaseUpdate=S,e.shared.pending=null}}while(!0);g===null&&(i=T),e.baseState=i,e.firstBaseUpdate=d,e.lastBaseUpdate=g,n===null&&(e.shared.lanes=0),yu|=f,l.lanes=f,l.memoizedState=T}}function p0(l,t){if(typeof l!="function")throw Error(o(191,l));l.call(t)}function H0(l,t){var u=l.callbacks;if(u!==null)for(l.callbacks=null,l=0;ln?n:8;var f=b.T,c={};b.T=c,ac(l,!1,t,u);try{var i=e(),d=b.S;if(d!==null&&d(c,i),i!==null&&typeof i=="object"&&typeof i.then=="function"){var g=Ym(i,a);ka(l,t,g,et(l))}else ka(l,t,a,et(l))}catch(T){ka(l,t,{then:function(){},status:"rejected",reason:T},et())}finally{_.p=n,f!==null&&c.types!==null&&(f.types=c.types),b.T=f}}function Zm(){}function tc(l,t,u,a){if(l.tag!==5)throw Error(o(476));var e=iy(l).queue;cy(l,e,t,q,u===null?Zm:function(){return yy(l),u(a)})}function iy(l){var t=l.memoizedState;if(t!==null)return t;t={memoizedState:q,baseState:q,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Gt,lastRenderedState:q},next:null};var u={};return t.next={memoizedState:u,baseState:u,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Gt,lastRenderedState:u},next:null},l.memoizedState=t,l=l.alternate,l!==null&&(l.memoizedState=t),t}function yy(l){var t=iy(l);t.next===null&&(t=l.alternate.memoizedState),ka(l,t.next.queue,{},et())}function uc(){return Ul(he)}function vy(){return gl().memoizedState}function sy(){return gl().memoizedState}function Vm(l){for(var t=l.return;t!==null;){switch(t.tag){case 24:case 3:var u=et();l=au(u);var a=eu(t,l,u);a!==null&&(Jl(a,t,u),Ja(a,t,u)),t={cache:Nf()},l.payload=t;return}t=t.return}}function xm(l,t,u){var a=et();u={lane:a,revertLane:0,gesture:null,action:u,hasEagerState:!1,eagerState:null,next:null},nn(l)?dy(t,u):(u=Tf(l,t,u,a),u!==null&&(Jl(u,l,a),hy(u,t,a)))}function my(l,t,u){var a=et();ka(l,t,u,a)}function ka(l,t,u,a){var e={lane:a,revertLane:0,gesture:null,action:u,hasEagerState:!1,eagerState:null,next:null};if(nn(l))dy(t,e);else{var n=l.alternate;if(l.lanes===0&&(n===null||n.lanes===0)&&(n=t.lastRenderedReducer,n!==null))try{var f=t.lastRenderedState,c=n(f,u);if(e.hasEagerState=!0,e.eagerState=c,Il(c,f))return Qe(l,t,e,0),cl===null&&Xe(),!1}catch{}if(u=Tf(l,t,e,a),u!==null)return Jl(u,l,a),hy(u,t,a),!0}return!1}function ac(l,t,u,a){if(a={lane:2,revertLane:Yc(),gesture:null,action:a,hasEagerState:!1,eagerState:null,next:null},nn(l)){if(t)throw Error(o(479))}else t=Tf(l,u,a,2),t!==null&&Jl(t,l,2)}function nn(l){var t=l.alternate;return l===B||t!==null&&t===B}function dy(l,t){va=Ie=!0;var u=l.pending;u===null?t.next=t:(t.next=u.next,u.next=t),l.pending=t}function hy(l,t,u){if((u&4194048)!==0){var a=t.lanes;a&=l.pendingLanes,u|=a,t.lanes=u,zi(l,u)}}var Ia={readContext:Ul,use:tn,useCallback:dl,useContext:dl,useEffect:dl,useImperativeHandle:dl,useLayoutEffect:dl,useInsertionEffect:dl,useMemo:dl,useReducer:dl,useRef:dl,useState:dl,useDebugValue:dl,useDeferredValue:dl,useTransition:dl,useSyncExternalStore:dl,useId:dl,useHostTransitionStatus:dl,useFormState:dl,useActionState:dl,useOptimistic:dl,useMemoCache:dl,useCacheRefresh:dl};Ia.useEffectEvent=dl;var oy={readContext:Ul,use:tn,useCallback:function(l,t){return Yl().memoizedState=[l,t===void 0?null:t],l},useContext:Ul,useEffect:I0,useImperativeHandle:function(l,t,u){u=u!=null?u.concat([l]):null,an(4194308,4,uy.bind(null,t,l),u)},useLayoutEffect:function(l,t){return an(4194308,4,l,t)},useInsertionEffect:function(l,t){an(4,2,l,t)},useMemo:function(l,t){var u=Yl();t=t===void 0?null:t;var a=l();if(Bu){$t(!0);try{l()}finally{$t(!1)}}return u.memoizedState=[a,t],a},useReducer:function(l,t,u){var a=Yl();if(u!==void 0){var e=u(t);if(Bu){$t(!0);try{u(t)}finally{$t(!1)}}}else e=t;return a.memoizedState=a.baseState=e,l={pending:null,lanes:0,dispatch:null,lastRenderedReducer:l,lastRenderedState:e},a.queue=l,l=l.dispatch=xm.bind(null,B,l),[a.memoizedState,l]},useRef:function(l){var t=Yl();return l={current:l},t.memoizedState=l},useState:function(l){l=Ff(l);var t=l.queue,u=my.bind(null,B,t);return t.dispatch=u,[l.memoizedState,u]},useDebugValue:Pf,useDeferredValue:function(l,t){var u=Yl();return lc(u,l,t)},useTransition:function(){var l=Ff(!1);return l=cy.bind(null,B,l.queue,!0,!1),Yl().memoizedState=l,[!1,l]},useSyncExternalStore:function(l,t,u){var a=B,e=Yl();if(J){if(u===void 0)throw Error(o(407));u=u()}else{if(u=t(),cl===null)throw Error(o(349));(V&127)!==0||B0(a,t,u)}e.memoizedState=u;var n={value:u,getSnapshot:t};return e.queue=n,I0(X0.bind(null,a,n,l),[l]),a.flags|=2048,ma(9,{destroy:void 0},G0.bind(null,a,n,u,t),null),u},useId:function(){var l=Yl(),t=cl.identifierPrefix;if(J){var u=_t,a=rt;u=(a&~(1<<32-kl(a)-1)).toString(32)+u,t="_"+t+"R_"+u,u=Pe++,0<\/script>",n=n.removeChild(n.firstChild);break;case"select":n=typeof a.is=="string"?f.createElement("select",{is:a.is}):f.createElement("select"),a.multiple?n.multiple=!0:a.size&&(n.size=a.size);break;default:n=typeof a.is=="string"?f.createElement(e,{is:a.is}):f.createElement(e)}}n[Ml]=t,n[jl]=a;l:for(f=t.child;f!==null;){if(f.tag===5||f.tag===6)n.appendChild(f.stateNode);else if(f.tag!==4&&f.tag!==27&&f.child!==null){f.child.return=f,f=f.child;continue}if(f===t)break l;for(;f.sibling===null;){if(f.return===null||f.return===t)break l;f=f.return}f.sibling.return=f.return,f=f.sibling}t.stateNode=n;l:switch(Hl(n,e,a),e){case"button":case"input":case"select":case"textarea":a=!!a.autoFocus;break l;case"img":a=!0;break l;default:a=!1}a&&Qt(t)}}return yl(t),gc(t,t.type,l===null?null:l.memoizedProps,t.pendingProps,u),null;case 6:if(l&&t.stateNode!=null)l.memoizedProps!==a&&Qt(t);else{if(typeof a!="string"&&t.stateNode===null)throw Error(o(166));if(l=Q.current,aa(t)){if(l=t.stateNode,u=t.memoizedProps,a=null,e=Dl,e!==null)switch(e.tag){case 27:case 5:a=e.memoizedProps}l[Ml]=t,l=!!(l.nodeValue===u||a!==null&&a.suppressHydrationWarning===!0||Cv(l.nodeValue,u)),l||lu(t,!0)}else l=Mn(l).createTextNode(a),l[Ml]=t,t.stateNode=l}return yl(t),null;case 31:if(u=t.memoizedState,l===null||l.memoizedState!==null){if(a=aa(t),u!==null){if(l===null){if(!a)throw Error(o(318));if(l=t.memoizedState,l=l!==null?l.dehydrated:null,!l)throw Error(o(557));l[Ml]=t}else pu(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;yl(t),l=!1}else u=Df(),l!==null&&l.memoizedState!==null&&(l.memoizedState.hydrationErrors=u),l=!0;if(!l)return t.flags&256?(tt(t),t):(tt(t),null);if((t.flags&128)!==0)throw Error(o(558))}return yl(t),null;case 13:if(a=t.memoizedState,l===null||l.memoizedState!==null&&l.memoizedState.dehydrated!==null){if(e=aa(t),a!==null&&a.dehydrated!==null){if(l===null){if(!e)throw Error(o(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(o(317));e[Ml]=t}else pu(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;yl(t),e=!1}else e=Df(),l!==null&&l.memoizedState!==null&&(l.memoizedState.hydrationErrors=e),e=!0;if(!e)return t.flags&256?(tt(t),t):(tt(t),null)}return tt(t),(t.flags&128)!==0?(t.lanes=u,t):(u=a!==null,l=l!==null&&l.memoizedState!==null,u&&(a=t.child,e=null,a.alternate!==null&&a.alternate.memoizedState!==null&&a.alternate.memoizedState.cachePool!==null&&(e=a.alternate.memoizedState.cachePool.pool),n=null,a.memoizedState!==null&&a.memoizedState.cachePool!==null&&(n=a.memoizedState.cachePool.pool),n!==e&&(a.flags|=2048)),u!==l&&u&&(t.child.flags|=8192),sn(t,t.updateQueue),yl(t),null);case 4:return ol(),l===null&&Qc(t.stateNode.containerInfo),yl(t),null;case 10:return Yt(t.type),yl(t),null;case 19:if(E(Sl),a=t.memoizedState,a===null)return yl(t),null;if(e=(t.flags&128)!==0,n=a.rendering,n===null)if(e)le(a,!1);else{if(hl!==0||l!==null&&(l.flags&128)!==0)for(l=t.child;l!==null;){if(n=ke(l),n!==null){for(t.flags|=128,le(a,!1),l=n.updateQueue,t.updateQueue=l,sn(t,l),t.subtreeFlags=0,l=u,u=t.child;u!==null;)m0(u,l),u=u.sibling;return O(Sl,Sl.current&1|2),J&&qt(t,a.treeForkCount),t.child}l=l.sibling}a.tail!==null&&$l()>Sn&&(t.flags|=128,e=!0,le(a,!1),t.lanes=4194304)}else{if(!e)if(l=ke(n),l!==null){if(t.flags|=128,e=!0,l=l.updateQueue,t.updateQueue=l,sn(t,l),le(a,!0),a.tail===null&&a.tailMode==="hidden"&&!n.alternate&&!J)return yl(t),null}else 2*$l()-a.renderingStartTime>Sn&&u!==536870912&&(t.flags|=128,e=!0,le(a,!1),t.lanes=4194304);a.isBackwards?(n.sibling=t.child,t.child=n):(l=a.last,l!==null?l.sibling=n:t.child=n,a.last=n)}return a.tail!==null?(l=a.tail,a.rendering=l,a.tail=l.sibling,a.renderingStartTime=$l(),l.sibling=null,u=Sl.current,O(Sl,e?u&1|2:u&1),J&&qt(t,a.treeForkCount),l):(yl(t),null);case 22:case 23:return tt(t),jf(),a=t.memoizedState!==null,l!==null?l.memoizedState!==null!==a&&(t.flags|=8192):a&&(t.flags|=8192),a?(u&536870912)!==0&&(t.flags&128)===0&&(yl(t),t.subtreeFlags&6&&(t.flags|=8192)):yl(t),u=t.updateQueue,u!==null&&sn(t,u.retryQueue),u=null,l!==null&&l.memoizedState!==null&&l.memoizedState.cachePool!==null&&(u=l.memoizedState.cachePool.pool),a=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(a=t.memoizedState.cachePool.pool),a!==u&&(t.flags|=2048),l!==null&&E(Ru),null;case 24:return u=null,l!==null&&(u=l.memoizedState.cache),t.memoizedState.cache!==u&&(t.flags|=2048),Yt(bl),yl(t),null;case 25:return null;case 30:return null}throw Error(o(156,t.tag))}function Wm(l,t){switch(Of(t),t.tag){case 1:return l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 3:return Yt(bl),ol(),l=t.flags,(l&65536)!==0&&(l&128)===0?(t.flags=l&-65537|128,t):null;case 26:case 27:case 5:return Ee(t),null;case 31:if(t.memoizedState!==null){if(tt(t),t.alternate===null)throw Error(o(340));pu()}return l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 13:if(tt(t),l=t.memoizedState,l!==null&&l.dehydrated!==null){if(t.alternate===null)throw Error(o(340));pu()}return l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 19:return E(Sl),null;case 4:return ol(),null;case 10:return Yt(t.type),null;case 22:case 23:return tt(t),jf(),l!==null&&E(Ru),l=t.flags,l&65536?(t.flags=l&-65537|128,t):null;case 24:return Yt(bl),null;case 25:return null;default:return null}}function Qy(l,t){switch(Of(t),t.tag){case 3:Yt(bl),ol();break;case 26:case 27:case 5:Ee(t);break;case 4:ol();break;case 31:t.memoizedState!==null&&tt(t);break;case 13:tt(t);break;case 19:E(Sl);break;case 10:Yt(t.type);break;case 22:case 23:tt(t),jf(),l!==null&&E(Ru);break;case 24:Yt(bl)}}function te(l,t){try{var u=t.updateQueue,a=u!==null?u.lastEffect:null;if(a!==null){var e=a.next;u=e;do{if((u.tag&l)===l){a=void 0;var n=u.create,f=u.inst;a=n(),f.destroy=a}u=u.next}while(u!==e)}}catch(c){tl(t,t.return,c)}}function cu(l,t,u){try{var a=t.updateQueue,e=a!==null?a.lastEffect:null;if(e!==null){var n=e.next;a=n;do{if((a.tag&l)===l){var f=a.inst,c=f.destroy;if(c!==void 0){f.destroy=void 0,e=t;var i=u,d=c;try{d()}catch(g){tl(e,i,g)}}}a=a.next}while(a!==n)}}catch(g){tl(t,t.return,g)}}function jy(l){var t=l.updateQueue;if(t!==null){var u=l.stateNode;try{H0(t,u)}catch(a){tl(l,l.return,a)}}}function Zy(l,t,u){u.props=Gu(l.type,l.memoizedProps),u.state=l.memoizedState;try{u.componentWillUnmount()}catch(a){tl(l,t,a)}}function ue(l,t){try{var u=l.ref;if(u!==null){switch(l.tag){case 26:case 27:case 5:var a=l.stateNode;break;case 30:a=l.stateNode;break;default:a=l.stateNode}typeof u=="function"?l.refCleanup=u(a):u.current=a}}catch(e){tl(l,t,e)}}function Ot(l,t){var u=l.ref,a=l.refCleanup;if(u!==null)if(typeof a=="function")try{a()}catch(e){tl(l,t,e)}finally{l.refCleanup=null,l=l.alternate,l!=null&&(l.refCleanup=null)}else if(typeof u=="function")try{u(null)}catch(e){tl(l,t,e)}else u.current=null}function Vy(l){var t=l.type,u=l.memoizedProps,a=l.stateNode;try{l:switch(t){case"button":case"input":case"select":case"textarea":u.autoFocus&&a.focus();break l;case"img":u.src?a.src=u.src:u.srcSet&&(a.srcset=u.srcSet)}}catch(e){tl(l,l.return,e)}}function bc(l,t,u){try{var a=l.stateNode;Sd(a,l.type,u,t),a[jl]=t}catch(e){tl(l,l.return,e)}}function xy(l){return l.tag===5||l.tag===3||l.tag===26||l.tag===27&&hu(l.type)||l.tag===4}function zc(l){l:for(;;){for(;l.sibling===null;){if(l.return===null||xy(l.return))return null;l=l.return}for(l.sibling.return=l.return,l=l.sibling;l.tag!==5&&l.tag!==6&&l.tag!==18;){if(l.tag===27&&hu(l.type)||l.flags&2||l.child===null||l.tag===4)continue l;l.child.return=l,l=l.child}if(!(l.flags&2))return l.stateNode}}function Tc(l,t,u){var a=l.tag;if(a===5||a===6)l=l.stateNode,t?(u.nodeType===9?u.body:u.nodeName==="HTML"?u.ownerDocument.body:u).insertBefore(l,t):(t=u.nodeType===9?u.body:u.nodeName==="HTML"?u.ownerDocument.body:u,t.appendChild(l),u=u._reactRootContainer,u!=null||t.onclick!==null||(t.onclick=Ht));else if(a!==4&&(a===27&&hu(l.type)&&(u=l.stateNode,t=null),l=l.child,l!==null))for(Tc(l,t,u),l=l.sibling;l!==null;)Tc(l,t,u),l=l.sibling}function mn(l,t,u){var a=l.tag;if(a===5||a===6)l=l.stateNode,t?u.insertBefore(l,t):u.appendChild(l);else if(a!==4&&(a===27&&hu(l.type)&&(u=l.stateNode),l=l.child,l!==null))for(mn(l,t,u),l=l.sibling;l!==null;)mn(l,t,u),l=l.sibling}function Ly(l){var t=l.stateNode,u=l.memoizedProps;try{for(var a=l.type,e=t.attributes;e.length;)t.removeAttributeNode(e[0]);Hl(t,a,u),t[Ml]=l,t[jl]=u}catch(n){tl(l,l.return,n)}}var jt=!1,El=!1,Ec=!1,Ky=typeof WeakSet=="function"?WeakSet:Set,_l=null;function $m(l,t){if(l=l.containerInfo,Vc=qn,l=a0(l),hf(l)){if("selectionStart"in l)var u={start:l.selectionStart,end:l.selectionEnd};else l:{u=(u=l.ownerDocument)&&u.defaultView||window;var a=u.getSelection&&u.getSelection();if(a&&a.rangeCount!==0){u=a.anchorNode;var e=a.anchorOffset,n=a.focusNode;a=a.focusOffset;try{u.nodeType,n.nodeType}catch{u=null;break l}var f=0,c=-1,i=-1,d=0,g=0,T=l,h=null;t:for(;;){for(var S;T!==u||e!==0&&T.nodeType!==3||(c=f+e),T!==n||a!==0&&T.nodeType!==3||(i=f+a),T.nodeType===3&&(f+=T.nodeValue.length),(S=T.firstChild)!==null;)h=T,T=S;for(;;){if(T===l)break t;if(h===u&&++d===e&&(c=f),h===n&&++g===a&&(i=f),(S=T.nextSibling)!==null)break;T=h,h=T.parentNode}T=S}u=c===-1||i===-1?null:{start:c,end:i}}else u=null}u=u||{start:0,end:0}}else u=null;for(xc={focusedElem:l,selectionRange:u},qn=!1,_l=t;_l!==null;)if(t=_l,l=t.child,(t.subtreeFlags&1028)!==0&&l!==null)l.return=t,_l=l;else for(;_l!==null;){switch(t=_l,n=t.alternate,l=t.flags,t.tag){case 0:if((l&4)!==0&&(l=t.updateQueue,l=l!==null?l.events:null,l!==null))for(u=0;u title"))),Hl(n,a,u),n[Ml]=l,rl(n),a=n;break l;case"link":var f=kv("link","href",e).get(a+(u.href||""));if(f){for(var c=0;cnl&&(f=nl,nl=N,N=f);var s=t0(c,N),y=t0(c,nl);if(s&&y&&(S.rangeCount!==1||S.anchorNode!==s.node||S.anchorOffset!==s.offset||S.focusNode!==y.node||S.focusOffset!==y.offset)){var m=T.createRange();m.setStart(s.node,s.offset),S.removeAllRanges(),N>nl?(S.addRange(m),S.extend(y.node,y.offset)):(m.setEnd(y.node,y.offset),S.addRange(m))}}}}for(T=[],S=c;S=S.parentNode;)S.nodeType===1&&T.push({element:S,left:S.scrollLeft,top:S.scrollTop});for(typeof c.focus=="function"&&c.focus(),c=0;cu?32:u,b.T=null,u=Uc,Uc=null;var n=su,f=Kt;if(Al=0,ga=su=null,Kt=0,(k&6)!==0)throw Error(o(331));var c=k;if(k|=4,uv(n.current),Py(n,n.current,f,u),k=c,ie(0,!1),Fl&&typeof Fl.onPostCommitFiberRoot=="function")try{Fl.onPostCommitFiberRoot(Ma,n)}catch{}return!0}finally{_.p=e,b.T=a,Tv(l,t)}}function Av(l,t,u){t=yt(u,t),t=cc(l.stateNode,t,2),l=eu(l,t,2),l!==null&&(Ua(l,2),Mt(l))}function tl(l,t,u){if(l.tag===3)Av(l,l,u);else for(;t!==null;){if(t.tag===3){Av(t,l,u);break}else if(t.tag===1){var a=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof a.componentDidCatch=="function"&&(vu===null||!vu.has(a))){l=yt(u,l),u=ry(2),a=eu(t,u,2),a!==null&&(_y(u,a,t,l),Ua(a,2),Mt(a));break}}t=t.return}}function Rc(l,t,u){var a=l.pingCache;if(a===null){a=l.pingCache=new Im;var e=new Set;a.set(t,e)}else e=a.get(t),e===void 0&&(e=new Set,a.set(t,e));e.has(u)||(_c=!0,e.add(u),l=ad.bind(null,l,t,u),t.then(l,l))}function ad(l,t,u){var a=l.pingCache;a!==null&&a.delete(t),l.pingedLanes|=l.suspendedLanes&u,l.warmLanes&=~u,cl===l&&(V&u)===u&&(hl===4||hl===3&&(V&62914560)===V&&300>$l()-on?(k&2)===0&&ba(l,0):Oc|=u,Sa===V&&(Sa=0)),Mt(l)}function rv(l,t){t===0&&(t=gi()),l=Du(l,t),l!==null&&(Ua(l,t),Mt(l))}function ed(l){var t=l.memoizedState,u=0;t!==null&&(u=t.retryLane),rv(l,u)}function nd(l,t){var u=0;switch(l.tag){case 31:case 13:var a=l.stateNode,e=l.memoizedState;e!==null&&(u=e.retryLane);break;case 19:a=l.stateNode;break;case 22:a=l.stateNode._retryCache;break;default:throw Error(o(314))}a!==null&&a.delete(t),rv(l,u)}function fd(l,t){return Ln(l,t)}var An=null,Ta=null,qc=!1,rn=!1,Cc=!1,du=0;function Mt(l){l!==Ta&&l.next===null&&(Ta===null?An=Ta=l:Ta=Ta.next=l),rn=!0,qc||(qc=!0,id())}function ie(l,t){if(!Cc&&rn){Cc=!0;do for(var u=!1,a=An;a!==null;){if(l!==0){var e=a.pendingLanes;if(e===0)var n=0;else{var f=a.suspendedLanes,c=a.pingedLanes;n=(1<<31-kl(42|l)+1)-1,n&=e&~(f&~c),n=n&201326741?n&201326741|1:n?n|2:0}n!==0&&(u=!0,Dv(a,n))}else n=V,n=Me(a,a===cl?n:0,a.cancelPendingCommit!==null||a.timeoutHandle!==-1),(n&3)===0||Da(a,n)||(u=!0,Dv(a,n));a=a.next}while(u);Cc=!1}}function cd(){_v()}function _v(){rn=qc=!1;var l=0;du!==0&&bd()&&(l=du);for(var t=$l(),u=null,a=An;a!==null;){var e=a.next,n=Ov(a,t);n===0?(a.next=null,u===null?An=e:u.next=e,e===null&&(Ta=u)):(u=a,(l!==0||(n&3)!==0)&&(rn=!0)),a=e}Al!==0&&Al!==5||ie(l),du!==0&&(du=0)}function Ov(l,t){for(var u=l.suspendedLanes,a=l.pingedLanes,e=l.expirationTimes,n=l.pendingLanes&-62914561;0c)break;var g=i.transferSize,T=i.initiatorType;g&&Yv(T)&&(i=i.responseEnd,f+=g*(i"u"?null:document;function wv(l,t,u){var a=Ea;if(a&&typeof t=="string"&&t){var e=ct(t);e='link[rel="'+l+'"][href="'+e+'"]',typeof u=="string"&&(e+='[crossorigin="'+u+'"]'),Jv.has(e)||(Jv.add(e),l={rel:l,crossOrigin:u,href:t},a.querySelector(e)===null&&(t=a.createElement("link"),Hl(t,"link",l),rl(t),a.head.appendChild(t)))}}function Dd(l){Jt.D(l),wv("dns-prefetch",l,null)}function Ud(l,t){Jt.C(l,t),wv("preconnect",l,t)}function pd(l,t,u){Jt.L(l,t,u);var a=Ea;if(a&&l&&t){var e='link[rel="preload"][as="'+ct(t)+'"]';t==="image"&&u&&u.imageSrcSet?(e+='[imagesrcset="'+ct(u.imageSrcSet)+'"]',typeof u.imageSizes=="string"&&(e+='[imagesizes="'+ct(u.imageSizes)+'"]')):e+='[href="'+ct(l)+'"]';var n=e;switch(t){case"style":n=Aa(l);break;case"script":n=ra(l)}ot.has(n)||(l=R({rel:"preload",href:t==="image"&&u&&u.imageSrcSet?void 0:l,as:t},u),ot.set(n,l),a.querySelector(e)!==null||t==="style"&&a.querySelector(me(n))||t==="script"&&a.querySelector(de(n))||(t=a.createElement("link"),Hl(t,"link",l),rl(t),a.head.appendChild(t)))}}function Hd(l,t){Jt.m(l,t);var u=Ea;if(u&&l){var a=t&&typeof t.as=="string"?t.as:"script",e='link[rel="modulepreload"][as="'+ct(a)+'"][href="'+ct(l)+'"]',n=e;switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":n=ra(l)}if(!ot.has(n)&&(l=R({rel:"modulepreload",href:l},t),ot.set(n,l),u.querySelector(e)===null)){switch(a){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(u.querySelector(de(n)))return}a=u.createElement("link"),Hl(a,"link",l),rl(a),u.head.appendChild(a)}}}function Nd(l,t,u){Jt.S(l,t,u);var a=Ea;if(a&&l){var e=Lu(a).hoistableStyles,n=Aa(l);t=t||"default";var f=e.get(n);if(!f){var c={loading:0,preload:null};if(f=a.querySelector(me(n)))c.loading=5;else{l=R({rel:"stylesheet",href:l,"data-precedence":t},u),(u=ot.get(n))&&Fc(l,u);var i=f=a.createElement("link");rl(i),Hl(i,"link",l),i._p=new Promise(function(d,g){i.onload=d,i.onerror=g}),i.addEventListener("load",function(){c.loading|=1}),i.addEventListener("error",function(){c.loading|=2}),c.loading|=4,Un(f,t,a)}f={type:"stylesheet",instance:f,count:1,state:c},e.set(n,f)}}}function Rd(l,t){Jt.X(l,t);var u=Ea;if(u&&l){var a=Lu(u).hoistableScripts,e=ra(l),n=a.get(e);n||(n=u.querySelector(de(e)),n||(l=R({src:l,async:!0},t),(t=ot.get(e))&&kc(l,t),n=u.createElement("script"),rl(n),Hl(n,"link",l),u.head.appendChild(n)),n={type:"script",instance:n,count:1,state:null},a.set(e,n))}}function qd(l,t){Jt.M(l,t);var u=Ea;if(u&&l){var a=Lu(u).hoistableScripts,e=ra(l),n=a.get(e);n||(n=u.querySelector(de(e)),n||(l=R({src:l,async:!0,type:"module"},t),(t=ot.get(e))&&kc(l,t),n=u.createElement("script"),rl(n),Hl(n,"link",l),u.head.appendChild(n)),n={type:"script",instance:n,count:1,state:null},a.set(e,n))}}function Wv(l,t,u,a){var e=(e=Q.current)?Dn(e):null;if(!e)throw Error(o(446));switch(l){case"meta":case"title":return null;case"style":return typeof u.precedence=="string"&&typeof u.href=="string"?(t=Aa(u.href),u=Lu(e).hoistableStyles,a=u.get(t),a||(a={type:"style",instance:null,count:0,state:null},u.set(t,a)),a):{type:"void",instance:null,count:0,state:null};case"link":if(u.rel==="stylesheet"&&typeof u.href=="string"&&typeof u.precedence=="string"){l=Aa(u.href);var n=Lu(e).hoistableStyles,f=n.get(l);if(f||(e=e.ownerDocument||e,f={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},n.set(l,f),(n=e.querySelector(me(l)))&&!n._p&&(f.instance=n,f.state.loading=5),ot.has(l)||(u={rel:"preload",as:"style",href:u.href,crossOrigin:u.crossOrigin,integrity:u.integrity,media:u.media,hrefLang:u.hrefLang,referrerPolicy:u.referrerPolicy},ot.set(l,u),n||Cd(e,l,u,f.state))),t&&a===null)throw Error(o(528,""));return f}if(t&&a!==null)throw Error(o(529,""));return null;case"script":return t=u.async,u=u.src,typeof u=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=ra(u),u=Lu(e).hoistableScripts,a=u.get(t),a||(a={type:"script",instance:null,count:0,state:null},u.set(t,a)),a):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,l))}}function Aa(l){return'href="'+ct(l)+'"'}function me(l){return'link[rel="stylesheet"]['+l+"]"}function $v(l){return R({},l,{"data-precedence":l.precedence,precedence:null})}function Cd(l,t,u,a){l.querySelector('link[rel="preload"][as="style"]['+t+"]")?a.loading=1:(t=l.createElement("link"),a.preload=t,t.addEventListener("load",function(){return a.loading|=1}),t.addEventListener("error",function(){return a.loading|=2}),Hl(t,"link",u),rl(t),l.head.appendChild(t))}function ra(l){return'[src="'+ct(l)+'"]'}function de(l){return"script[async]"+l}function Fv(l,t,u){if(t.count++,t.instance===null)switch(t.type){case"style":var a=l.querySelector('style[data-href~="'+ct(u.href)+'"]');if(a)return t.instance=a,rl(a),a;var e=R({},u,{"data-href":u.href,"data-precedence":u.precedence,href:null,precedence:null});return a=(l.ownerDocument||l).createElement("style"),rl(a),Hl(a,"style",e),Un(a,u.precedence,l),t.instance=a;case"stylesheet":e=Aa(u.href);var n=l.querySelector(me(e));if(n)return t.state.loading|=4,t.instance=n,rl(n),n;a=$v(u),(e=ot.get(e))&&Fc(a,e),n=(l.ownerDocument||l).createElement("link"),rl(n);var f=n;return f._p=new Promise(function(c,i){f.onload=c,f.onerror=i}),Hl(n,"link",a),t.state.loading|=4,Un(n,u.precedence,l),t.instance=n;case"script":return n=ra(u.src),(e=l.querySelector(de(n)))?(t.instance=e,rl(e),e):(a=u,(e=ot.get(n))&&(a=R({},u),kc(a,e)),l=l.ownerDocument||l,e=l.createElement("script"),rl(e),Hl(e,"link",a),l.head.appendChild(e),t.instance=e);case"void":return null;default:throw Error(o(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(a=t.instance,t.state.loading|=4,Un(a,u.precedence,l));return t.instance}function Un(l,t,u){for(var a=u.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),e=a.length?a[a.length-1]:null,n=e,f=0;f title"):null)}function Yd(l,t,u){if(u===1||t.itemProp!=null)return!1;switch(l){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(l=t.disabled,typeof t.precedence=="string"&&l==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Pv(l){return!(l.type==="stylesheet"&&(l.state.loading&3)===0)}function Bd(l,t,u,a){if(u.type==="stylesheet"&&(typeof a.media!="string"||matchMedia(a.media).matches!==!1)&&(u.state.loading&4)===0){if(u.instance===null){var e=Aa(a.href),n=t.querySelector(me(e));if(n){t=n._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(l.count++,l=Hn.bind(l),t.then(l,l)),u.state.loading|=4,u.instance=n,rl(n);return}n=t.ownerDocument||t,a=$v(a),(e=ot.get(e))&&Fc(a,e),n=n.createElement("link"),rl(n);var f=n;f._p=new Promise(function(c,i){f.onload=c,f.onerror=i}),Hl(n,"link",a),u.instance=n}l.stylesheets===null&&(l.stylesheets=new Map),l.stylesheets.set(u,t),(t=u.state.preload)&&(u.state.loading&3)===0&&(l.count++,u=Hn.bind(l),t.addEventListener("load",u),t.addEventListener("error",u))}}var Ic=0;function Gd(l,t){return l.stylesheets&&l.count===0&&Rn(l,l.stylesheets),0Ic?50:800)+t);return l.unsuspend=u,function(){l.unsuspend=null,clearTimeout(a),clearTimeout(e)}}:null}function Hn(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Rn(this,this.stylesheets);else if(this.unsuspend){var l=this.unsuspend;this.unsuspend=null,l()}}}var Nn=null;function Rn(l,t){l.stylesheets=null,l.unsuspend!==null&&(l.count++,Nn=new Map,t.forEach(Xd,l),Nn=null,Hn.call(l))}function Xd(l,t){if(!(t.state.loading&4)){var u=Nn.get(l);if(u)var a=u.get(null);else{u=new Map,Nn.set(l,u);for(var e=l.querySelectorAll("link[data-precedence],style[data-precedence]"),n=0;n"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(P){console.error(P)}}return r(),fi.exports=Id(),fi.exports}var l1=Pd();const e1=rs(l1);var vi={exports:{}},ze={};var Es;function t1(){if(Es)return ze;Es=1;var r=Symbol.for("react.transitional.element"),P=Symbol.for("react.fragment");function w(o,X,L){var vl=null;if(L!==void 0&&(vl=""+L),X.key!==void 0&&(vl=""+X.key),"key"in X){L={};for(var Ol in X)Ol!=="key"&&(L[Ol]=X[Ol])}else L=X;return X=L.ref,{$$typeof:r,type:o,key:vl,ref:X!==void 0?X:null,props:L}}return ze.Fragment=P,ze.jsx=w,ze.jsxs=w,ze}var As;function u1(){return As||(As=1,vi.exports=t1()),vi.exports}var wt=u1();function n1({children:r,fallback:P}){const[w,o]=Te.useState(null),[X,L]=Te.useState(!0),[vl,Ol]=Te.useState(null);return Te.useEffect(()=>{if(window.__MCP_APP_DATA__){o(window.__MCP_APP_DATA__),L(!1);return}const p=W=>{W.data?.type==="mcp-app-init"&&(o(W.data.data),L(!1))};window.addEventListener("message",p);const A=setTimeout(()=>{w||(Ol("No data received from MCP server"),L(!1))},5e3);return()=>{window.removeEventListener("message",p),clearTimeout(A)}},[]),X?wt.jsxs("div",{className:"ghl-loading",children:[wt.jsx("div",{className:"ghl-spinner"}),wt.jsx("span",{style:{marginLeft:12},children:"Loading..."})]}):vl?wt.jsx("div",{className:"ghl-empty",children:wt.jsx("p",{children:vl})}):!w&&P?wt.jsx(wt.Fragment,{children:P}):wt.jsx(wt.Fragment,{children:r(w)})}function f1(r){if(!r)return"N/A";try{return new Date(r).toLocaleDateString("en-US",{year:"numeric",month:"short",day:"numeric"})}catch{return r}}function c1(r,P="USD"){return r==null?"$0.00":new Intl.NumberFormat("en-US",{style:"currency",currency:P}).format(r/100)}function i1(r,P){const w=r?.charAt(0)?.toUpperCase()||"",o=P?.charAt(0)?.toUpperCase()||"";return w+o||"?"}function y1(r){return{paid:"success",sent:"primary",viewed:"info",draft:"default",overdue:"danger",cancelled:"danger",won:"success",lost:"danger",open:"primary",abandoned:"warning",active:"success",inactive:"default",pending:"warning"}[r?.toLowerCase()]||"default"}export{n1 as A,e1 as R,a1 as a,c1 as b,y1 as c,f1 as f,i1 as g,wt as j,Te as r}; diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/calendar-widget.html b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/calendar-widget.html deleted file mode 100644 index 05c294d..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/calendar-widget.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Calendar Widget - GHL MCP - - - - - -
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/contact-card.html b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/contact-card.html deleted file mode 100644 index c5d8a81..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/contact-card.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Contact Card - GHL MCP - - - - - -
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/contact-grid.html b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/contact-grid.html deleted file mode 100644 index 3106851..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/contact-grid.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Contact Grid - GHL MCP - - - - - -
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/conversation-thread.html b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/conversation-thread.html deleted file mode 100644 index 2097a39..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/conversation-thread.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Conversation Thread - GHL MCP - - - - - -
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/invoice-preview.html b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/invoice-preview.html deleted file mode 100644 index 77e5c3d..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/invoice-preview.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Invoice Preview - GHL MCP - - - - - -
- - diff --git a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/opportunity-kanban.html b/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/opportunity-kanban.html deleted file mode 100644 index 8eb97d6..0000000 --- a/mcp-diagrams/ghl-mcp-apps-only/src/ui/dist/opportunity-kanban.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - Pipeline Kanban - GHL MCP - - - - - -
- - diff --git a/mcp-diagrams/mcp-animation-framework/output/acuity.mp4 b/mcp-diagrams/mcp-animation-framework/output/acuity.mp4 deleted file mode 100644 index a578721..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/acuity.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/bamboohr.mp4 b/mcp-diagrams/mcp-animation-framework/output/bamboohr.mp4 deleted file mode 100644 index a09512c..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/bamboohr.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/basecamp.mp4 b/mcp-diagrams/mcp-animation-framework/output/basecamp.mp4 deleted file mode 100644 index 0697850..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/basecamp.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/bigcommerce.mp4 b/mcp-diagrams/mcp-animation-framework/output/bigcommerce.mp4 deleted file mode 100644 index 7b501f1..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/bigcommerce.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/brevo.mp4 b/mcp-diagrams/mcp-animation-framework/output/brevo.mp4 deleted file mode 100644 index 5901e30..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/brevo.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/calendly.mp4 b/mcp-diagrams/mcp-animation-framework/output/calendly.mp4 deleted file mode 100644 index 5193aa2..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/calendly.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/clickup.mp4 b/mcp-diagrams/mcp-animation-framework/output/clickup.mp4 deleted file mode 100644 index 370ad72..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/clickup.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/closecrm.mp4 b/mcp-diagrams/mcp-animation-framework/output/closecrm.mp4 deleted file mode 100644 index 527539f..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/closecrm.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/clover.mp4 b/mcp-diagrams/mcp-animation-framework/output/clover.mp4 deleted file mode 100644 index aaeaf10..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/clover.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/constantcontact.mp4 b/mcp-diagrams/mcp-animation-framework/output/constantcontact.mp4 deleted file mode 100644 index 0c4eb0d..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/constantcontact.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/fieldedge.mp4 b/mcp-diagrams/mcp-animation-framework/output/fieldedge.mp4 deleted file mode 100644 index 0d29365..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/fieldedge.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/freshbooks.mp4 b/mcp-diagrams/mcp-animation-framework/output/freshbooks.mp4 deleted file mode 100644 index f44086b..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/freshbooks.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/freshdesk.mp4 b/mcp-diagrams/mcp-animation-framework/output/freshdesk.mp4 deleted file mode 100644 index 811b0ae..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/freshdesk.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/gusto.mp4 b/mcp-diagrams/mcp-animation-framework/output/gusto.mp4 deleted file mode 100644 index ac88eee..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/gusto.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/helpscout.mp4 b/mcp-diagrams/mcp-animation-framework/output/helpscout.mp4 deleted file mode 100644 index 7716949..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/helpscout.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/housecallpro.mp4 b/mcp-diagrams/mcp-animation-framework/output/housecallpro.mp4 deleted file mode 100644 index 4a44859..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/housecallpro.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/jobber.mp4 b/mcp-diagrams/mcp-animation-framework/output/jobber.mp4 deleted file mode 100644 index c0c84d2..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/jobber.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/keap.mp4 b/mcp-diagrams/mcp-animation-framework/output/keap.mp4 deleted file mode 100644 index 614dfaf..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/keap.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/lightspeed.mp4 b/mcp-diagrams/mcp-animation-framework/output/lightspeed.mp4 deleted file mode 100644 index 64f3bd3..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/lightspeed.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/mailchimp.mp4 b/mcp-diagrams/mcp-animation-framework/output/mailchimp.mp4 deleted file mode 100644 index d403fe9..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/mailchimp.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/mcp-demo.mp4 b/mcp-diagrams/mcp-animation-framework/output/mcp-demo.mp4 deleted file mode 100644 index fdf6229..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/mcp-demo.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/pipedrive.mp4 b/mcp-diagrams/mcp-animation-framework/output/pipedrive.mp4 deleted file mode 100644 index 3bbefdd..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/pipedrive.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/rippling.mp4 b/mcp-diagrams/mcp-animation-framework/output/rippling.mp4 deleted file mode 100644 index ef99a79..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/rippling.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/servicetitan.mp4 b/mcp-diagrams/mcp-animation-framework/output/servicetitan.mp4 deleted file mode 100644 index c3da251..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/servicetitan.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/squarespace.mp4 b/mcp-diagrams/mcp-animation-framework/output/squarespace.mp4 deleted file mode 100644 index 6dcfd22..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/squarespace.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-animation.gif b/mcp-diagrams/mcp-animation-framework/output/stripe-animation.gif deleted file mode 100644 index f3faa45..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-animation.gif and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-full-flow.gif b/mcp-diagrams/mcp-animation-framework/output/stripe-full-flow.gif deleted file mode 100644 index f34a24e..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-full-flow.gif and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-v4.mp4 b/mcp-diagrams/mcp-animation-framework/output/stripe-v4.mp4 deleted file mode 100644 index bdd2cbc..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-v4.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-v5.mp4 b/mcp-diagrams/mcp-animation-framework/output/stripe-v5.mp4 deleted file mode 100644 index 70b1da3..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-v5.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-v6.mp4 b/mcp-diagrams/mcp-animation-framework/output/stripe-v6.mp4 deleted file mode 100644 index 56fbbc6..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-v6.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-web-simulation.mp4 b/mcp-diagrams/mcp-animation-framework/output/stripe-web-simulation.mp4 deleted file mode 100644 index 5ebfd2d..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-web-simulation.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-web-v2.mp4 b/mcp-diagrams/mcp-animation-framework/output/stripe-web-v2.mp4 deleted file mode 100644 index ba85b37..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-web-v2.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/stripe-web-v3.mp4 b/mcp-diagrams/mcp-animation-framework/output/stripe-web-v3.mp4 deleted file mode 100644 index 1f31751..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/stripe-web-v3.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/toast.mp4 b/mcp-diagrams/mcp-animation-framework/output/toast.mp4 deleted file mode 100644 index cd166c6..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/toast.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/touchbistro.mp4 b/mcp-diagrams/mcp-animation-framework/output/touchbistro.mp4 deleted file mode 100644 index 5ba98b8..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/touchbistro.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/trello.mp4 b/mcp-diagrams/mcp-animation-framework/output/trello.mp4 deleted file mode 100644 index 108be35..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/trello.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/wave.mp4 b/mcp-diagrams/mcp-animation-framework/output/wave.mp4 deleted file mode 100644 index f94b837..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/wave.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/wrike.mp4 b/mcp-diagrams/mcp-animation-framework/output/wrike.mp4 deleted file mode 100644 index e81cda2..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/wrike.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-animation-framework/output/zendesk.mp4 b/mcp-diagrams/mcp-animation-framework/output/zendesk.mp4 deleted file mode 100644 index 5ba4437..0000000 Binary files a/mcp-diagrams/mcp-animation-framework/output/zendesk.mp4 and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-01.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-01.jpg deleted file mode 100644 index 39cb496..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-01.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-02.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-02.jpg deleted file mode 100644 index 619ddd1..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-02.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-03.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-03.jpg deleted file mode 100644 index aae5659..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-03.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-04.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-04.jpg deleted file mode 100644 index ded261c..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-04.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-05.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-05.jpg deleted file mode 100644 index 5da1885..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-05.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-06.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-06.jpg deleted file mode 100644 index 3f3dd38..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-06.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-chat-animation/frames/frame-07.jpg b/mcp-diagrams/mcp-chat-animation/frames/frame-07.jpg deleted file mode 100644 index dc3e3b7..0000000 Binary files a/mcp-diagrams/mcp-chat-animation/frames/frame-07.jpg and /dev/null differ diff --git a/mcp-diagrams/mcp-servers/acuity-scheduling/dist/index.d.ts b/mcp-diagrams/mcp-servers/acuity-scheduling/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/acuity-scheduling/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/acuity-scheduling/dist/index.js b/mcp-diagrams/mcp-servers/acuity-scheduling/dist/index.js deleted file mode 100644 index 73442a0..0000000 --- a/mcp-diagrams/mcp-servers/acuity-scheduling/dist/index.js +++ /dev/null @@ -1,269 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "acuity-scheduling"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://acuityscheduling.com/api/v1"; -// ============================================ -// API CLIENT - Acuity uses Basic Auth -// ============================================ -class AcuityClient { - authHeader; - baseUrl; - constructor(userId, apiKey) { - // Acuity uses Basic Auth with userId:apiKey - this.authHeader = "Basic " + Buffer.from(`${userId}:${apiKey}`).toString("base64"); - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": this.authHeader, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const text = await response.text(); - throw new Error(`Acuity API error: ${response.status} ${response.statusText} - ${text}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_appointments", - description: "List appointments with optional filters. Returns scheduled appointments.", - inputSchema: { - type: "object", - properties: { - minDate: { type: "string", description: "Minimum date (YYYY-MM-DD)" }, - maxDate: { type: "string", description: "Maximum date (YYYY-MM-DD)" }, - calendarID: { type: "number", description: "Filter by calendar ID" }, - appointmentTypeID: { type: "number", description: "Filter by appointment type ID" }, - canceled: { type: "boolean", description: "Include canceled appointments" }, - max: { type: "number", description: "Maximum number of results (default 100)" }, - }, - }, - }, - { - name: "get_appointment", - description: "Get a specific appointment by ID", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Appointment ID" }, - }, - required: ["id"], - }, - }, - { - name: "create_appointment", - description: "Create a new appointment", - inputSchema: { - type: "object", - properties: { - datetime: { type: "string", description: "Appointment datetime (ISO 8601 format)" }, - appointmentTypeID: { type: "number", description: "Appointment type ID" }, - calendarID: { type: "number", description: "Calendar ID" }, - firstName: { type: "string", description: "Client first name" }, - lastName: { type: "string", description: "Client last name" }, - email: { type: "string", description: "Client email" }, - phone: { type: "string", description: "Client phone number" }, - notes: { type: "string", description: "Appointment notes" }, - fields: { type: "array", description: "Custom intake form fields", items: { type: "object" } }, - }, - required: ["datetime", "appointmentTypeID", "firstName", "lastName", "email"], - }, - }, - { - name: "cancel_appointment", - description: "Cancel an appointment", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Appointment ID to cancel" }, - cancelNote: { type: "string", description: "Reason for cancellation" }, - noShow: { type: "boolean", description: "Mark as no-show instead of cancel" }, - }, - required: ["id"], - }, - }, - { - name: "list_calendars", - description: "List all calendars/staff members", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "get_availability", - description: "Get available time slots for booking", - inputSchema: { - type: "object", - properties: { - appointmentTypeID: { type: "number", description: "Appointment type ID" }, - calendarID: { type: "number", description: "Calendar ID (optional)" }, - date: { type: "string", description: "Date to check (YYYY-MM-DD)" }, - month: { type: "string", description: "Month to check (YYYY-MM)" }, - timezone: { type: "string", description: "Timezone (e.g., America/New_York)" }, - }, - required: ["appointmentTypeID"], - }, - }, - { - name: "list_clients", - description: "List clients with optional search", - inputSchema: { - type: "object", - properties: { - search: { type: "string", description: "Search term (name, email, or phone)" }, - max: { type: "number", description: "Maximum number of results" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_appointments": { - const params = new URLSearchParams(); - if (args.minDate) - params.append("minDate", args.minDate); - if (args.maxDate) - params.append("maxDate", args.maxDate); - if (args.calendarID) - params.append("calendarID", String(args.calendarID)); - if (args.appointmentTypeID) - params.append("appointmentTypeID", String(args.appointmentTypeID)); - if (args.canceled !== undefined) - params.append("canceled", String(args.canceled)); - if (args.max) - params.append("max", String(args.max)); - const query = params.toString(); - return await client.get(`/appointments${query ? `?${query}` : ""}`); - } - case "get_appointment": { - return await client.get(`/appointments/${args.id}`); - } - case "create_appointment": { - const payload = { - datetime: args.datetime, - appointmentTypeID: args.appointmentTypeID, - firstName: args.firstName, - lastName: args.lastName, - email: args.email, - }; - if (args.calendarID) - payload.calendarID = args.calendarID; - if (args.phone) - payload.phone = args.phone; - if (args.notes) - payload.notes = args.notes; - if (args.fields) - payload.fields = args.fields; - return await client.post("/appointments", payload); - } - case "cancel_appointment": { - const payload = {}; - if (args.cancelNote) - payload.cancelNote = args.cancelNote; - if (args.noShow) - payload.noShow = args.noShow; - return await client.put(`/appointments/${args.id}/cancel`, payload); - } - case "list_calendars": { - return await client.get("/calendars"); - } - case "get_availability": { - const params = new URLSearchParams(); - params.append("appointmentTypeID", String(args.appointmentTypeID)); - if (args.calendarID) - params.append("calendarID", String(args.calendarID)); - if (args.date) - params.append("date", args.date); - if (args.month) - params.append("month", args.month); - if (args.timezone) - params.append("timezone", args.timezone); - return await client.get(`/availability/times?${params.toString()}`); - } - case "list_clients": { - const params = new URLSearchParams(); - if (args.search) - params.append("search", args.search); - if (args.max) - params.append("max", String(args.max)); - const query = params.toString(); - return await client.get(`/clients${query ? `?${query}` : ""}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const userId = process.env.ACUITY_USER_ID; - const apiKey = process.env.ACUITY_API_KEY; - if (!userId || !apiKey) { - console.error("Error: ACUITY_USER_ID and ACUITY_API_KEY environment variables required"); - process.exit(1); - } - const client = new AcuityClient(userId, apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/bamboohr/dist/index.d.ts b/mcp-diagrams/mcp-servers/bamboohr/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/bamboohr/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/bamboohr/dist/index.js b/mcp-diagrams/mcp-servers/bamboohr/dist/index.js deleted file mode 100644 index 7c0f9fc..0000000 --- a/mcp-diagrams/mcp-servers/bamboohr/dist/index.js +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "bamboohr"; -const MCP_VERSION = "1.0.0"; -// ============================================ -// API CLIENT -// ============================================ -class BambooHRClient { - apiKey; - companyDomain; - baseUrl; - constructor(apiKey, companyDomain) { - this.apiKey = apiKey; - this.companyDomain = companyDomain; - this.baseUrl = `https://api.bamboohr.com/api/gateway.php/${companyDomain}/v1`; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const authHeader = Buffer.from(`${this.apiKey}:x`).toString("base64"); - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Basic ${authHeader}`, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const text = await response.text(); - throw new Error(`BambooHR API error: ${response.status} ${response.statusText} - ${text}`); - } - const contentType = response.headers.get("content-type"); - if (contentType?.includes("application/json")) { - return response.json(); - } - return response.text(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - // Employee methods - async listEmployees() { - // Returns the employee directory with standard fields - return this.get("/employees/directory"); - } - async getEmployee(employeeId, fields) { - const fieldList = fields?.join(",") || "firstName,lastName,department,jobTitle,workEmail,workPhone,location,photoUrl,status"; - return this.get(`/employees/${employeeId}?fields=${fieldList}`); - } - async getDirectory() { - return this.get("/employees/directory"); - } - // Time Off methods - async listTimeOffRequests(options) { - const params = new URLSearchParams(); - if (options?.start) - params.append("start", options.start); - if (options?.end) - params.append("end", options.end); - if (options?.status) - params.append("status", options.status); - if (options?.employeeId) - params.append("employeeId", options.employeeId); - const query = params.toString(); - return this.get(`/time_off/requests${query ? `?${query}` : ""}`); - } - async requestTimeOff(data) { - return this.put(`/employees/${data.employeeId}/time_off/request`, { - timeOffTypeId: data.timeOffTypeId, - start: data.start, - end: data.end, - amount: data.amount, - notes: data.notes, - status: data.status || "requested", - }); - } - // Goals methods - async listGoals(employeeId) { - return this.get(`/employees/${employeeId}/goals`); - } - // Files methods - async listFiles(employeeId) { - return this.get(`/employees/${employeeId}/files/view`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_employees", - description: "List all employees from the BambooHR directory", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "get_employee", - description: "Get detailed information about a specific employee", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Employee ID" }, - fields: { - type: "array", - items: { type: "string" }, - description: "Specific fields to retrieve (e.g., firstName, lastName, department, jobTitle, workEmail, hireDate)" - }, - }, - required: ["employee_id"], - }, - }, - { - name: "list_time_off_requests", - description: "List time off requests from BambooHR", - inputSchema: { - type: "object", - properties: { - start: { type: "string", description: "Start date (YYYY-MM-DD)" }, - end: { type: "string", description: "End date (YYYY-MM-DD)" }, - status: { - type: "string", - description: "Filter by status", - enum: ["approved", "denied", "superceded", "requested", "canceled"] - }, - employee_id: { type: "string", description: "Filter by employee ID" }, - }, - }, - }, - { - name: "request_time_off", - description: "Submit a time off request for an employee", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Employee ID" }, - time_off_type_id: { type: "string", description: "Time off type ID (e.g., vacation, sick)" }, - start: { type: "string", description: "Start date (YYYY-MM-DD)" }, - end: { type: "string", description: "End date (YYYY-MM-DD)" }, - amount: { type: "number", description: "Number of days/hours" }, - notes: { type: "string", description: "Request notes" }, - }, - required: ["employee_id", "time_off_type_id", "start", "end"], - }, - }, - { - name: "list_goals", - description: "List goals for an employee", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Employee ID" }, - }, - required: ["employee_id"], - }, - }, - { - name: "get_directory", - description: "Get the full employee directory with contact information", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "list_files", - description: "List files associated with an employee", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Employee ID" }, - }, - required: ["employee_id"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_employees": { - return await client.listEmployees(); - } - case "get_employee": { - return await client.getEmployee(args.employee_id, args.fields); - } - case "list_time_off_requests": { - return await client.listTimeOffRequests({ - start: args.start, - end: args.end, - status: args.status, - employeeId: args.employee_id, - }); - } - case "request_time_off": { - return await client.requestTimeOff({ - employeeId: args.employee_id, - timeOffTypeId: args.time_off_type_id, - start: args.start, - end: args.end, - amount: args.amount, - notes: args.notes, - }); - } - case "list_goals": { - return await client.listGoals(args.employee_id); - } - case "get_directory": { - return await client.getDirectory(); - } - case "list_files": { - return await client.listFiles(args.employee_id); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.BAMBOOHR_API_KEY; - const companyDomain = process.env.BAMBOOHR_COMPANY_DOMAIN; - if (!apiKey) { - console.error("Error: BAMBOOHR_API_KEY environment variable required"); - process.exit(1); - } - if (!companyDomain) { - console.error("Error: BAMBOOHR_COMPANY_DOMAIN environment variable required"); - process.exit(1); - } - const client = new BambooHRClient(apiKey, companyDomain); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - // List available tools - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - // Handle tool calls - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - // Start server - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/basecamp/dist/index.d.ts b/mcp-diagrams/mcp-servers/basecamp/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/basecamp/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/basecamp/dist/index.js b/mcp-diagrams/mcp-servers/basecamp/dist/index.js deleted file mode 100644 index fcd08f7..0000000 --- a/mcp-diagrams/mcp-servers/basecamp/dist/index.js +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "basecamp"; -const MCP_VERSION = "1.0.0"; -// ============================================ -// API CLIENT (OAuth 2.0) -// Basecamp 4 API uses: https://3.basecampapi.com/{account_id}/ -// ============================================ -class BasecampClient { - accessToken; - accountId; - baseUrl; - userAgent; - constructor(accessToken, accountId, appIdentity) { - this.accessToken = accessToken; - this.accountId = accountId; - this.baseUrl = `https://3.basecampapi.com/${accountId}`; - this.userAgent = appIdentity; // Required: "AppName (contact@email.com)" - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - "User-Agent": this.userAgent, - ...options.headers, - }, - }); - if (!response.ok) { - const error = await response.text(); - throw new Error(`Basecamp API error: ${response.status} - ${error}`); - } - const text = await response.text(); - return text ? JSON.parse(text) : { success: true }; - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_projects", - description: "List all projects in the Basecamp account", - inputSchema: { - type: "object", - properties: { - status: { - type: "string", - enum: ["active", "archived", "trashed"], - description: "Filter by project status (default: active)" - }, - }, - }, - }, - { - name: "get_project", - description: "Get details of a specific project including its dock (tools)", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (required)" }, - }, - required: ["project_id"], - }, - }, - { - name: "list_todos", - description: "List to-dos from a to-do list in a project", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (required)" }, - todolist_id: { type: "number", description: "To-do list ID (required)" }, - status: { - type: "string", - enum: ["active", "archived", "trashed"], - description: "Filter by status" - }, - completed: { type: "boolean", description: "Filter by completion (true=completed, false=pending)" }, - }, - required: ["project_id", "todolist_id"], - }, - }, - { - name: "create_todo", - description: "Create a new to-do in a to-do list", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (required)" }, - todolist_id: { type: "number", description: "To-do list ID (required)" }, - content: { type: "string", description: "To-do content/title (required)" }, - description: { type: "string", description: "Rich text description (HTML)" }, - assignee_ids: { - type: "array", - items: { type: "number" }, - description: "Array of person IDs to assign" - }, - due_on: { type: "string", description: "Due date (YYYY-MM-DD)" }, - starts_on: { type: "string", description: "Start date (YYYY-MM-DD)" }, - notify: { type: "boolean", description: "Notify assignees (default: false)" }, - }, - required: ["project_id", "todolist_id", "content"], - }, - }, - { - name: "complete_todo", - description: "Mark a to-do as complete", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (required)" }, - todo_id: { type: "number", description: "To-do ID (required)" }, - }, - required: ["project_id", "todo_id"], - }, - }, - { - name: "list_messages", - description: "List messages from a project's message board", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (required)" }, - message_board_id: { type: "number", description: "Message board ID (required, get from project dock)" }, - }, - required: ["project_id", "message_board_id"], - }, - }, - { - name: "create_message", - description: "Create a new message on a project's message board", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (required)" }, - message_board_id: { type: "number", description: "Message board ID (required)" }, - subject: { type: "string", description: "Message subject (required)" }, - content: { type: "string", description: "Message content in HTML (required)" }, - status: { - type: "string", - enum: ["active", "draft"], - description: "Post status (default: active)" - }, - category_id: { type: "number", description: "Message type/category ID" }, - }, - required: ["project_id", "message_board_id", "subject", "content"], - }, - }, - { - name: "list_people", - description: "List all people in the Basecamp account or a specific project", - inputSchema: { - type: "object", - properties: { - project_id: { type: "number", description: "Project ID (optional - if provided, lists project members only)" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_projects": { - let endpoint = "/projects.json"; - if (args.status === "archived") { - endpoint = "/projects/archive.json"; - } - else if (args.status === "trashed") { - endpoint = "/projects/trash.json"; - } - return await client.get(endpoint); - } - case "get_project": { - const { project_id } = args; - return await client.get(`/projects/${project_id}.json`); - } - case "list_todos": { - const { project_id, todolist_id, completed } = args; - let endpoint = `/buckets/${project_id}/todolists/${todolist_id}/todos.json`; - if (completed === true) { - endpoint += "?completed=true"; - } - return await client.get(endpoint); - } - case "create_todo": { - const { project_id, todolist_id, content, description, assignee_ids, due_on, starts_on, notify } = args; - const payload = { content }; - if (description) - payload.description = description; - if (assignee_ids) - payload.assignee_ids = assignee_ids; - if (due_on) - payload.due_on = due_on; - if (starts_on) - payload.starts_on = starts_on; - if (notify !== undefined) - payload.notify = notify; - return await client.post(`/buckets/${project_id}/todolists/${todolist_id}/todos.json`, payload); - } - case "complete_todo": { - const { project_id, todo_id } = args; - return await client.post(`/buckets/${project_id}/todos/${todo_id}/completion.json`, {}); - } - case "list_messages": { - const { project_id, message_board_id } = args; - return await client.get(`/buckets/${project_id}/message_boards/${message_board_id}/messages.json`); - } - case "create_message": { - const { project_id, message_board_id, subject, content, status, category_id } = args; - const payload = { subject, content }; - if (status) - payload.status = status; - if (category_id) - payload.category_id = category_id; - return await client.post(`/buckets/${project_id}/message_boards/${message_board_id}/messages.json`, payload); - } - case "list_people": { - const { project_id } = args; - if (project_id) { - return await client.get(`/projects/${project_id}/people.json`); - } - return await client.get("/people.json"); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.BASECAMP_ACCESS_TOKEN; - const accountId = process.env.BASECAMP_ACCOUNT_ID; - const appIdentity = process.env.BASECAMP_APP_IDENTITY || "MCPServer (mcp@example.com)"; - if (!accessToken) { - console.error("Error: BASECAMP_ACCESS_TOKEN environment variable required"); - console.error("Obtain via OAuth 2.0 flow: https://github.com/basecamp/api/blob/master/sections/authentication.md"); - process.exit(1); - } - if (!accountId) { - console.error("Error: BASECAMP_ACCOUNT_ID environment variable required"); - console.error("Find your account ID in the Basecamp URL: https://3.basecamp.com/{ACCOUNT_ID}/"); - process.exit(1); - } - const client = new BasecampClient(accessToken, accountId, appIdentity); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/bigcommerce/dist/index.d.ts b/mcp-diagrams/mcp-servers/bigcommerce/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/bigcommerce/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/bigcommerce/dist/index.js b/mcp-diagrams/mcp-servers/bigcommerce/dist/index.js deleted file mode 100644 index a50ca47..0000000 --- a/mcp-diagrams/mcp-servers/bigcommerce/dist/index.js +++ /dev/null @@ -1,421 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// BIGCOMMERCE MCP SERVER -// API Docs: https://developer.bigcommerce.com/docs/api -// ============================================ -const MCP_NAME = "bigcommerce"; -const MCP_VERSION = "1.0.0"; -// ============================================ -// API CLIENT - OAuth2/API Token Authentication -// ============================================ -class BigCommerceClient { - accessToken; - storeHash; - baseUrlV3; - baseUrlV2; - constructor(accessToken, storeHash) { - this.accessToken = accessToken; - this.storeHash = storeHash; - this.baseUrlV3 = `https://api.bigcommerce.com/stores/${storeHash}/v3`; - this.baseUrlV2 = `https://api.bigcommerce.com/stores/${storeHash}/v2`; - } - async request(url, options = {}) { - const response = await fetch(url, { - ...options, - headers: { - "X-Auth-Token": this.accessToken, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`BigCommerce API error: ${response.status} ${response.statusText} - ${errorText}`); - } - // Handle 204 No Content - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async getV3(endpoint, params) { - const queryString = params ? '?' + new URLSearchParams(params).toString() : ''; - return this.request(`${this.baseUrlV3}${endpoint}${queryString}`, { method: "GET" }); - } - async getV2(endpoint, params) { - const queryString = params ? '?' + new URLSearchParams(params).toString() : ''; - return this.request(`${this.baseUrlV2}${endpoint}${queryString}`, { method: "GET" }); - } - async postV3(endpoint, data) { - return this.request(`${this.baseUrlV3}${endpoint}`, { - method: "POST", - body: JSON.stringify(data), - }); - } - async putV3(endpoint, data) { - return this.request(`${this.baseUrlV3}${endpoint}`, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async putV2(endpoint, data) { - return this.request(`${this.baseUrlV2}${endpoint}`, { - method: "PUT", - body: JSON.stringify(data), - }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_products", - description: "List products from BigCommerce catalog with filtering and pagination", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max products to return (default 50, max 250)" }, - page: { type: "number", description: "Page number for pagination" }, - name: { type: "string", description: "Filter by product name (partial match)" }, - sku: { type: "string", description: "Filter by SKU" }, - brand_id: { type: "number", description: "Filter by brand ID" }, - categories: { type: "string", description: "Filter by category ID(s), comma-separated" }, - is_visible: { type: "boolean", description: "Filter by visibility status" }, - availability: { type: "string", description: "Filter by availability: available, disabled, preorder" }, - include: { type: "string", description: "Sub-resources to include: variants, images, custom_fields, bulk_pricing_rules, primary_image, modifiers, options, videos" }, - }, - }, - }, - { - name: "get_product", - description: "Get a specific product by ID with full details", - inputSchema: { - type: "object", - properties: { - product_id: { type: "number", description: "Product ID" }, - include: { type: "string", description: "Sub-resources to include: variants, images, custom_fields, bulk_pricing_rules, primary_image, modifiers, options, videos" }, - }, - required: ["product_id"], - }, - }, - { - name: "create_product", - description: "Create a new product in BigCommerce catalog", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Product name (required)" }, - type: { type: "string", description: "Product type: physical, digital (required)" }, - weight: { type: "number", description: "Product weight (required for physical)" }, - price: { type: "number", description: "Product price (required)" }, - sku: { type: "string", description: "Stock Keeping Unit" }, - description: { type: "string", description: "Product description (HTML allowed)" }, - categories: { type: "array", description: "Array of category IDs", items: { type: "number" } }, - brand_id: { type: "number", description: "Brand ID" }, - inventory_level: { type: "number", description: "Current inventory level" }, - inventory_tracking: { type: "string", description: "Inventory tracking: none, product, variant" }, - is_visible: { type: "boolean", description: "Whether product is visible on storefront" }, - availability: { type: "string", description: "Availability: available, disabled, preorder" }, - cost_price: { type: "number", description: "Cost price for profit calculations" }, - sale_price: { type: "number", description: "Sale price" }, - }, - required: ["name", "type", "weight", "price"], - }, - }, - { - name: "update_product", - description: "Update an existing product in BigCommerce", - inputSchema: { - type: "object", - properties: { - product_id: { type: "number", description: "Product ID (required)" }, - name: { type: "string", description: "Product name" }, - price: { type: "number", description: "Product price" }, - sku: { type: "string", description: "Stock Keeping Unit" }, - description: { type: "string", description: "Product description" }, - categories: { type: "array", description: "Array of category IDs", items: { type: "number" } }, - inventory_level: { type: "number", description: "Current inventory level" }, - is_visible: { type: "boolean", description: "Whether product is visible" }, - availability: { type: "string", description: "Availability: available, disabled, preorder" }, - sale_price: { type: "number", description: "Sale price" }, - }, - required: ["product_id"], - }, - }, - { - name: "list_orders", - description: "List orders from BigCommerce (V2 API)", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max orders to return (default 50, max 250)" }, - page: { type: "number", description: "Page number for pagination" }, - min_date_created: { type: "string", description: "Filter by min creation date (RFC 2822 or ISO 8601)" }, - max_date_created: { type: "string", description: "Filter by max creation date" }, - status_id: { type: "number", description: "Filter by status ID" }, - customer_id: { type: "number", description: "Filter by customer ID" }, - min_total: { type: "number", description: "Filter by minimum total" }, - max_total: { type: "number", description: "Filter by maximum total" }, - is_deleted: { type: "boolean", description: "Include deleted orders" }, - sort: { type: "string", description: "Sort field: id, date_created, date_modified, status_id" }, - }, - }, - }, - { - name: "get_order", - description: "Get a specific order by ID with full details", - inputSchema: { - type: "object", - properties: { - order_id: { type: "number", description: "Order ID" }, - include_products: { type: "boolean", description: "Include order products (separate call)" }, - include_shipping: { type: "boolean", description: "Include shipping addresses (separate call)" }, - }, - required: ["order_id"], - }, - }, - { - name: "list_customers", - description: "List customers from BigCommerce", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max customers to return (default 50, max 250)" }, - page: { type: "number", description: "Page number for pagination" }, - email: { type: "string", description: "Filter by email address" }, - name: { type: "string", description: "Filter by name (first or last)" }, - company: { type: "string", description: "Filter by company name" }, - customer_group_id: { type: "number", description: "Filter by customer group ID" }, - date_created_min: { type: "string", description: "Filter by minimum creation date" }, - date_created_max: { type: "string", description: "Filter by maximum creation date" }, - include: { type: "string", description: "Sub-resources: addresses, storecredit, attributes, formfields" }, - }, - }, - }, - { - name: "update_inventory", - description: "Update inventory level for a product or variant", - inputSchema: { - type: "object", - properties: { - product_id: { type: "number", description: "Product ID (required)" }, - variant_id: { type: "number", description: "Variant ID (if updating variant inventory)" }, - inventory_level: { type: "number", description: "New inventory level (required)" }, - inventory_warning_level: { type: "number", description: "Low stock warning threshold" }, - }, - required: ["product_id", "inventory_level"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_products": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.page) - params.page = String(args.page); - if (args.name) - params['name:like'] = args.name; - if (args.sku) - params.sku = args.sku; - if (args.brand_id) - params.brand_id = String(args.brand_id); - if (args.categories) - params['categories:in'] = args.categories; - if (args.is_visible !== undefined) - params.is_visible = String(args.is_visible); - if (args.availability) - params.availability = args.availability; - if (args.include) - params.include = args.include; - return await client.getV3("/catalog/products", params); - } - case "get_product": { - const params = {}; - if (args.include) - params.include = args.include; - return await client.getV3(`/catalog/products/${args.product_id}`, params); - } - case "create_product": { - const productData = { - name: args.name, - type: args.type, - weight: args.weight, - price: args.price, - }; - if (args.sku) - productData.sku = args.sku; - if (args.description) - productData.description = args.description; - if (args.categories) - productData.categories = args.categories; - if (args.brand_id) - productData.brand_id = args.brand_id; - if (args.inventory_level !== undefined) - productData.inventory_level = args.inventory_level; - if (args.inventory_tracking) - productData.inventory_tracking = args.inventory_tracking; - if (args.is_visible !== undefined) - productData.is_visible = args.is_visible; - if (args.availability) - productData.availability = args.availability; - if (args.cost_price !== undefined) - productData.cost_price = args.cost_price; - if (args.sale_price !== undefined) - productData.sale_price = args.sale_price; - return await client.postV3("/catalog/products", productData); - } - case "update_product": { - const updateData = {}; - if (args.name) - updateData.name = args.name; - if (args.price !== undefined) - updateData.price = args.price; - if (args.sku) - updateData.sku = args.sku; - if (args.description) - updateData.description = args.description; - if (args.categories) - updateData.categories = args.categories; - if (args.inventory_level !== undefined) - updateData.inventory_level = args.inventory_level; - if (args.is_visible !== undefined) - updateData.is_visible = args.is_visible; - if (args.availability) - updateData.availability = args.availability; - if (args.sale_price !== undefined) - updateData.sale_price = args.sale_price; - return await client.putV3(`/catalog/products/${args.product_id}`, updateData); - } - case "list_orders": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.page) - params.page = String(args.page); - if (args.min_date_created) - params.min_date_created = args.min_date_created; - if (args.max_date_created) - params.max_date_created = args.max_date_created; - if (args.status_id) - params.status_id = String(args.status_id); - if (args.customer_id) - params.customer_id = String(args.customer_id); - if (args.min_total) - params.min_total = String(args.min_total); - if (args.max_total) - params.max_total = String(args.max_total); - if (args.is_deleted !== undefined) - params.is_deleted = String(args.is_deleted); - if (args.sort) - params.sort = args.sort; - return await client.getV2("/orders", params); - } - case "get_order": { - const order = await client.getV2(`/orders/${args.order_id}`); - const result = { order }; - if (args.include_products) { - result.products = await client.getV2(`/orders/${args.order_id}/products`); - } - if (args.include_shipping) { - result.shipping_addresses = await client.getV2(`/orders/${args.order_id}/shipping_addresses`); - } - return result; - } - case "list_customers": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.page) - params.page = String(args.page); - if (args.email) - params['email:in'] = args.email; - if (args.name) - params['name:like'] = args.name; - if (args.company) - params['company:like'] = args.company; - if (args.customer_group_id) - params.customer_group_id = String(args.customer_group_id); - if (args.date_created_min) - params['date_created:min'] = args.date_created_min; - if (args.date_created_max) - params['date_created:max'] = args.date_created_max; - if (args.include) - params.include = args.include; - return await client.getV3("/customers", params); - } - case "update_inventory": { - if (args.variant_id) { - // Update variant inventory - const variantData = { - inventory_level: args.inventory_level, - }; - if (args.inventory_warning_level !== undefined) { - variantData.inventory_warning_level = args.inventory_warning_level; - } - return await client.putV3(`/catalog/products/${args.product_id}/variants/${args.variant_id}`, variantData); - } - else { - // Update product inventory - const productData = { - inventory_level: args.inventory_level, - }; - if (args.inventory_warning_level !== undefined) { - productData.inventory_warning_level = args.inventory_warning_level; - } - return await client.putV3(`/catalog/products/${args.product_id}`, productData); - } - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.BIGCOMMERCE_ACCESS_TOKEN; - const storeHash = process.env.BIGCOMMERCE_STORE_HASH; - if (!accessToken) { - console.error("Error: BIGCOMMERCE_ACCESS_TOKEN environment variable required"); - process.exit(1); - } - if (!storeHash) { - console.error("Error: BIGCOMMERCE_STORE_HASH environment variable required"); - process.exit(1); - } - const client = new BigCommerceClient(accessToken, storeHash); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/brevo/dist/index.d.ts b/mcp-diagrams/mcp-servers/brevo/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/brevo/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/brevo/dist/index.js b/mcp-diagrams/mcp-servers/brevo/dist/index.js deleted file mode 100644 index 9b105ad..0000000 --- a/mcp-diagrams/mcp-servers/brevo/dist/index.js +++ /dev/null @@ -1,398 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "brevo"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.brevo.com/v3"; -// ============================================ -// API CLIENT - Brevo uses api-key header -// ============================================ -class BrevoClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "api-key": this.apiKey, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const text = await response.text(); - throw new Error(`Brevo API error: ${response.status} ${response.statusText} - ${text}`); - } - // Some endpoints return 204 No Content - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "send_email", - description: "Send a transactional email", - inputSchema: { - type: "object", - properties: { - to: { - type: "array", - description: "Array of recipient objects with email and optional name", - items: { - type: "object", - properties: { - email: { type: "string" }, - name: { type: "string" } - }, - required: ["email"] - } - }, - sender: { - type: "object", - description: "Sender object with email and optional name", - properties: { - email: { type: "string" }, - name: { type: "string" } - }, - required: ["email"] - }, - subject: { type: "string", description: "Email subject" }, - htmlContent: { type: "string", description: "HTML content of the email" }, - textContent: { type: "string", description: "Plain text content" }, - templateId: { type: "number", description: "Template ID to use instead of content" }, - params: { type: "object", description: "Template parameters" }, - replyTo: { type: "object", description: "Reply-to address" }, - attachment: { type: "array", description: "Array of attachment objects" }, - tags: { type: "array", items: { type: "string" }, description: "Tags for the email" }, - }, - required: ["to", "sender"], - }, - }, - { - name: "list_contacts", - description: "List contacts with optional filters", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Number of contacts to return (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - modifiedSince: { type: "string", description: "Filter by modification date (YYYY-MM-DD)" }, - sort: { type: "string", description: "Sort order (asc or desc)" }, - }, - }, - }, - { - name: "add_contact", - description: "Create a new contact", - inputSchema: { - type: "object", - properties: { - email: { type: "string", description: "Contact email address" }, - attributes: { type: "object", description: "Contact attributes (FIRSTNAME, LASTNAME, SMS, etc.)" }, - listIds: { type: "array", items: { type: "number" }, description: "List IDs to add contact to" }, - updateEnabled: { type: "boolean", description: "Update contact if already exists" }, - smtpBlacklistSender: { type: "array", items: { type: "string" }, description: "Blacklisted senders" }, - }, - required: ["email"], - }, - }, - { - name: "update_contact", - description: "Update an existing contact", - inputSchema: { - type: "object", - properties: { - identifier: { type: "string", description: "Email or contact ID" }, - attributes: { type: "object", description: "Contact attributes to update" }, - listIds: { type: "array", items: { type: "number" }, description: "List IDs to add contact to" }, - unlinkListIds: { type: "array", items: { type: "number" }, description: "List IDs to remove contact from" }, - emailBlacklisted: { type: "boolean", description: "Blacklist the contact email" }, - smsBlacklisted: { type: "boolean", description: "Blacklist the contact SMS" }, - }, - required: ["identifier"], - }, - }, - { - name: "list_campaigns", - description: "List email campaigns", - inputSchema: { - type: "object", - properties: { - type: { type: "string", description: "Campaign type (classic, trigger)" }, - status: { type: "string", description: "Campaign status (suspended, archive, sent, queued, draft, inProcess)" }, - limit: { type: "number", description: "Number of results (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - sort: { type: "string", description: "Sort order (asc or desc)" }, - }, - }, - }, - { - name: "create_campaign", - description: "Create a new email campaign", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Campaign name" }, - subject: { type: "string", description: "Email subject" }, - sender: { - type: "object", - description: "Sender object with email and name", - properties: { - email: { type: "string" }, - name: { type: "string" } - }, - required: ["email", "name"] - }, - htmlContent: { type: "string", description: "HTML content" }, - templateId: { type: "number", description: "Template ID to use" }, - recipients: { - type: "object", - description: "Recipients configuration", - properties: { - listIds: { type: "array", items: { type: "number" } }, - exclusionListIds: { type: "array", items: { type: "number" } } - } - }, - scheduledAt: { type: "string", description: "Schedule time (ISO 8601)" }, - replyTo: { type: "string", description: "Reply-to email address" }, - toField: { type: "string", description: "Personalization field for To header" }, - tag: { type: "string", description: "Campaign tag" }, - }, - required: ["name", "subject", "sender"], - }, - }, - { - name: "send_sms", - description: "Send a transactional SMS", - inputSchema: { - type: "object", - properties: { - sender: { type: "string", description: "Sender name (max 11 chars) or phone number" }, - recipient: { type: "string", description: "Recipient phone number with country code" }, - content: { type: "string", description: "SMS message content (max 160 chars for single SMS)" }, - type: { type: "string", description: "SMS type: transactional or marketing" }, - tag: { type: "string", description: "Tag for the SMS" }, - webUrl: { type: "string", description: "Webhook URL for delivery report" }, - }, - required: ["sender", "recipient", "content"], - }, - }, - { - name: "list_templates", - description: "List email templates", - inputSchema: { - type: "object", - properties: { - templateStatus: { type: "boolean", description: "Filter by active status" }, - limit: { type: "number", description: "Number of results (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - sort: { type: "string", description: "Sort order (asc or desc)" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "send_email": { - const payload = { - to: args.to, - sender: args.sender, - }; - if (args.subject) - payload.subject = args.subject; - if (args.htmlContent) - payload.htmlContent = args.htmlContent; - if (args.textContent) - payload.textContent = args.textContent; - if (args.templateId) - payload.templateId = args.templateId; - if (args.params) - payload.params = args.params; - if (args.replyTo) - payload.replyTo = args.replyTo; - if (args.attachment) - payload.attachment = args.attachment; - if (args.tags) - payload.tags = args.tags; - return await client.post("/smtp/email", payload); - } - case "list_contacts": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", String(args.limit)); - if (args.offset) - params.append("offset", String(args.offset)); - if (args.modifiedSince) - params.append("modifiedSince", args.modifiedSince); - if (args.sort) - params.append("sort", args.sort); - const query = params.toString(); - return await client.get(`/contacts${query ? `?${query}` : ""}`); - } - case "add_contact": { - const payload = { - email: args.email, - }; - if (args.attributes) - payload.attributes = args.attributes; - if (args.listIds) - payload.listIds = args.listIds; - if (args.updateEnabled !== undefined) - payload.updateEnabled = args.updateEnabled; - if (args.smtpBlacklistSender) - payload.smtpBlacklistSender = args.smtpBlacklistSender; - return await client.post("/contacts", payload); - } - case "update_contact": { - const payload = {}; - if (args.attributes) - payload.attributes = args.attributes; - if (args.listIds) - payload.listIds = args.listIds; - if (args.unlinkListIds) - payload.unlinkListIds = args.unlinkListIds; - if (args.emailBlacklisted !== undefined) - payload.emailBlacklisted = args.emailBlacklisted; - if (args.smsBlacklisted !== undefined) - payload.smsBlacklisted = args.smsBlacklisted; - return await client.put(`/contacts/${encodeURIComponent(args.identifier)}`, payload); - } - case "list_campaigns": { - const params = new URLSearchParams(); - if (args.type) - params.append("type", args.type); - if (args.status) - params.append("status", args.status); - if (args.limit) - params.append("limit", String(args.limit)); - if (args.offset) - params.append("offset", String(args.offset)); - if (args.sort) - params.append("sort", args.sort); - const query = params.toString(); - return await client.get(`/emailCampaigns${query ? `?${query}` : ""}`); - } - case "create_campaign": { - const payload = { - name: args.name, - subject: args.subject, - sender: args.sender, - }; - if (args.htmlContent) - payload.htmlContent = args.htmlContent; - if (args.templateId) - payload.templateId = args.templateId; - if (args.recipients) - payload.recipients = args.recipients; - if (args.scheduledAt) - payload.scheduledAt = args.scheduledAt; - if (args.replyTo) - payload.replyTo = args.replyTo; - if (args.toField) - payload.toField = args.toField; - if (args.tag) - payload.tag = args.tag; - return await client.post("/emailCampaigns", payload); - } - case "send_sms": { - const payload = { - sender: args.sender, - recipient: args.recipient, - content: args.content, - }; - if (args.type) - payload.type = args.type; - if (args.tag) - payload.tag = args.tag; - if (args.webUrl) - payload.webUrl = args.webUrl; - return await client.post("/transactionalSMS/sms", payload); - } - case "list_templates": { - const params = new URLSearchParams(); - if (args.templateStatus !== undefined) - params.append("templateStatus", String(args.templateStatus)); - if (args.limit) - params.append("limit", String(args.limit)); - if (args.offset) - params.append("offset", String(args.offset)); - if (args.sort) - params.append("sort", args.sort); - const query = params.toString(); - return await client.get(`/smtp/templates${query ? `?${query}` : ""}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.BREVO_API_KEY; - if (!apiKey) { - console.error("Error: BREVO_API_KEY environment variable required"); - process.exit(1); - } - const client = new BrevoClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/calendly/dist/index.d.ts b/mcp-diagrams/mcp-servers/calendly/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/calendly/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/calendly/dist/index.js b/mcp-diagrams/mcp-servers/calendly/dist/index.js deleted file mode 100644 index 5cf05ee..0000000 --- a/mcp-diagrams/mcp-servers/calendly/dist/index.js +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "calendly"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.calendly.com"; -// ============================================ -// API CLIENT - Calendly API v2 -// ============================================ -class CalendlyClient { - apiKey; - baseUrl; - currentUserUri = null; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Calendly API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } - async getCurrentUser() { - if (!this.currentUserUri) { - const result = await this.get("/users/me"); - this.currentUserUri = result.resource.uri; - } - return this.currentUserUri; - } -} -// ============================================ -// TOOL DEFINITIONS - Calendly API v2 -// ============================================ -const tools = [ - { - name: "list_events", - description: "List scheduled events. Returns events for the authenticated user within the specified time range.", - inputSchema: { - type: "object", - properties: { - count: { type: "number", description: "Number of events to return (max 100)" }, - min_start_time: { type: "string", description: "Start of time range (ISO 8601 format)" }, - max_start_time: { type: "string", description: "End of time range (ISO 8601 format)" }, - status: { type: "string", enum: ["active", "canceled"], description: "Filter by event status" }, - page_token: { type: "string", description: "Token for pagination" }, - }, - }, - }, - { - name: "get_event", - description: "Get details of a specific scheduled event by its UUID", - inputSchema: { - type: "object", - properties: { - event_uuid: { type: "string", description: "The UUID of the scheduled event" }, - }, - required: ["event_uuid"], - }, - }, - { - name: "cancel_event", - description: "Cancel a scheduled event. Optionally provide a reason for cancellation.", - inputSchema: { - type: "object", - properties: { - event_uuid: { type: "string", description: "The UUID of the scheduled event to cancel" }, - reason: { type: "string", description: "Reason for cancellation (optional)" }, - }, - required: ["event_uuid"], - }, - }, - { - name: "list_event_types", - description: "List all event types available for the authenticated user", - inputSchema: { - type: "object", - properties: { - count: { type: "number", description: "Number of event types to return (max 100)" }, - active: { type: "boolean", description: "Filter by active status" }, - page_token: { type: "string", description: "Token for pagination" }, - }, - }, - }, - { - name: "get_availability", - description: "Get available time slots for an event type", - inputSchema: { - type: "object", - properties: { - event_type_uuid: { type: "string", description: "The UUID of the event type" }, - start_time: { type: "string", description: "Start of availability window (ISO 8601)" }, - end_time: { type: "string", description: "End of availability window (ISO 8601)" }, - }, - required: ["event_type_uuid", "start_time", "end_time"], - }, - }, - { - name: "list_invitees", - description: "List invitees for a scheduled event", - inputSchema: { - type: "object", - properties: { - event_uuid: { type: "string", description: "The UUID of the scheduled event" }, - count: { type: "number", description: "Number of invitees to return (max 100)" }, - status: { type: "string", enum: ["active", "canceled"], description: "Filter by invitee status" }, - page_token: { type: "string", description: "Token for pagination" }, - }, - required: ["event_uuid"], - }, - }, - { - name: "get_user", - description: "Get the current authenticated user's information", - inputSchema: { - type: "object", - properties: {}, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_events": { - const userUri = await client.getCurrentUser(); - const params = new URLSearchParams({ user: userUri }); - if (args.count) - params.append("count", String(args.count)); - if (args.min_start_time) - params.append("min_start_time", args.min_start_time); - if (args.max_start_time) - params.append("max_start_time", args.max_start_time); - if (args.status) - params.append("status", args.status); - if (args.page_token) - params.append("page_token", args.page_token); - return await client.get(`/scheduled_events?${params.toString()}`); - } - case "get_event": { - const { event_uuid } = args; - return await client.get(`/scheduled_events/${event_uuid}`); - } - case "cancel_event": { - const { event_uuid, reason } = args; - const body = {}; - if (reason) - body.reason = reason; - return await client.post(`/scheduled_events/${event_uuid}/cancellation`, body); - } - case "list_event_types": { - const userUri = await client.getCurrentUser(); - const params = new URLSearchParams({ user: userUri }); - if (args.count) - params.append("count", String(args.count)); - if (args.active !== undefined) - params.append("active", String(args.active)); - if (args.page_token) - params.append("page_token", args.page_token); - return await client.get(`/event_types?${params.toString()}`); - } - case "get_availability": { - const { event_type_uuid, start_time, end_time } = args; - const params = new URLSearchParams({ - start_time, - end_time, - }); - return await client.get(`/event_type_available_times?event_type=https://api.calendly.com/event_types/${event_type_uuid}&${params.toString()}`); - } - case "list_invitees": { - const { event_uuid, count, status, page_token } = args; - const params = new URLSearchParams(); - if (count) - params.append("count", String(count)); - if (status) - params.append("status", status); - if (page_token) - params.append("page_token", page_token); - const queryString = params.toString(); - return await client.get(`/scheduled_events/${event_uuid}/invitees${queryString ? '?' + queryString : ''}`); - } - case "get_user": { - return await client.get("/users/me"); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.CALENDLY_API_KEY; - if (!apiKey) { - console.error("Error: CALENDLY_API_KEY environment variable required"); - console.error("Get your Personal Access Token from: https://calendly.com/integrations/api_webhooks"); - process.exit(1); - } - const client = new CalendlyClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/clickup/dist/index.d.ts b/mcp-diagrams/mcp-servers/clickup/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/clickup/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/clickup/dist/index.js b/mcp-diagrams/mcp-servers/clickup/dist/index.js deleted file mode 100644 index 71db5f7..0000000 --- a/mcp-diagrams/mcp-servers/clickup/dist/index.js +++ /dev/null @@ -1,458 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "clickup"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.clickup.com/api/v2"; -// ============================================ -// API CLIENT -// ============================================ -class ClickUpClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": this.apiKey, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`ClickUp API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - // Handle empty responses (like 204 No Content) - const text = await response.text(); - return text ? JSON.parse(text) : { success: true }; - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - // Space endpoints - async listSpaces(teamId, archived) { - const params = new URLSearchParams(); - if (archived !== undefined) - params.append("archived", archived.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/team/${teamId}/space${query}`); - } - // List endpoints - async listLists(folderId, archived) { - const params = new URLSearchParams(); - if (archived !== undefined) - params.append("archived", archived.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/folder/${folderId}/list${query}`); - } - async listFolderlessLists(spaceId, archived) { - const params = new URLSearchParams(); - if (archived !== undefined) - params.append("archived", archived.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/space/${spaceId}/list${query}`); - } - // Task endpoints - async listTasks(listId, options) { - const params = new URLSearchParams(); - if (options?.archived !== undefined) - params.append("archived", options.archived.toString()); - if (options?.page !== undefined) - params.append("page", options.page.toString()); - if (options?.order_by) - params.append("order_by", options.order_by); - if (options?.reverse !== undefined) - params.append("reverse", options.reverse.toString()); - if (options?.subtasks !== undefined) - params.append("subtasks", options.subtasks.toString()); - if (options?.include_closed !== undefined) - params.append("include_closed", options.include_closed.toString()); - if (options?.statuses) - options.statuses.forEach(s => params.append("statuses[]", s)); - if (options?.assignees) - options.assignees.forEach(a => params.append("assignees[]", a)); - if (options?.due_date_gt) - params.append("due_date_gt", options.due_date_gt.toString()); - if (options?.due_date_lt) - params.append("due_date_lt", options.due_date_lt.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/list/${listId}/task${query}`); - } - async getTask(taskId, includeSubtasks) { - const params = new URLSearchParams(); - if (includeSubtasks !== undefined) - params.append("include_subtasks", includeSubtasks.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/task/${taskId}${query}`); - } - async createTask(listId, data) { - return this.post(`/list/${listId}/task`, data); - } - async updateTask(taskId, data) { - return this.put(`/task/${taskId}`, data); - } - // Comment endpoints - async addComment(taskId, commentText, assignee, notifyAll) { - const payload = { comment_text: commentText }; - if (assignee) - payload.assignee = assignee; - if (notifyAll !== undefined) - payload.notify_all = notifyAll; - return this.post(`/task/${taskId}/comment`, payload); - } - // Time tracking endpoints - async getTimeEntries(teamId, options) { - const params = new URLSearchParams(); - if (options?.start_date) - params.append("start_date", options.start_date.toString()); - if (options?.end_date) - params.append("end_date", options.end_date.toString()); - if (options?.assignee) - params.append("assignee", options.assignee); - if (options?.include_task_tags !== undefined) - params.append("include_task_tags", options.include_task_tags.toString()); - if (options?.include_location_names !== undefined) - params.append("include_location_names", options.include_location_names.toString()); - if (options?.space_id) - params.append("space_id", options.space_id); - if (options?.folder_id) - params.append("folder_id", options.folder_id); - if (options?.list_id) - params.append("list_id", options.list_id); - if (options?.task_id) - params.append("task_id", options.task_id); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/team/${teamId}/time_entries${query}`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_spaces", - description: "List all spaces in a ClickUp workspace/team", - inputSchema: { - type: "object", - properties: { - team_id: { type: "string", description: "The workspace/team ID" }, - archived: { type: "boolean", description: "Include archived spaces" }, - }, - required: ["team_id"], - }, - }, - { - name: "list_lists", - description: "List all lists in a folder or space (folderless lists)", - inputSchema: { - type: "object", - properties: { - folder_id: { type: "string", description: "The folder ID (for lists in a folder)" }, - space_id: { type: "string", description: "The space ID (for folderless lists)" }, - archived: { type: "boolean", description: "Include archived lists" }, - }, - }, - }, - { - name: "list_tasks", - description: "List tasks in a list with optional filters", - inputSchema: { - type: "object", - properties: { - list_id: { type: "string", description: "The list ID" }, - archived: { type: "boolean", description: "Filter by archived status" }, - page: { type: "number", description: "Page number (0-indexed)" }, - order_by: { - type: "string", - description: "Order by field: id, created, updated, due_date", - enum: ["id", "created", "updated", "due_date"] - }, - reverse: { type: "boolean", description: "Reverse order" }, - subtasks: { type: "boolean", description: "Include subtasks" }, - include_closed: { type: "boolean", description: "Include closed tasks" }, - statuses: { - type: "array", - items: { type: "string" }, - description: "Filter by status names" - }, - assignees: { - type: "array", - items: { type: "string" }, - description: "Filter by assignee user IDs" - }, - }, - required: ["list_id"], - }, - }, - { - name: "get_task", - description: "Get detailed information about a specific task", - inputSchema: { - type: "object", - properties: { - task_id: { type: "string", description: "The task ID" }, - include_subtasks: { type: "boolean", description: "Include subtask details" }, - }, - required: ["task_id"], - }, - }, - { - name: "create_task", - description: "Create a new task in a list", - inputSchema: { - type: "object", - properties: { - list_id: { type: "string", description: "The list ID to create the task in" }, - name: { type: "string", description: "Task name" }, - description: { type: "string", description: "Task description (supports markdown)" }, - assignees: { - type: "array", - items: { type: "string" }, - description: "Array of user IDs to assign" - }, - tags: { - type: "array", - items: { type: "string" }, - description: "Array of tag names" - }, - status: { type: "string", description: "Status name" }, - priority: { - type: "number", - description: "Priority: 1=urgent, 2=high, 3=normal, 4=low", - enum: [1, 2, 3, 4] - }, - due_date: { type: "number", description: "Due date as Unix timestamp in milliseconds" }, - start_date: { type: "number", description: "Start date as Unix timestamp in milliseconds" }, - time_estimate: { type: "number", description: "Time estimate in milliseconds" }, - parent: { type: "string", description: "Parent task ID (to create as subtask)" }, - }, - required: ["list_id", "name"], - }, - }, - { - name: "update_task", - description: "Update an existing task", - inputSchema: { - type: "object", - properties: { - task_id: { type: "string", description: "The task ID to update" }, - name: { type: "string", description: "New task name" }, - description: { type: "string", description: "New task description" }, - status: { type: "string", description: "New status name" }, - priority: { - type: "number", - description: "Priority: 1=urgent, 2=high, 3=normal, 4=low, null=none", - enum: [1, 2, 3, 4] - }, - due_date: { type: "number", description: "Due date as Unix timestamp in milliseconds" }, - start_date: { type: "number", description: "Start date as Unix timestamp in milliseconds" }, - time_estimate: { type: "number", description: "Time estimate in milliseconds" }, - assignees_add: { - type: "array", - items: { type: "string" }, - description: "User IDs to add as assignees" - }, - assignees_remove: { - type: "array", - items: { type: "string" }, - description: "User IDs to remove from assignees" - }, - archived: { type: "boolean", description: "Archive or unarchive the task" }, - }, - required: ["task_id"], - }, - }, - { - name: "add_comment", - description: "Add a comment to a task", - inputSchema: { - type: "object", - properties: { - task_id: { type: "string", description: "The task ID" }, - comment_text: { type: "string", description: "Comment text (supports markdown)" }, - assignee: { type: "string", description: "User ID to assign the comment to" }, - notify_all: { type: "boolean", description: "Notify all assignees" }, - }, - required: ["task_id", "comment_text"], - }, - }, - { - name: "get_time_entries", - description: "Get time tracking entries for a workspace", - inputSchema: { - type: "object", - properties: { - team_id: { type: "string", description: "The workspace/team ID" }, - start_date: { type: "number", description: "Start date as Unix timestamp in milliseconds" }, - end_date: { type: "number", description: "End date as Unix timestamp in milliseconds" }, - assignee: { type: "string", description: "Filter by user ID" }, - task_id: { type: "string", description: "Filter by task ID" }, - list_id: { type: "string", description: "Filter by list ID" }, - space_id: { type: "string", description: "Filter by space ID" }, - include_task_tags: { type: "boolean", description: "Include task tags in response" }, - include_location_names: { type: "boolean", description: "Include location names in response" }, - }, - required: ["team_id"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_spaces": { - const { team_id, archived } = args; - return await client.listSpaces(team_id, archived); - } - case "list_lists": { - const { folder_id, space_id, archived } = args; - if (folder_id) { - return await client.listLists(folder_id, archived); - } - else if (space_id) { - return await client.listFolderlessLists(space_id, archived); - } - else { - throw new Error("Either folder_id or space_id is required"); - } - } - case "list_tasks": { - const { list_id, archived, page, order_by, reverse, subtasks, include_closed, statuses, assignees } = args; - return await client.listTasks(list_id, { - archived, - page, - order_by, - reverse, - subtasks, - include_closed, - statuses, - assignees, - }); - } - case "get_task": { - const { task_id, include_subtasks } = args; - return await client.getTask(task_id, include_subtasks); - } - case "create_task": { - const { list_id, name, description, assignees, tags, status, priority, due_date, start_date, time_estimate, parent } = args; - return await client.createTask(list_id, { - name, - description, - assignees, - tags, - status, - priority, - due_date, - start_date, - time_estimate, - parent, - }); - } - case "update_task": { - const { task_id, name, description, status, priority, due_date, start_date, time_estimate, assignees_add, assignees_remove, archived } = args; - const updateData = {}; - if (name !== undefined) - updateData.name = name; - if (description !== undefined) - updateData.description = description; - if (status !== undefined) - updateData.status = status; - if (priority !== undefined) - updateData.priority = priority; - if (due_date !== undefined) - updateData.due_date = due_date; - if (start_date !== undefined) - updateData.start_date = start_date; - if (time_estimate !== undefined) - updateData.time_estimate = time_estimate; - if (archived !== undefined) - updateData.archived = archived; - if (assignees_add || assignees_remove) { - updateData.assignees = {}; - if (assignees_add) - updateData.assignees.add = assignees_add; - if (assignees_remove) - updateData.assignees.rem = assignees_remove; - } - return await client.updateTask(task_id, updateData); - } - case "add_comment": { - const { task_id, comment_text, assignee, notify_all } = args; - return await client.addComment(task_id, comment_text, assignee, notify_all); - } - case "get_time_entries": { - const { team_id, start_date, end_date, assignee, task_id, list_id, space_id, include_task_tags, include_location_names } = args; - return await client.getTimeEntries(team_id, { - start_date, - end_date, - assignee, - task_id, - list_id, - space_id, - include_task_tags, - include_location_names, - }); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.CLICKUP_API_KEY; - if (!apiKey) { - console.error("Error: CLICKUP_API_KEY environment variable required"); - console.error("Get your API key from ClickUp Settings > Apps > API Token"); - process.exit(1); - } - const client = new ClickUpClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/close/dist/index.d.ts b/mcp-diagrams/mcp-servers/close/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/close/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/close/dist/index.js b/mcp-diagrams/mcp-servers/close/dist/index.js deleted file mode 100644 index 3b2e8df..0000000 --- a/mcp-diagrams/mcp-servers/close/dist/index.js +++ /dev/null @@ -1,489 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "close"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.close.com/api/v1"; -// ============================================ -// REST API CLIENT -// ============================================ -class CloseClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - getAuthHeader() { - // Close uses Basic auth with API key as username, empty password - return `Basic ${Buffer.from(`${this.apiKey}:`).toString('base64')}`; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": this.getAuthHeader(), - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Close API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - return response.json(); - } - async get(endpoint, params = {}) { - const searchParams = new URLSearchParams(); - for (const [key, value] of Object.entries(params)) { - if (value !== undefined && value !== null) { - searchParams.append(key, String(value)); - } - } - const queryString = searchParams.toString(); - const url = queryString ? `${endpoint}?${queryString}` : endpoint; - return this.request(url, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_leads", - description: "List leads from Close CRM with optional search query", - inputSchema: { - type: "object", - properties: { - query: { type: "string", description: "Search query (Close query syntax)" }, - _limit: { type: "number", description: "Max results to return (default 100)" }, - _skip: { type: "number", description: "Number of results to skip (pagination)" }, - _fields: { type: "string", description: "Comma-separated list of fields to return" }, - }, - }, - }, - { - name: "get_lead", - description: "Get a specific lead by ID", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Lead ID (e.g., lead_xxx)" }, - }, - required: ["lead_id"], - }, - }, - { - name: "create_lead", - description: "Create a new lead in Close CRM", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Lead/Company name" }, - url: { type: "string", description: "Company website URL" }, - description: { type: "string", description: "Lead description" }, - status_id: { type: "string", description: "Lead status ID" }, - contacts: { - type: "array", - description: "Array of contacts to add to the lead", - items: { - type: "object", - properties: { - name: { type: "string", description: "Contact name" }, - title: { type: "string", description: "Job title" }, - emails: { - type: "array", - items: { - type: "object", - properties: { - email: { type: "string" }, - type: { type: "string", description: "office, home, direct, mobile, fax, other" }, - }, - }, - }, - phones: { - type: "array", - items: { - type: "object", - properties: { - phone: { type: "string" }, - type: { type: "string", description: "office, home, direct, mobile, fax, other" }, - }, - }, - }, - }, - }, - }, - addresses: { - type: "array", - description: "Lead addresses", - items: { - type: "object", - properties: { - address_1: { type: "string" }, - address_2: { type: "string" }, - city: { type: "string" }, - state: { type: "string" }, - zipcode: { type: "string" }, - country: { type: "string" }, - }, - }, - }, - custom: { type: "object", description: "Custom field values (key-value pairs)" }, - }, - required: ["name"], - }, - }, - { - name: "update_lead", - description: "Update an existing lead", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Lead ID to update" }, - name: { type: "string", description: "Lead/Company name" }, - url: { type: "string", description: "Company website URL" }, - description: { type: "string", description: "Lead description" }, - status_id: { type: "string", description: "Lead status ID" }, - custom: { type: "object", description: "Custom field values to update" }, - }, - required: ["lead_id"], - }, - }, - { - name: "list_opportunities", - description: "List opportunities from Close CRM", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Filter by lead ID" }, - status_id: { type: "string", description: "Filter by opportunity status ID" }, - user_id: { type: "string", description: "Filter by assigned user ID" }, - _limit: { type: "number", description: "Max results to return" }, - _skip: { type: "number", description: "Number of results to skip" }, - }, - }, - }, - { - name: "create_opportunity", - description: "Create a new opportunity/deal", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Lead ID to attach opportunity to" }, - status_id: { type: "string", description: "Opportunity status ID" }, - value: { type: "number", description: "Deal value in cents" }, - value_period: { type: "string", description: "one_time, monthly, annual" }, - confidence: { type: "number", description: "Confidence percentage (0-100)" }, - note: { type: "string", description: "Opportunity notes" }, - date_won: { type: "string", description: "Date won (YYYY-MM-DD)" }, - }, - required: ["lead_id"], - }, - }, - { - name: "create_activity", - description: "Create an activity (note, call, email, meeting, etc.)", - inputSchema: { - type: "object", - properties: { - activity_type: { type: "string", description: "Type: Note, Call, Email, Meeting, SMS" }, - lead_id: { type: "string", description: "Lead ID for the activity" }, - contact_id: { type: "string", description: "Contact ID (optional)" }, - user_id: { type: "string", description: "User ID who performed activity" }, - note: { type: "string", description: "Activity note/body content" }, - subject: { type: "string", description: "Subject (for emails)" }, - status: { type: "string", description: "Call status: completed, no-answer, busy, etc." }, - direction: { type: "string", description: "inbound or outbound" }, - duration: { type: "number", description: "Duration in seconds (for calls)" }, - date_created: { type: "string", description: "Activity date (ISO 8601)" }, - }, - required: ["activity_type", "lead_id"], - }, - }, - { - name: "list_tasks", - description: "List tasks from Close CRM", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Filter by lead ID" }, - assigned_to: { type: "string", description: "Filter by assigned user ID" }, - is_complete: { type: "boolean", description: "Filter by completion status" }, - _type: { type: "string", description: "Task type: lead, opportunity, incoming_email, missed_call, etc." }, - _limit: { type: "number", description: "Max results to return" }, - _skip: { type: "number", description: "Number of results to skip" }, - }, - }, - }, - { - name: "create_task", - description: "Create a new task", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Lead ID for the task" }, - assigned_to: { type: "string", description: "User ID to assign task to" }, - text: { type: "string", description: "Task description" }, - date: { type: "string", description: "Due date (YYYY-MM-DD or ISO 8601)" }, - is_complete: { type: "boolean", description: "Task completion status" }, - }, - required: ["lead_id", "text"], - }, - }, - { - name: "send_email", - description: "Send an email through Close CRM", - inputSchema: { - type: "object", - properties: { - lead_id: { type: "string", description: "Lead ID" }, - contact_id: { type: "string", description: "Contact ID to send to" }, - to: { type: "array", items: { type: "string" }, description: "Recipient email addresses" }, - cc: { type: "array", items: { type: "string" }, description: "CC email addresses" }, - bcc: { type: "array", items: { type: "string" }, description: "BCC email addresses" }, - subject: { type: "string", description: "Email subject" }, - body_text: { type: "string", description: "Plain text body" }, - body_html: { type: "string", description: "HTML body" }, - status: { type: "string", description: "draft, outbox, sent" }, - template_id: { type: "string", description: "Email template ID to use" }, - }, - required: ["lead_id", "to", "subject"], - }, - }, - { - name: "list_statuses", - description: "List lead and opportunity statuses", - inputSchema: { - type: "object", - properties: { - type: { type: "string", description: "lead or opportunity" }, - }, - }, - }, - { - name: "list_users", - description: "List users in the Close organization", - inputSchema: { - type: "object", - properties: {}, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_leads": { - const { query, _limit = 100, _skip, _fields } = args; - const params = { _limit }; - if (query) - params.query = query; - if (_skip) - params._skip = _skip; - if (_fields) - params._fields = _fields; - return await client.get("/lead/", params); - } - case "get_lead": { - const { lead_id } = args; - return await client.get(`/lead/${lead_id}/`); - } - case "create_lead": { - const { name, url, description, status_id, contacts, addresses, custom } = args; - const data = { name }; - if (url) - data.url = url; - if (description) - data.description = description; - if (status_id) - data.status_id = status_id; - if (contacts) - data.contacts = contacts; - if (addresses) - data.addresses = addresses; - if (custom) - data.custom = custom; - return await client.post("/lead/", data); - } - case "update_lead": { - const { lead_id, ...updates } = args; - return await client.put(`/lead/${lead_id}/`, updates); - } - case "list_opportunities": { - const { lead_id, status_id, user_id, _limit = 100, _skip } = args; - const params = { _limit }; - if (lead_id) - params.lead_id = lead_id; - if (status_id) - params.status_id = status_id; - if (user_id) - params.user_id = user_id; - if (_skip) - params._skip = _skip; - return await client.get("/opportunity/", params); - } - case "create_opportunity": { - const { lead_id, status_id, value, value_period, confidence, note, date_won } = args; - const data = { lead_id }; - if (status_id) - data.status_id = status_id; - if (value !== undefined) - data.value = value; - if (value_period) - data.value_period = value_period; - if (confidence !== undefined) - data.confidence = confidence; - if (note) - data.note = note; - if (date_won) - data.date_won = date_won; - return await client.post("/opportunity/", data); - } - case "create_activity": { - const { activity_type, lead_id, contact_id, user_id, note, subject, status, direction, duration, date_created } = args; - // Map activity type to endpoint - const typeMap = { - 'Note': 'note', - 'Call': 'call', - 'Email': 'email', - 'Meeting': 'meeting', - 'SMS': 'sms', - }; - const endpoint = typeMap[activity_type] || activity_type.toLowerCase(); - const data = { lead_id }; - if (contact_id) - data.contact_id = contact_id; - if (user_id) - data.user_id = user_id; - if (note) - data.note = note; - if (subject) - data.subject = subject; - if (status) - data.status = status; - if (direction) - data.direction = direction; - if (duration) - data.duration = duration; - if (date_created) - data.date_created = date_created; - return await client.post(`/activity/${endpoint}/`, data); - } - case "list_tasks": { - const { lead_id, assigned_to, is_complete, _type, _limit = 100, _skip } = args; - const params = { _limit }; - if (lead_id) - params.lead_id = lead_id; - if (assigned_to) - params.assigned_to = assigned_to; - if (is_complete !== undefined) - params.is_complete = is_complete; - if (_type) - params._type = _type; - if (_skip) - params._skip = _skip; - return await client.get("/task/", params); - } - case "create_task": { - const { lead_id, assigned_to, text, date, is_complete } = args; - const data = { lead_id, text }; - if (assigned_to) - data.assigned_to = assigned_to; - if (date) - data.date = date; - if (is_complete !== undefined) - data.is_complete = is_complete; - return await client.post("/task/", data); - } - case "send_email": { - const { lead_id, contact_id, to, cc, bcc, subject, body_text, body_html, status, template_id } = args; - const data = { lead_id, to, subject }; - if (contact_id) - data.contact_id = contact_id; - if (cc) - data.cc = cc; - if (bcc) - data.bcc = bcc; - if (body_text) - data.body_text = body_text; - if (body_html) - data.body_html = body_html; - if (status) - data.status = status; - if (template_id) - data.template_id = template_id; - return await client.post("/activity/email/", data); - } - case "list_statuses": { - const { type } = args; - if (type === 'opportunity') { - return await client.get("/status/opportunity/"); - } - return await client.get("/status/lead/"); - } - case "list_users": { - return await client.get("/user/"); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.CLOSE_API_KEY; - if (!apiKey) { - console.error("Error: CLOSE_API_KEY environment variable required"); - console.error("Get your API key at Settings > Integrations > API Keys in Close"); - process.exit(1); - } - const client = new CloseClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/clover/dist/index.d.ts b/mcp-diagrams/mcp-servers/clover/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/clover/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/clover/dist/index.js b/mcp-diagrams/mcp-servers/clover/dist/index.js deleted file mode 100644 index 6d06cce..0000000 --- a/mcp-diagrams/mcp-servers/clover/dist/index.js +++ /dev/null @@ -1,323 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "clover"; -const MCP_VERSION = "1.0.0"; -// Clover API base URLs -// Production: https://api.clover.com (US/Canada), https://api.eu.clover.com (Europe), https://api.la.clover.com (LATAM) -// Sandbox: https://apisandbox.dev.clover.com -const API_BASE_URL = process.env.CLOVER_SANDBOX === "true" - ? "https://apisandbox.dev.clover.com" - : (process.env.CLOVER_REGION === "EU" - ? "https://api.eu.clover.com" - : process.env.CLOVER_REGION === "LA" - ? "https://api.la.clover.com" - : "https://api.clover.com"); -// ============================================ -// API CLIENT -// ============================================ -class CloverClient { - apiKey; - merchantId; - baseUrl; - constructor(apiKey, merchantId) { - this.apiKey = apiKey; - this.merchantId = merchantId; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Clover API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } - getMerchantId() { - return this.merchantId; - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_orders", - description: "List orders for the merchant. Returns paginated list of orders with details like totals, state, and timestamps.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max orders to return (default 100)" }, - offset: { type: "number", description: "Pagination offset" }, - filter: { type: "string", description: "Filter query (e.g., 'state=open')" }, - expand: { type: "string", description: "Expand related objects (e.g., 'lineItems,payments')" }, - }, - }, - }, - { - name: "get_order", - description: "Get a specific order by ID with full details including line items, payments, and discounts.", - inputSchema: { - type: "object", - properties: { - order_id: { type: "string", description: "Order ID" }, - expand: { type: "string", description: "Expand related objects (e.g., 'lineItems,payments,discounts')" }, - }, - required: ["order_id"], - }, - }, - { - name: "create_order", - description: "Create a new order. Use atomic_order for complete orders with line items in one call.", - inputSchema: { - type: "object", - properties: { - state: { type: "string", description: "Order state: 'open', 'locked', etc." }, - title: { type: "string", description: "Order title/note" }, - note: { type: "string", description: "Additional order notes" }, - order_type_id: { type: "string", description: "Order type ID" }, - line_items: { - type: "array", - description: "Array of line items with item_id, quantity, and optional modifications", - items: { - type: "object", - properties: { - item_id: { type: "string" }, - quantity: { type: "number" }, - price: { type: "number" }, - name: { type: "string" }, - } - } - }, - }, - }, - }, - { - name: "list_items", - description: "List inventory items (products) available for sale. Returns item details, prices, and stock info.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max items to return (default 100)" }, - offset: { type: "number", description: "Pagination offset" }, - filter: { type: "string", description: "Filter by name, SKU, etc." }, - expand: { type: "string", description: "Expand related objects (e.g., 'categories,modifierGroups,tags')" }, - }, - }, - }, - { - name: "get_inventory", - description: "Get inventory stock counts for items. Shows current quantity and tracking status.", - inputSchema: { - type: "object", - properties: { - item_id: { type: "string", description: "Specific item ID (optional - omit to get all)" }, - }, - }, - }, - { - name: "list_customers", - description: "List customers in the merchant's customer database. Includes contact info and marketing preferences.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max customers to return (default 100)" }, - offset: { type: "number", description: "Pagination offset" }, - filter: { type: "string", description: "Filter by name, email, phone" }, - expand: { type: "string", description: "Expand related objects (e.g., 'addresses,emailAddresses,phoneNumbers')" }, - }, - }, - }, - { - name: "list_payments", - description: "List payments processed by the merchant. Includes payment method, amount, status, and related order.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max payments to return (default 100)" }, - offset: { type: "number", description: "Pagination offset" }, - filter: { type: "string", description: "Filter by result (SUCCESS, DECLINED, etc.)" }, - expand: { type: "string", description: "Expand related objects (e.g., 'tender,order')" }, - }, - }, - }, - { - name: "get_merchant", - description: "Get merchant account information including business name, address, timezone, and settings.", - inputSchema: { - type: "object", - properties: { - expand: { type: "string", description: "Expand related objects (e.g., 'address,openingHours,owner')" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - const mId = client.getMerchantId(); - switch (name) { - case "list_orders": { - const { limit = 100, offset = 0, filter, expand } = args; - let endpoint = `/v3/merchants/${mId}/orders?limit=${limit}&offset=${offset}`; - if (filter) - endpoint += `&filter=${encodeURIComponent(filter)}`; - if (expand) - endpoint += `&expand=${encodeURIComponent(expand)}`; - return await client.get(endpoint); - } - case "get_order": { - const { order_id, expand } = args; - let endpoint = `/v3/merchants/${mId}/orders/${order_id}`; - if (expand) - endpoint += `?expand=${encodeURIComponent(expand)}`; - return await client.get(endpoint); - } - case "create_order": { - const { state = "open", title, note, order_type_id, line_items } = args; - // If line_items provided, use atomic order endpoint - if (line_items && line_items.length > 0) { - const orderData = { - orderCart: { - lineItems: line_items.map((item) => ({ - item: item.item_id ? { id: item.item_id } : undefined, - name: item.name, - price: item.price, - unitQty: item.quantity || 1, - })), - }, - }; - if (title) - orderData.orderCart.title = title; - if (note) - orderData.orderCart.note = note; - if (order_type_id) - orderData.orderCart.orderType = { id: order_type_id }; - return await client.post(`/v3/merchants/${mId}/atomic_order/orders`, orderData); - } - // Simple order creation - const orderData = { state }; - if (title) - orderData.title = title; - if (note) - orderData.note = note; - if (order_type_id) - orderData.orderType = { id: order_type_id }; - return await client.post(`/v3/merchants/${mId}/orders`, orderData); - } - case "list_items": { - const { limit = 100, offset = 0, filter, expand } = args; - let endpoint = `/v3/merchants/${mId}/items?limit=${limit}&offset=${offset}`; - if (filter) - endpoint += `&filter=${encodeURIComponent(filter)}`; - if (expand) - endpoint += `&expand=${encodeURIComponent(expand)}`; - return await client.get(endpoint); - } - case "get_inventory": { - const { item_id } = args; - if (item_id) { - return await client.get(`/v3/merchants/${mId}/item_stocks/${item_id}`); - } - return await client.get(`/v3/merchants/${mId}/item_stocks`); - } - case "list_customers": { - const { limit = 100, offset = 0, filter, expand } = args; - let endpoint = `/v3/merchants/${mId}/customers?limit=${limit}&offset=${offset}`; - if (filter) - endpoint += `&filter=${encodeURIComponent(filter)}`; - if (expand) - endpoint += `&expand=${encodeURIComponent(expand)}`; - return await client.get(endpoint); - } - case "list_payments": { - const { limit = 100, offset = 0, filter, expand } = args; - let endpoint = `/v3/merchants/${mId}/payments?limit=${limit}&offset=${offset}`; - if (filter) - endpoint += `&filter=${encodeURIComponent(filter)}`; - if (expand) - endpoint += `&expand=${encodeURIComponent(expand)}`; - return await client.get(endpoint); - } - case "get_merchant": { - const { expand } = args; - let endpoint = `/v3/merchants/${mId}`; - if (expand) - endpoint += `?expand=${encodeURIComponent(expand)}`; - return await client.get(endpoint); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.CLOVER_API_KEY; - const merchantId = process.env.CLOVER_MERCHANT_ID; - if (!apiKey) { - console.error("Error: CLOVER_API_KEY environment variable required"); - process.exit(1); - } - if (!merchantId) { - console.error("Error: CLOVER_MERCHANT_ID environment variable required"); - process.exit(1); - } - const client = new CloverClient(apiKey, merchantId); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/constant-contact/dist/index.d.ts b/mcp-diagrams/mcp-servers/constant-contact/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/constant-contact/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/constant-contact/dist/index.js b/mcp-diagrams/mcp-servers/constant-contact/dist/index.js deleted file mode 100644 index 8737c7b..0000000 --- a/mcp-diagrams/mcp-servers/constant-contact/dist/index.js +++ /dev/null @@ -1,399 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "constant-contact"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.cc.email/v3"; -// ============================================ -// API CLIENT - Constant Contact uses OAuth2 Bearer token -// ============================================ -class ConstantContactClient { - accessToken; - baseUrl; - constructor(accessToken) { - this.accessToken = accessToken; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Constant Contact API error: ${response.status} ${response.statusText} - ${errorText}`); - } - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_contacts", - description: "List contacts with filtering and pagination. Returns contact email, name, and list memberships.", - inputSchema: { - type: "object", - properties: { - status: { - type: "string", - enum: ["all", "active", "deleted", "not_set", "pending_confirmation", "temp_hold", "unsubscribed"], - description: "Filter by contact status (default: all)", - }, - email: { type: "string", description: "Filter by exact email address" }, - lists: { type: "string", description: "Comma-separated list IDs to filter by" }, - segment_id: { type: "string", description: "Filter by segment ID" }, - limit: { type: "number", description: "Results per page (default 50, max 500)" }, - include: { - type: "string", - enum: ["custom_fields", "list_memberships", "phone_numbers", "street_addresses", "notes", "taggings"], - description: "Include additional data", - }, - include_count: { type: "boolean", description: "Include total count in response" }, - cursor: { type: "string", description: "Pagination cursor from previous response" }, - }, - }, - }, - { - name: "add_contact", - description: "Create or update a contact. If email exists, contact is updated.", - inputSchema: { - type: "object", - properties: { - email_address: { type: "string", description: "Email address (required)" }, - first_name: { type: "string", description: "First name" }, - last_name: { type: "string", description: "Last name" }, - job_title: { type: "string", description: "Job title" }, - company_name: { type: "string", description: "Company name" }, - phone_numbers: { - type: "array", - items: { - type: "object", - properties: { - phone_number: { type: "string" }, - kind: { type: "string", enum: ["home", "work", "mobile", "other"] }, - }, - }, - description: "Phone numbers", - }, - street_addresses: { - type: "array", - items: { - type: "object", - properties: { - street: { type: "string" }, - city: { type: "string" }, - state: { type: "string" }, - postal_code: { type: "string" }, - country: { type: "string" }, - kind: { type: "string", enum: ["home", "work", "other"] }, - }, - }, - description: "Street addresses", - }, - list_memberships: { - type: "array", - items: { type: "string" }, - description: "Array of list IDs to add contact to", - }, - custom_fields: { - type: "array", - items: { - type: "object", - properties: { - custom_field_id: { type: "string" }, - value: { type: "string" }, - }, - }, - description: "Custom field values", - }, - birthday_month: { type: "number", description: "Birthday month (1-12)" }, - birthday_day: { type: "number", description: "Birthday day (1-31)" }, - anniversary: { type: "string", description: "Anniversary date (YYYY-MM-DD)" }, - create_source: { type: "string", enum: ["Contact", "Account"], description: "Source of contact creation" }, - }, - required: ["email_address"], - }, - }, - { - name: "list_campaigns", - description: "List email campaigns (email activities)", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Results per page (default 50, max 500)" }, - before_date: { type: "string", description: "Filter campaigns before this date (ISO 8601)" }, - after_date: { type: "string", description: "Filter campaigns after this date (ISO 8601)" }, - cursor: { type: "string", description: "Pagination cursor" }, - }, - }, - }, - { - name: "create_campaign", - description: "Create a new email campaign", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Campaign name (required)" }, - subject: { type: "string", description: "Email subject line (required)" }, - from_name: { type: "string", description: "From name displayed to recipients (required)" }, - from_email: { type: "string", description: "From email address (required, must be verified)" }, - reply_to_email: { type: "string", description: "Reply-to email address" }, - html_content: { type: "string", description: "HTML content of the email" }, - text_content: { type: "string", description: "Plain text content of the email" }, - format_type: { - type: "number", - enum: [1, 2, 3, 4, 5], - description: "Format: 1=HTML, 2=TEXT, 3=HTML+TEXT, 4=TEMPLATE, 5=AMP+HTML+TEXT", - }, - physical_address_in_footer: { - type: "object", - properties: { - address_line1: { type: "string" }, - address_line2: { type: "string" }, - address_line3: { type: "string" }, - city: { type: "string" }, - state: { type: "string" }, - postal_code: { type: "string" }, - country: { type: "string" }, - organization_name: { type: "string" }, - }, - description: "Physical address for CAN-SPAM compliance", - }, - }, - required: ["name", "subject", "from_name", "from_email"], - }, - }, - { - name: "list_lists", - description: "List all contact lists", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Results per page (default 50, max 1000)" }, - include_count: { type: "boolean", description: "Include contact count per list" }, - include_membership_count: { type: "string", enum: ["all", "active", "unsubscribed"], description: "Which membership counts to include" }, - cursor: { type: "string", description: "Pagination cursor" }, - }, - }, - }, - { - name: "add_to_list", - description: "Add one or more contacts to a list", - inputSchema: { - type: "object", - properties: { - list_id: { type: "string", description: "List ID to add contacts to (required)" }, - contact_ids: { - type: "array", - items: { type: "string" }, - description: "Array of contact IDs to add (required)", - }, - }, - required: ["list_id", "contact_ids"], - }, - }, - { - name: "get_campaign_stats", - description: "Get tracking statistics for a campaign (sends, opens, clicks, bounces, etc.)", - inputSchema: { - type: "object", - properties: { - campaign_activity_id: { type: "string", description: "Campaign activity ID (required)" }, - }, - required: ["campaign_activity_id"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_contacts": { - const params = new URLSearchParams(); - if (args.status) - params.append("status", args.status); - if (args.email) - params.append("email", args.email); - if (args.lists) - params.append("lists", args.lists); - if (args.segment_id) - params.append("segment_id", args.segment_id); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.include) - params.append("include", args.include); - if (args.include_count) - params.append("include_count", "true"); - if (args.cursor) - params.append("cursor", args.cursor); - const query = params.toString(); - return await client.get(`/contacts${query ? `?${query}` : ""}`); - } - case "add_contact": { - const payload = { - email_address: { - address: args.email_address, - permission_to_send: "implicit", - }, - }; - if (args.first_name) - payload.first_name = args.first_name; - if (args.last_name) - payload.last_name = args.last_name; - if (args.job_title) - payload.job_title = args.job_title; - if (args.company_name) - payload.company_name = args.company_name; - if (args.phone_numbers) - payload.phone_numbers = args.phone_numbers; - if (args.street_addresses) - payload.street_addresses = args.street_addresses; - if (args.list_memberships) - payload.list_memberships = args.list_memberships; - if (args.custom_fields) - payload.custom_fields = args.custom_fields; - if (args.birthday_month) - payload.birthday_month = args.birthday_month; - if (args.birthday_day) - payload.birthday_day = args.birthday_day; - if (args.anniversary) - payload.anniversary = args.anniversary; - if (args.create_source) - payload.create_source = args.create_source; - return await client.post("/contacts/sign_up_form", payload); - } - case "list_campaigns": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.before_date) - params.append("before_date", args.before_date); - if (args.after_date) - params.append("after_date", args.after_date); - if (args.cursor) - params.append("cursor", args.cursor); - const query = params.toString(); - return await client.get(`/emails${query ? `?${query}` : ""}`); - } - case "create_campaign": { - // First create the campaign - const campaignPayload = { - name: args.name, - email_campaign_activities: [ - { - format_type: args.format_type || 5, - from_name: args.from_name, - from_email: args.from_email, - reply_to_email: args.reply_to_email || args.from_email, - subject: args.subject, - html_content: args.html_content || "", - text_content: args.text_content || "", - }, - ], - }; - if (args.physical_address_in_footer) { - campaignPayload.email_campaign_activities[0].physical_address_in_footer = args.physical_address_in_footer; - } - return await client.post("/emails", campaignPayload); - } - case "list_lists": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.include_count) - params.append("include_count", "true"); - if (args.include_membership_count) - params.append("include_membership_count", args.include_membership_count); - if (args.cursor) - params.append("cursor", args.cursor); - const query = params.toString(); - return await client.get(`/contact_lists${query ? `?${query}` : ""}`); - } - case "add_to_list": { - const { list_id, contact_ids } = args; - // Constant Contact uses a specific endpoint for bulk adding to lists - const payload = { - source: { - contact_ids: contact_ids, - }, - list_ids: [list_id], - }; - return await client.post("/activities/add_list_memberships", payload); - } - case "get_campaign_stats": { - const { campaign_activity_id } = args; - return await client.get(`/reports/email_reports/${campaign_activity_id}/tracking/sends`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.CONSTANT_CONTACT_ACCESS_TOKEN; - if (!accessToken) { - console.error("Error: CONSTANT_CONTACT_ACCESS_TOKEN environment variable required"); - console.error("Get your access token from the Constant Contact V3 API after OAuth2 authorization"); - process.exit(1); - } - const client = new ConstantContactClient(accessToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/fieldedge/dist/index.d.ts b/mcp-diagrams/mcp-servers/fieldedge/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/fieldedge/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/fieldedge/dist/index.js b/mcp-diagrams/mcp-servers/fieldedge/dist/index.js deleted file mode 100644 index 7e8dead..0000000 --- a/mcp-diagrams/mcp-servers/fieldedge/dist/index.js +++ /dev/null @@ -1,335 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "fieldedge"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.fieldedge.com/v1"; -// ============================================ -// API CLIENT -// ============================================ -class FieldEdgeClient { - apiKey; - subscriptionKey; - baseUrl; - constructor(apiKey, subscriptionKey) { - this.apiKey = apiKey; - this.subscriptionKey = subscriptionKey || apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Ocp-Apim-Subscription-Key": this.subscriptionKey, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`FieldEdge API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } - // Work Orders - async listWorkOrders(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.status) - query.append("status", params.status); - if (params.customerId) - query.append("customerId", params.customerId); - if (params.technicianId) - query.append("technicianId", params.technicianId); - if (params.startDate) - query.append("startDate", params.startDate); - if (params.endDate) - query.append("endDate", params.endDate); - return this.get(`/work-orders?${query.toString()}`); - } - async getWorkOrder(id) { - return this.get(`/work-orders/${id}`); - } - async createWorkOrder(data) { - return this.post("/work-orders", data); - } - // Customers - async listCustomers(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.search) - query.append("search", params.search); - if (params.sortBy) - query.append("sortBy", params.sortBy); - if (params.sortOrder) - query.append("sortOrder", params.sortOrder); - return this.get(`/customers?${query.toString()}`); - } - // Technicians - async listTechnicians(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.active !== undefined) - query.append("active", params.active.toString()); - if (params.departmentId) - query.append("departmentId", params.departmentId); - return this.get(`/technicians?${query.toString()}`); - } - // Invoices - async listInvoices(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.status) - query.append("status", params.status); - if (params.customerId) - query.append("customerId", params.customerId); - if (params.startDate) - query.append("startDate", params.startDate); - if (params.endDate) - query.append("endDate", params.endDate); - return this.get(`/invoices?${query.toString()}`); - } - // Equipment - async listEquipment(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.customerId) - query.append("customerId", params.customerId); - if (params.locationId) - query.append("locationId", params.locationId); - if (params.equipmentType) - query.append("equipmentType", params.equipmentType); - return this.get(`/equipment?${query.toString()}`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_work_orders", - description: "List work orders from FieldEdge. Filter by status, customer, technician, and date range.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination (default: 1)" }, - pageSize: { type: "number", description: "Number of results per page (default: 25, max: 100)" }, - status: { - type: "string", - description: "Filter by work order status", - enum: ["open", "scheduled", "in_progress", "completed", "canceled", "on_hold"] - }, - customerId: { type: "string", description: "Filter work orders by customer ID" }, - technicianId: { type: "string", description: "Filter work orders by assigned technician ID" }, - startDate: { type: "string", description: "Filter by scheduled date (start) in YYYY-MM-DD format" }, - endDate: { type: "string", description: "Filter by scheduled date (end) in YYYY-MM-DD format" }, - }, - }, - }, - { - name: "get_work_order", - description: "Get detailed information about a specific work order by ID", - inputSchema: { - type: "object", - properties: { - id: { type: "string", description: "The work order ID" }, - }, - required: ["id"], - }, - }, - { - name: "create_work_order", - description: "Create a new work order in FieldEdge", - inputSchema: { - type: "object", - properties: { - customerId: { type: "string", description: "The customer ID (required)" }, - locationId: { type: "string", description: "The service location ID" }, - description: { type: "string", description: "Work order description (required)" }, - workType: { - type: "string", - description: "Type of work", - enum: ["service", "repair", "installation", "maintenance", "inspection"] - }, - priority: { - type: "string", - description: "Priority level", - enum: ["low", "normal", "high", "emergency"] - }, - scheduledDate: { type: "string", description: "Scheduled date in YYYY-MM-DD format" }, - scheduledTime: { type: "string", description: "Scheduled time in HH:MM format" }, - technicianId: { type: "string", description: "Assigned technician ID" }, - equipmentIds: { - type: "array", - items: { type: "string" }, - description: "Array of equipment IDs related to this work order" - }, - notes: { type: "string", description: "Additional notes or instructions" }, - }, - required: ["customerId", "description"], - }, - }, - { - name: "list_customers", - description: "List customers from FieldEdge with search and pagination", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - search: { type: "string", description: "Search query to filter customers by name, email, phone, or address" }, - sortBy: { type: "string", description: "Sort field (e.g., 'name', 'createdAt')" }, - sortOrder: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - }, - }, - }, - { - name: "list_technicians", - description: "List technicians/employees from FieldEdge", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - active: { type: "boolean", description: "Filter by active status" }, - departmentId: { type: "string", description: "Filter by department ID" }, - }, - }, - }, - { - name: "list_invoices", - description: "List invoices from FieldEdge", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - status: { - type: "string", - description: "Filter by invoice status", - enum: ["draft", "pending", "sent", "paid", "partial", "overdue", "void"] - }, - customerId: { type: "string", description: "Filter invoices by customer ID" }, - startDate: { type: "string", description: "Filter by invoice date (start) in YYYY-MM-DD format" }, - endDate: { type: "string", description: "Filter by invoice date (end) in YYYY-MM-DD format" }, - }, - }, - }, - { - name: "list_equipment", - description: "List equipment records from FieldEdge. Track HVAC units, appliances, and other equipment at customer locations.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - customerId: { type: "string", description: "Filter equipment by customer ID" }, - locationId: { type: "string", description: "Filter equipment by location ID" }, - equipmentType: { - type: "string", - description: "Filter by equipment type", - enum: ["hvac", "plumbing", "electrical", "appliance", "other"] - }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_work_orders": - return await client.listWorkOrders(args); - case "get_work_order": - return await client.getWorkOrder(args.id); - case "create_work_order": - return await client.createWorkOrder(args); - case "list_customers": - return await client.listCustomers(args); - case "list_technicians": - return await client.listTechnicians(args); - case "list_invoices": - return await client.listInvoices(args); - case "list_equipment": - return await client.listEquipment(args); - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.FIELDEDGE_API_KEY; - const subscriptionKey = process.env.FIELDEDGE_SUBSCRIPTION_KEY; - if (!apiKey) { - console.error("Error: FIELDEDGE_API_KEY environment variable required"); - process.exit(1); - } - const client = new FieldEdgeClient(apiKey, subscriptionKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/freshbooks/dist/index.d.ts b/mcp-diagrams/mcp-servers/freshbooks/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/freshbooks/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/freshbooks/dist/index.js b/mcp-diagrams/mcp-servers/freshbooks/dist/index.js deleted file mode 100644 index 130ebf1..0000000 --- a/mcp-diagrams/mcp-servers/freshbooks/dist/index.js +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "freshbooks"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.freshbooks.com"; -// ============================================ -// API CLIENT -// ============================================ -class FreshBooksClient { - accessToken; - accountId; - baseUrl; - constructor(accessToken, accountId) { - this.accessToken = accessToken; - this.accountId = accountId; - this.baseUrl = `${API_BASE_URL}/accounting/account/${accountId}`; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - "Api-Version": "alpha", - ...options.headers, - }, - }); - if (!response.ok) { - const text = await response.text(); - throw new Error(`FreshBooks API error: ${response.status} ${response.statusText} - ${text}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - // Invoice methods - async listInvoices(options) { - const params = new URLSearchParams(); - if (options?.page) - params.append("page", options.page.toString()); - if (options?.perPage) - params.append("per_page", options.perPage.toString()); - if (options?.status) - params.append("search[v3_status]", options.status); - const query = params.toString(); - return this.get(`/invoices/invoices${query ? `?${query}` : ""}`); - } - async getInvoice(invoiceId) { - return this.get(`/invoices/invoices/${invoiceId}`); - } - async createInvoice(data) { - return this.post("/invoices/invoices", { invoice: data }); - } - async sendInvoice(invoiceId, emailData) { - // To send an invoice, update status to "sent" - return this.put(`/invoices/invoices/${invoiceId}`, { - invoice: { - action_email: emailData.action_email ?? true, - email_recipients: emailData.email_recipients, - email_subject: emailData.email_subject, - email_body: emailData.email_body, - status: 2, // 2 = sent - }, - }); - } - // Client methods - async listClients(options) { - const params = new URLSearchParams(); - if (options?.page) - params.append("page", options.page.toString()); - if (options?.perPage) - params.append("per_page", options.perPage.toString()); - const query = params.toString(); - return this.get(`/users/clients${query ? `?${query}` : ""}`); - } - async getClient(clientId) { - return this.get(`/users/clients/${clientId}`); - } - async createClient(data) { - return this.post("/users/clients", { client: data }); - } - // Expense methods - async listExpenses(options) { - const params = new URLSearchParams(); - if (options?.page) - params.append("page", options.page.toString()); - if (options?.perPage) - params.append("per_page", options.perPage.toString()); - const query = params.toString(); - return this.get(`/expenses/expenses${query ? `?${query}` : ""}`); - } - async getExpense(expenseId) { - return this.get(`/expenses/expenses/${expenseId}`); - } - // Payment methods - async listPayments(options) { - const params = new URLSearchParams(); - if (options?.page) - params.append("page", options.page.toString()); - if (options?.perPage) - params.append("per_page", options.perPage.toString()); - const query = params.toString(); - return this.get(`/payments/payments${query ? `?${query}` : ""}`); - } - async getPayment(paymentId) { - return this.get(`/payments/payments/${paymentId}`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_invoices", - description: "List invoices from FreshBooks", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - per_page: { type: "number", description: "Results per page (default 15)" }, - status: { - type: "string", - description: "Filter by status", - enum: ["draft", "sent", "viewed", "paid", "overdue", "disputed"] - }, - }, - }, - }, - { - name: "get_invoice", - description: "Get a specific invoice by ID", - inputSchema: { - type: "object", - properties: { - invoice_id: { type: "string", description: "Invoice ID" }, - }, - required: ["invoice_id"], - }, - }, - { - name: "create_invoice", - description: "Create a new invoice in FreshBooks", - inputSchema: { - type: "object", - properties: { - customer_id: { type: "number", description: "Client/customer ID" }, - create_date: { type: "string", description: "Invoice date (YYYY-MM-DD)" }, - due_offset_days: { type: "number", description: "Days until due (default 30)" }, - currency_code: { type: "string", description: "Currency code (e.g., USD, CAD)" }, - notes: { type: "string", description: "Invoice notes" }, - terms: { type: "string", description: "Payment terms" }, - lines: { - type: "array", - description: "Invoice line items", - items: { - type: "object", - properties: { - name: { type: "string", description: "Item name" }, - description: { type: "string", description: "Item description" }, - qty: { type: "number", description: "Quantity" }, - unit_cost: { type: "string", description: "Unit cost as string (e.g., '100.00')" }, - }, - required: ["name", "qty", "unit_cost"], - }, - }, - }, - required: ["customer_id", "create_date"], - }, - }, - { - name: "send_invoice", - description: "Send an invoice to the client via email", - inputSchema: { - type: "object", - properties: { - invoice_id: { type: "string", description: "Invoice ID to send" }, - email_recipients: { - type: "array", - items: { type: "string" }, - description: "Email addresses to send to" - }, - email_subject: { type: "string", description: "Email subject line" }, - email_body: { type: "string", description: "Email body message" }, - }, - required: ["invoice_id"], - }, - }, - { - name: "list_clients", - description: "List all clients from FreshBooks", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - per_page: { type: "number", description: "Results per page (default 15)" }, - }, - }, - }, - { - name: "create_client", - description: "Create a new client in FreshBooks", - inputSchema: { - type: "object", - properties: { - email: { type: "string", description: "Client email" }, - fname: { type: "string", description: "First name" }, - lname: { type: "string", description: "Last name" }, - organization: { type: "string", description: "Company/organization name" }, - p_street: { type: "string", description: "Street address" }, - p_city: { type: "string", description: "City" }, - p_province: { type: "string", description: "State/Province" }, - p_code: { type: "string", description: "Postal/ZIP code" }, - p_country: { type: "string", description: "Country" }, - currency_code: { type: "string", description: "Currency code (e.g., USD)" }, - bus_phone: { type: "string", description: "Business phone" }, - note: { type: "string", description: "Notes about client" }, - }, - }, - }, - { - name: "list_expenses", - description: "List expenses from FreshBooks", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - per_page: { type: "number", description: "Results per page (default 15)" }, - }, - }, - }, - { - name: "list_payments", - description: "List payments received in FreshBooks", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - per_page: { type: "number", description: "Results per page (default 15)" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_invoices": { - return await client.listInvoices({ - page: args.page, - perPage: args.per_page, - status: args.status, - }); - } - case "get_invoice": { - return await client.getInvoice(args.invoice_id); - } - case "create_invoice": { - const lines = args.lines?.map((line) => ({ - name: line.name, - description: line.description, - qty: line.qty, - unit_cost: { amount: line.unit_cost, code: args.currency_code || "USD" }, - })); - return await client.createInvoice({ - customerid: args.customer_id, - create_date: args.create_date, - due_offset_days: args.due_offset_days || 30, - currency_code: args.currency_code, - notes: args.notes, - terms: args.terms, - lines, - }); - } - case "send_invoice": { - return await client.sendInvoice(args.invoice_id, { - email_recipients: args.email_recipients, - email_subject: args.email_subject, - email_body: args.email_body, - action_email: true, - }); - } - case "list_clients": { - return await client.listClients({ - page: args.page, - perPage: args.per_page, - }); - } - case "create_client": { - return await client.createClient({ - email: args.email, - fname: args.fname, - lname: args.lname, - organization: args.organization, - p_street: args.p_street, - p_city: args.p_city, - p_province: args.p_province, - p_code: args.p_code, - p_country: args.p_country, - currency_code: args.currency_code, - bus_phone: args.bus_phone, - note: args.note, - }); - } - case "list_expenses": { - return await client.listExpenses({ - page: args.page, - perPage: args.per_page, - }); - } - case "list_payments": { - return await client.listPayments({ - page: args.page, - perPage: args.per_page, - }); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.FRESHBOOKS_ACCESS_TOKEN; - const accountId = process.env.FRESHBOOKS_ACCOUNT_ID; - if (!accessToken) { - console.error("Error: FRESHBOOKS_ACCESS_TOKEN environment variable required"); - process.exit(1); - } - if (!accountId) { - console.error("Error: FRESHBOOKS_ACCOUNT_ID environment variable required"); - process.exit(1); - } - const client = new FreshBooksClient(accessToken, accountId); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - // List available tools - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - // Handle tool calls - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - // Start server - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/freshdesk/dist/index.d.ts b/mcp-diagrams/mcp-servers/freshdesk/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/freshdesk/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/freshdesk/dist/index.js b/mcp-diagrams/mcp-servers/freshdesk/dist/index.js deleted file mode 100644 index 90ca648..0000000 --- a/mcp-diagrams/mcp-servers/freshdesk/dist/index.js +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "freshdesk"; -const MCP_VERSION = "1.0.0"; -// ============================================ -// API CLIENT - Freshdesk uses Basic Auth with API key -// ============================================ -class FreshdeskClient { - apiKey; - domain; - baseUrl; - constructor(apiKey, domain) { - this.apiKey = apiKey; - this.domain = domain; - this.baseUrl = `https://${domain}.freshdesk.com/api/v2`; - } - getAuthHeader() { - // Freshdesk uses Basic Auth: API key as username, "X" as password - return "Basic " + Buffer.from(`${this.apiKey}:X`).toString("base64"); - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": this.getAuthHeader(), - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Freshdesk API error: ${response.status} ${response.statusText} - ${errorText}`); - } - // Handle 204 No Content - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_tickets", - description: "List all tickets with optional filtering. Returns tickets sorted by created_at descending.", - inputSchema: { - type: "object", - properties: { - filter: { - type: "string", - description: "Filter tickets by predefined filters: new_and_my_open, watching, spam, deleted, or all_tickets", - enum: ["new_and_my_open", "watching", "spam", "deleted", "all_tickets"], - }, - page: { type: "number", description: "Page number for pagination (default: 1)" }, - per_page: { type: "number", description: "Results per page, max 100 (default: 30)" }, - order_by: { type: "string", description: "Order by field: created_at, due_by, updated_at, status" }, - order_type: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - }, - }, - }, - { - name: "get_ticket", - description: "Get a specific ticket by ID with full details including conversations", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Ticket ID" }, - include: { - type: "string", - description: "Include additional data: conversations, requester, company, stats", - }, - }, - required: ["id"], - }, - }, - { - name: "create_ticket", - description: "Create a new support ticket", - inputSchema: { - type: "object", - properties: { - subject: { type: "string", description: "Ticket subject (required)" }, - description: { type: "string", description: "HTML content of the ticket (required)" }, - email: { type: "string", description: "Email of the requester (required if no requester_id)" }, - requester_id: { type: "number", description: "ID of the requester (required if no email)" }, - priority: { - type: "number", - description: "Priority: 1=Low, 2=Medium, 3=High, 4=Urgent", - enum: [1, 2, 3, 4], - }, - status: { - type: "number", - description: "Status: 2=Open, 3=Pending, 4=Resolved, 5=Closed", - enum: [2, 3, 4, 5], - }, - type: { type: "string", description: "Ticket type (as configured in your helpdesk)" }, - source: { - type: "number", - description: "Source: 1=Email, 2=Portal, 3=Phone, 7=Chat, 9=Feedback Widget, 10=Outbound Email", - }, - group_id: { type: "number", description: "ID of the group to assign" }, - responder_id: { type: "number", description: "ID of the agent to assign" }, - tags: { - type: "array", - items: { type: "string" }, - description: "Tags to add to the ticket", - }, - custom_fields: { type: "object", description: "Custom field values as key-value pairs" }, - }, - required: ["subject", "description"], - }, - }, - { - name: "update_ticket", - description: "Update an existing ticket's properties", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Ticket ID" }, - subject: { type: "string", description: "Updated subject" }, - description: { type: "string", description: "Updated description" }, - priority: { type: "number", description: "Priority: 1=Low, 2=Medium, 3=High, 4=Urgent" }, - status: { type: "number", description: "Status: 2=Open, 3=Pending, 4=Resolved, 5=Closed" }, - type: { type: "string", description: "Ticket type" }, - group_id: { type: "number", description: "Group to assign" }, - responder_id: { type: "number", description: "Agent to assign" }, - tags: { type: "array", items: { type: "string" }, description: "Tags (replaces existing)" }, - custom_fields: { type: "object", description: "Custom field values" }, - }, - required: ["id"], - }, - }, - { - name: "reply_ticket", - description: "Add a reply to a ticket (creates a conversation)", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Ticket ID" }, - body: { type: "string", description: "HTML content of the reply (required)" }, - from_email: { type: "string", description: "Email address to send reply from" }, - user_id: { type: "number", description: "ID of the agent/contact adding the note" }, - cc_emails: { - type: "array", - items: { type: "string" }, - description: "CC email addresses", - }, - bcc_emails: { - type: "array", - items: { type: "string" }, - description: "BCC email addresses", - }, - private: { type: "boolean", description: "If true, creates a private note instead of public reply" }, - }, - required: ["id", "body"], - }, - }, - { - name: "list_contacts", - description: "List all contacts in your helpdesk", - inputSchema: { - type: "object", - properties: { - email: { type: "string", description: "Filter by email address" }, - phone: { type: "string", description: "Filter by phone number" }, - mobile: { type: "string", description: "Filter by mobile number" }, - company_id: { type: "number", description: "Filter by company ID" }, - state: { type: "string", enum: ["blocked", "deleted", "unverified", "verified"], description: "Filter by state" }, - page: { type: "number", description: "Page number" }, - per_page: { type: "number", description: "Results per page (max 100)" }, - }, - }, - }, - { - name: "list_agents", - description: "List all agents in your helpdesk", - inputSchema: { - type: "object", - properties: { - email: { type: "string", description: "Filter by email" }, - phone: { type: "string", description: "Filter by phone" }, - state: { type: "string", enum: ["fulltime", "occasional"], description: "Filter by agent type" }, - page: { type: "number", description: "Page number" }, - per_page: { type: "number", description: "Results per page (max 100)" }, - }, - }, - }, - { - name: "search_tickets", - description: "Search tickets using Freshdesk query language. Supports field:value syntax.", - inputSchema: { - type: "object", - properties: { - query: { - type: "string", - description: 'Search query using Freshdesk syntax. Examples: "status:2", "priority:4 AND created_at:>\'2023-01-01\'", "tag:\'urgent\'"', - }, - page: { type: "number", description: "Page number (each page has 30 results)" }, - }, - required: ["query"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_tickets": { - const params = new URLSearchParams(); - if (args.filter) - params.append("filter", args.filter); - if (args.page) - params.append("page", args.page.toString()); - if (args.per_page) - params.append("per_page", args.per_page.toString()); - if (args.order_by) - params.append("order_by", args.order_by); - if (args.order_type) - params.append("order_type", args.order_type); - const query = params.toString(); - return await client.get(`/tickets${query ? `?${query}` : ""}`); - } - case "get_ticket": { - const { id, include } = args; - const query = include ? `?include=${include}` : ""; - return await client.get(`/tickets/${id}${query}`); - } - case "create_ticket": { - const { subject, description, email, requester_id, priority, status, type, source, group_id, responder_id, tags, custom_fields } = args; - const payload = { subject, description }; - if (email) - payload.email = email; - if (requester_id) - payload.requester_id = requester_id; - if (priority) - payload.priority = priority; - if (status) - payload.status = status; - if (type) - payload.type = type; - if (source) - payload.source = source; - if (group_id) - payload.group_id = group_id; - if (responder_id) - payload.responder_id = responder_id; - if (tags) - payload.tags = tags; - if (custom_fields) - payload.custom_fields = custom_fields; - return await client.post("/tickets", payload); - } - case "update_ticket": { - const { id, ...updates } = args; - return await client.put(`/tickets/${id}`, updates); - } - case "reply_ticket": { - const { id, body, from_email, user_id, cc_emails, bcc_emails, private: isPrivate } = args; - const payload = { body }; - if (from_email) - payload.from_email = from_email; - if (user_id) - payload.user_id = user_id; - if (cc_emails) - payload.cc_emails = cc_emails; - if (bcc_emails) - payload.bcc_emails = bcc_emails; - // Private notes use a different endpoint - if (isPrivate) { - payload.private = true; - return await client.post(`/tickets/${id}/notes`, payload); - } - return await client.post(`/tickets/${id}/reply`, payload); - } - case "list_contacts": { - const params = new URLSearchParams(); - if (args.email) - params.append("email", args.email); - if (args.phone) - params.append("phone", args.phone); - if (args.mobile) - params.append("mobile", args.mobile); - if (args.company_id) - params.append("company_id", args.company_id.toString()); - if (args.state) - params.append("state", args.state); - if (args.page) - params.append("page", args.page.toString()); - if (args.per_page) - params.append("per_page", args.per_page.toString()); - const query = params.toString(); - return await client.get(`/contacts${query ? `?${query}` : ""}`); - } - case "list_agents": { - const params = new URLSearchParams(); - if (args.email) - params.append("email", args.email); - if (args.phone) - params.append("phone", args.phone); - if (args.state) - params.append("state", args.state); - if (args.page) - params.append("page", args.page.toString()); - if (args.per_page) - params.append("per_page", args.per_page.toString()); - const query = params.toString(); - return await client.get(`/agents${query ? `?${query}` : ""}`); - } - case "search_tickets": { - const { query, page } = args; - const params = new URLSearchParams(); - params.append("query", `"${query}"`); - if (page) - params.append("page", page.toString()); - return await client.get(`/search/tickets?${params.toString()}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.FRESHDESK_API_KEY; - const domain = process.env.FRESHDESK_DOMAIN; - if (!apiKey) { - console.error("Error: FRESHDESK_API_KEY environment variable required"); - process.exit(1); - } - if (!domain) { - console.error("Error: FRESHDESK_DOMAIN environment variable required (e.g., 'yourcompany' for yourcompany.freshdesk.com)"); - process.exit(1); - } - const client = new FreshdeskClient(apiKey, domain); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/gusto/dist/index.d.ts b/mcp-diagrams/mcp-servers/gusto/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/gusto/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/gusto/dist/index.js b/mcp-diagrams/mcp-servers/gusto/dist/index.js deleted file mode 100644 index afd3da4..0000000 --- a/mcp-diagrams/mcp-servers/gusto/dist/index.js +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "gusto"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.gusto.com/v1"; -// ============================================ -// API CLIENT -// ============================================ -class GustoClient { - accessToken; - baseUrl; - constructor(accessToken) { - this.accessToken = accessToken; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Gusto API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - // Employee endpoints - async listEmployees(companyId, page, per) { - const params = new URLSearchParams(); - if (page) - params.append("page", page.toString()); - if (per) - params.append("per", per.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/companies/${companyId}/employees${query}`); - } - async getEmployee(employeeId) { - return this.get(`/employees/${employeeId}`); - } - // Payroll endpoints - async listPayrolls(companyId, processed, startDate, endDate) { - const params = new URLSearchParams(); - if (processed !== undefined) - params.append("processed", processed.toString()); - if (startDate) - params.append("start_date", startDate); - if (endDate) - params.append("end_date", endDate); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/companies/${companyId}/payrolls${query}`); - } - async getPayroll(companyId, payrollId) { - return this.get(`/companies/${companyId}/payrolls/${payrollId}`); - } - // Contractor endpoints - async listContractors(companyId, page, per) { - const params = new URLSearchParams(); - if (page) - params.append("page", page.toString()); - if (per) - params.append("per", per.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/companies/${companyId}/contractors${query}`); - } - // Company endpoints - async getCompany(companyId) { - return this.get(`/companies/${companyId}`); - } - // Benefits endpoints - async listBenefits(companyId) { - return this.get(`/companies/${companyId}/company_benefits`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_employees", - description: "List all employees for a company in Gusto", - inputSchema: { - type: "object", - properties: { - company_id: { type: "string", description: "The company UUID" }, - page: { type: "number", description: "Page number for pagination" }, - per: { type: "number", description: "Number of results per page (max 100)" }, - }, - required: ["company_id"], - }, - }, - { - name: "get_employee", - description: "Get details of a specific employee by ID", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "The employee UUID" }, - }, - required: ["employee_id"], - }, - }, - { - name: "list_payrolls", - description: "List payrolls for a company, optionally filtered by date range and processing status", - inputSchema: { - type: "object", - properties: { - company_id: { type: "string", description: "The company UUID" }, - processed: { type: "boolean", description: "Filter by processed status" }, - start_date: { type: "string", description: "Start date filter (YYYY-MM-DD)" }, - end_date: { type: "string", description: "End date filter (YYYY-MM-DD)" }, - }, - required: ["company_id"], - }, - }, - { - name: "get_payroll", - description: "Get details of a specific payroll", - inputSchema: { - type: "object", - properties: { - company_id: { type: "string", description: "The company UUID" }, - payroll_id: { type: "string", description: "The payroll ID or UUID" }, - }, - required: ["company_id", "payroll_id"], - }, - }, - { - name: "list_contractors", - description: "List all contractors for a company", - inputSchema: { - type: "object", - properties: { - company_id: { type: "string", description: "The company UUID" }, - page: { type: "number", description: "Page number for pagination" }, - per: { type: "number", description: "Number of results per page" }, - }, - required: ["company_id"], - }, - }, - { - name: "get_company", - description: "Get company details including locations and settings", - inputSchema: { - type: "object", - properties: { - company_id: { type: "string", description: "The company UUID" }, - }, - required: ["company_id"], - }, - }, - { - name: "list_benefits", - description: "List all company benefits (health insurance, 401k, etc.)", - inputSchema: { - type: "object", - properties: { - company_id: { type: "string", description: "The company UUID" }, - }, - required: ["company_id"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_employees": { - const { company_id, page, per } = args; - return await client.listEmployees(company_id, page, per); - } - case "get_employee": { - const { employee_id } = args; - return await client.getEmployee(employee_id); - } - case "list_payrolls": { - const { company_id, processed, start_date, end_date } = args; - return await client.listPayrolls(company_id, processed, start_date, end_date); - } - case "get_payroll": { - const { company_id, payroll_id } = args; - return await client.getPayroll(company_id, payroll_id); - } - case "list_contractors": { - const { company_id, page, per } = args; - return await client.listContractors(company_id, page, per); - } - case "get_company": { - const { company_id } = args; - return await client.getCompany(company_id); - } - case "list_benefits": { - const { company_id } = args; - return await client.listBenefits(company_id); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.GUSTO_ACCESS_TOKEN; - if (!accessToken) { - console.error("Error: GUSTO_ACCESS_TOKEN environment variable required"); - console.error("Obtain an OAuth2 access token from Gusto's developer portal"); - process.exit(1); - } - const client = new GustoClient(accessToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/helpscout/dist/index.d.ts b/mcp-diagrams/mcp-servers/helpscout/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/helpscout/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/helpscout/dist/index.js b/mcp-diagrams/mcp-servers/helpscout/dist/index.js deleted file mode 100644 index 235070c..0000000 --- a/mcp-diagrams/mcp-servers/helpscout/dist/index.js +++ /dev/null @@ -1,337 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "helpscout"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.helpscout.net/v2"; -// ============================================ -// API CLIENT (OAuth 2.0) -// ============================================ -class HelpScoutClient { - accessToken; - baseUrl; - constructor(accessToken) { - this.accessToken = accessToken; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const error = await response.text(); - throw new Error(`Help Scout API error: ${response.status} - ${error}`); - } - // Some endpoints return 201/204 with no body - const text = await response.text(); - return text ? JSON.parse(text) : { success: true }; - } - async get(endpoint, params = {}) { - const url = new URL(`${this.baseUrl}${endpoint}`); - for (const [key, value] of Object.entries(params)) { - if (value !== undefined && value !== null) { - url.searchParams.set(key, String(value)); - } - } - return this.request(url.pathname + url.search, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_conversations", - description: "List conversations (tickets) from Help Scout. Returns paginated list with embedded conversation data.", - inputSchema: { - type: "object", - properties: { - mailbox: { type: "number", description: "Filter by mailbox ID" }, - status: { - type: "string", - description: "Filter by status", - enum: ["active", "open", "closed", "pending", "spam"] - }, - tag: { type: "string", description: "Filter by tag" }, - assigned_to: { type: "number", description: "Filter by assigned user ID" }, - folder: { type: "number", description: "Filter by folder ID" }, - page: { type: "number", description: "Page number (default 1)" }, - sortField: { type: "string", description: "Sort field (createdAt, modifiedAt, number)" }, - sortOrder: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - }, - }, - }, - { - name: "get_conversation", - description: "Get a specific conversation by ID with full thread details", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Conversation ID" }, - }, - required: ["id"], - }, - }, - { - name: "create_conversation", - description: "Create a new conversation (ticket) in Help Scout", - inputSchema: { - type: "object", - properties: { - mailboxId: { type: "number", description: "Mailbox ID (required)" }, - subject: { type: "string", description: "Conversation subject (required)" }, - customer: { - type: "object", - description: "Customer object with email (required): {email: 'customer@example.com'}", - }, - type: { - type: "string", - enum: ["email", "phone", "chat"], - description: "Conversation type (default: email)" - }, - status: { - type: "string", - enum: ["active", "closed", "pending"], - description: "Initial status (default: active)" - }, - threads: { - type: "array", - description: "Initial threads [{type: 'customer', text: 'message content'}]", - items: { type: "object" } - }, - tags: { - type: "array", - items: { type: "string" }, - description: "Tags to apply" - }, - assignTo: { type: "number", description: "User ID to assign to" }, - }, - required: ["mailboxId", "subject", "customer"], - }, - }, - { - name: "reply_conversation", - description: "Reply to an existing conversation", - inputSchema: { - type: "object", - properties: { - conversationId: { type: "number", description: "Conversation ID to reply to (required)" }, - text: { type: "string", description: "Reply text/HTML content (required)" }, - user: { type: "number", description: "User ID sending reply (required for agent replies)" }, - customer: { - type: "object", - description: "Customer object for customer replies: {email: 'customer@example.com'}" - }, - type: { - type: "string", - enum: ["reply", "note"], - description: "Thread type (reply=visible to customer, note=internal)" - }, - status: { - type: "string", - enum: ["active", "closed", "pending"], - description: "Set conversation status after reply" - }, - draft: { type: "boolean", description: "Save as draft" }, - cc: { type: "array", items: { type: "string" }, description: "CC email addresses" }, - bcc: { type: "array", items: { type: "string" }, description: "BCC email addresses" }, - }, - required: ["conversationId", "text"], - }, - }, - { - name: "list_customers", - description: "List customers from Help Scout", - inputSchema: { - type: "object", - properties: { - email: { type: "string", description: "Filter by email address" }, - firstName: { type: "string", description: "Filter by first name" }, - lastName: { type: "string", description: "Filter by last name" }, - query: { type: "string", description: "Search query" }, - page: { type: "number", description: "Page number" }, - sortField: { type: "string", description: "Sort field (firstName, lastName, modifiedAt)" }, - sortOrder: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - }, - }, - }, - { - name: "list_mailboxes", - description: "List all mailboxes accessible to the authenticated user", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - }, - }, - }, - { - name: "search", - description: "Search conversations using Help Scout's search syntax", - inputSchema: { - type: "object", - properties: { - query: { - type: "string", - description: "Search query (required). Supports: subject:, customer:, status:, tag:, mailbox:, etc." - }, - page: { type: "number", description: "Page number" }, - sortField: { type: "string", description: "Sort field" }, - sortOrder: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - }, - required: ["query"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_conversations": { - const params = {}; - if (args.mailbox) - params.mailbox = args.mailbox; - if (args.status) - params.status = args.status; - if (args.tag) - params.tag = args.tag; - if (args.assigned_to) - params["assigned_to"] = args.assigned_to; - if (args.folder) - params.folder = args.folder; - if (args.page) - params.page = args.page; - if (args.sortField) - params.sortField = args.sortField; - if (args.sortOrder) - params.sortOrder = args.sortOrder; - return await client.get("/conversations", params); - } - case "get_conversation": { - const { id } = args; - return await client.get(`/conversations/${id}`); - } - case "create_conversation": { - const payload = { - mailboxId: args.mailboxId, - subject: args.subject, - customer: args.customer, - type: args.type || "email", - status: args.status || "active", - }; - if (args.threads) - payload.threads = args.threads; - if (args.tags) - payload.tags = args.tags; - if (args.assignTo) - payload.assignTo = args.assignTo; - return await client.post("/conversations", payload); - } - case "reply_conversation": { - const { conversationId, ...threadData } = args; - const payload = { - text: threadData.text, - type: threadData.type || "reply", - }; - if (threadData.user) - payload.user = threadData.user; - if (threadData.customer) - payload.customer = threadData.customer; - if (threadData.status) - payload.status = threadData.status; - if (threadData.draft) - payload.draft = threadData.draft; - if (threadData.cc) - payload.cc = threadData.cc; - if (threadData.bcc) - payload.bcc = threadData.bcc; - return await client.post(`/conversations/${conversationId}/reply`, payload); - } - case "list_customers": { - const params = {}; - if (args.email) - params.email = args.email; - if (args.firstName) - params.firstName = args.firstName; - if (args.lastName) - params.lastName = args.lastName; - if (args.query) - params.query = args.query; - if (args.page) - params.page = args.page; - if (args.sortField) - params.sortField = args.sortField; - if (args.sortOrder) - params.sortOrder = args.sortOrder; - return await client.get("/customers", params); - } - case "list_mailboxes": { - return await client.get("/mailboxes", { page: args.page }); - } - case "search": { - const params = { query: args.query }; - if (args.page) - params.page = args.page; - if (args.sortField) - params.sortField = args.sortField; - if (args.sortOrder) - params.sortOrder = args.sortOrder; - return await client.get("/conversations/search", params); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.HELPSCOUT_ACCESS_TOKEN; - if (!accessToken) { - console.error("Error: HELPSCOUT_ACCESS_TOKEN environment variable required"); - console.error("Obtain via OAuth 2.0 flow at https://developer.helpscout.com/mailbox-api/overview/authentication/"); - process.exit(1); - } - const client = new HelpScoutClient(accessToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/housecall-pro/dist/index.d.ts b/mcp-diagrams/mcp-servers/housecall-pro/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/housecall-pro/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/housecall-pro/dist/index.js b/mcp-diagrams/mcp-servers/housecall-pro/dist/index.js deleted file mode 100644 index e021c39..0000000 --- a/mcp-diagrams/mcp-servers/housecall-pro/dist/index.js +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "housecall-pro"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.housecallpro.com/v1"; -// ============================================ -// API CLIENT -// ============================================ -class HousecallProClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Housecall Pro API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } - // Jobs - async listJobs(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.per_page) - query.append("per_page", params.per_page.toString()); - if (params.status) - query.append("status", params.status); - if (params.customer_id) - query.append("customer_id", params.customer_id); - return this.get(`/jobs?${query.toString()}`); - } - async getJob(id) { - return this.get(`/jobs/${id}`); - } - async createJob(data) { - return this.post("/jobs", data); - } - // Estimates - async listEstimates(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.per_page) - query.append("per_page", params.per_page.toString()); - if (params.status) - query.append("status", params.status); - if (params.customer_id) - query.append("customer_id", params.customer_id); - return this.get(`/estimates?${query.toString()}`); - } - async createEstimate(data) { - return this.post("/estimates", data); - } - // Customers - async listCustomers(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.per_page) - query.append("per_page", params.per_page.toString()); - if (params.q) - query.append("q", params.q); - if (params.sort) - query.append("sort", params.sort); - return this.get(`/customers?${query.toString()}`); - } - // Invoices - async listInvoices(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.per_page) - query.append("per_page", params.per_page.toString()); - if (params.status) - query.append("status", params.status); - if (params.customer_id) - query.append("customer_id", params.customer_id); - return this.get(`/invoices?${query.toString()}`); - } - // Employees - async listEmployees(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.per_page) - query.append("per_page", params.per_page.toString()); - if (params.active !== undefined) - query.append("active", params.active.toString()); - return this.get(`/employees?${query.toString()}`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_jobs", - description: "List jobs from Housecall Pro. Filter by status, customer, and paginate results.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination (default: 1)" }, - per_page: { type: "number", description: "Number of results per page (default: 25, max: 100)" }, - status: { - type: "string", - description: "Filter by job status", - enum: ["unscheduled", "scheduled", "in_progress", "complete", "canceled"] - }, - customer_id: { type: "string", description: "Filter jobs by customer ID" }, - }, - }, - }, - { - name: "get_job", - description: "Get detailed information about a specific job by ID", - inputSchema: { - type: "object", - properties: { - id: { type: "string", description: "The job ID" }, - }, - required: ["id"], - }, - }, - { - name: "create_job", - description: "Create a new job in Housecall Pro", - inputSchema: { - type: "object", - properties: { - customer_id: { type: "string", description: "The customer ID to associate with this job (required)" }, - address_id: { type: "string", description: "The address ID for the job location" }, - description: { type: "string", description: "Job description or work to be performed" }, - scheduled_start: { type: "string", description: "Scheduled start time in ISO 8601 format" }, - scheduled_end: { type: "string", description: "Scheduled end time in ISO 8601 format" }, - assigned_employee_ids: { - type: "array", - items: { type: "string" }, - description: "Array of employee IDs to assign to this job" - }, - tags: { - type: "array", - items: { type: "string" }, - description: "Tags to categorize the job" - }, - }, - required: ["customer_id"], - }, - }, - { - name: "list_estimates", - description: "List estimates from Housecall Pro with optional filters", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Number of results per page (max: 100)" }, - status: { - type: "string", - description: "Filter by estimate status", - enum: ["pending", "sent", "approved", "declined", "converted"] - }, - customer_id: { type: "string", description: "Filter estimates by customer ID" }, - }, - }, - }, - { - name: "create_estimate", - description: "Create a new estimate for a customer", - inputSchema: { - type: "object", - properties: { - customer_id: { type: "string", description: "The customer ID (required)" }, - address_id: { type: "string", description: "The address ID for the estimate" }, - message: { type: "string", description: "Message or notes for the estimate" }, - options: { - type: "array", - description: "Estimate options/packages", - items: { - type: "object", - properties: { - name: { type: "string", description: "Option name (e.g., 'Basic', 'Premium')" }, - total_amount: { type: "number", description: "Total amount for this option in cents" }, - line_items: { - type: "array", - items: { - type: "object", - properties: { - name: { type: "string", description: "Line item name" }, - description: { type: "string", description: "Line item description" }, - quantity: { type: "number", description: "Quantity" }, - unit_price: { type: "number", description: "Unit price in cents" }, - }, - }, - }, - }, - }, - }, - }, - required: ["customer_id"], - }, - }, - { - name: "list_customers", - description: "List customers from Housecall Pro with search and pagination", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Number of results per page (max: 100)" }, - q: { type: "string", description: "Search query to filter customers by name, email, or phone" }, - sort: { type: "string", description: "Sort field (e.g., 'created_at', 'updated_at')" }, - }, - }, - }, - { - name: "list_invoices", - description: "List invoices from Housecall Pro", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Number of results per page (max: 100)" }, - status: { - type: "string", - description: "Filter by invoice status", - enum: ["draft", "sent", "paid", "partial", "void"] - }, - customer_id: { type: "string", description: "Filter invoices by customer ID" }, - }, - }, - }, - { - name: "list_employees", - description: "List employees/technicians from Housecall Pro", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Number of results per page (max: 100)" }, - active: { type: "boolean", description: "Filter by active status" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_jobs": - return await client.listJobs(args); - case "get_job": - return await client.getJob(args.id); - case "create_job": - return await client.createJob(args); - case "list_estimates": - return await client.listEstimates(args); - case "create_estimate": - return await client.createEstimate(args); - case "list_customers": - return await client.listCustomers(args); - case "list_invoices": - return await client.listInvoices(args); - case "list_employees": - return await client.listEmployees(args); - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.HOUSECALL_PRO_API_KEY; - if (!apiKey) { - console.error("Error: HOUSECALL_PRO_API_KEY environment variable required"); - process.exit(1); - } - const client = new HousecallProClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/jobber/dist/index.d.ts b/mcp-diagrams/mcp-servers/jobber/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/jobber/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/jobber/dist/index.js b/mcp-diagrams/mcp-servers/jobber/dist/index.js deleted file mode 100644 index bf29e81..0000000 --- a/mcp-diagrams/mcp-servers/jobber/dist/index.js +++ /dev/null @@ -1,506 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "jobber"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.getjobber.com/api/graphql"; -// ============================================ -// GRAPHQL CLIENT -// ============================================ -class JobberClient { - accessToken; - constructor(accessToken) { - this.accessToken = accessToken; - } - async query(query, variables = {}) { - const response = await fetch(API_BASE_URL, { - method: "POST", - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - "X-JOBBER-GRAPHQL-VERSION": "2024-12-16", - }, - body: JSON.stringify({ query, variables }), - }); - if (!response.ok) { - throw new Error(`Jobber API error: ${response.status} ${response.statusText}`); - } - const result = await response.json(); - if (result.errors) { - throw new Error(`GraphQL error: ${JSON.stringify(result.errors)}`); - } - return result.data; - } -} -// ============================================ -// GRAPHQL QUERIES AND MUTATIONS -// ============================================ -const QUERIES = { - listJobs: ` - query ListJobs($first: Int, $after: String) { - jobs(first: $first, after: $after) { - nodes { - id - title - jobNumber - jobStatus - startAt - endAt - client { - id - name - } - property { - id - address { - street1 - city - province - postalCode - } - } - total - instructions - } - pageInfo { - hasNextPage - endCursor - } - } - } - `, - getJob: ` - query GetJob($id: EncodedId!) { - job(id: $id) { - id - title - jobNumber - jobStatus - startAt - endAt - client { - id - name - emails { - address - } - phones { - number - } - } - property { - id - address { - street1 - street2 - city - province - postalCode - country - } - } - lineItems { - nodes { - name - description - quantity - unitPrice - total - } - } - total - instructions - createdAt - updatedAt - } - } - `, - listQuotes: ` - query ListQuotes($first: Int, $after: String) { - quotes(first: $first, after: $after) { - nodes { - id - quoteNumber - quoteStatus - title - client { - id - name - } - amounts { - subtotal - total - } - createdAt - sentAt - } - pageInfo { - hasNextPage - endCursor - } - } - } - `, - listInvoices: ` - query ListInvoices($first: Int, $after: String) { - invoices(first: $first, after: $after) { - nodes { - id - invoiceNumber - invoiceStatus - subject - client { - id - name - } - amounts { - subtotal - total - depositAmount - discountAmount - paymentsTotal - invoiceBalance - } - dueDate - issuedDate - createdAt - } - pageInfo { - hasNextPage - endCursor - } - } - } - `, - listClients: ` - query ListClients($first: Int, $after: String, $searchTerm: String) { - clients(first: $first, after: $after, searchTerm: $searchTerm) { - nodes { - id - name - firstName - lastName - companyName - isCompany - emails { - address - primary - } - phones { - number - primary - } - billingAddress { - street1 - city - province - postalCode - } - createdAt - } - pageInfo { - hasNextPage - endCursor - } - } - } - `, -}; -const MUTATIONS = { - createJob: ` - mutation CreateJob($input: JobCreateInput!) { - jobCreate(input: $input) { - job { - id - title - jobNumber - jobStatus - } - userErrors { - message - path - } - } - } - `, - createQuote: ` - mutation CreateQuote($input: QuoteCreateInput!) { - quoteCreate(input: $input) { - quote { - id - quoteNumber - quoteStatus - title - } - userErrors { - message - path - } - } - } - `, - createClient: ` - mutation CreateClient($input: ClientCreateInput!) { - clientCreate(input: $input) { - client { - id - name - firstName - lastName - } - userErrors { - message - path - } - } - } - `, -}; -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_jobs", - description: "List jobs from Jobber with pagination", - inputSchema: { - type: "object", - properties: { - first: { type: "number", description: "Number of jobs to return (max 100)" }, - after: { type: "string", description: "Cursor for pagination" }, - }, - }, - }, - { - name: "get_job", - description: "Get a specific job by ID", - inputSchema: { - type: "object", - properties: { - id: { type: "string", description: "Job ID (encoded ID format)" }, - }, - required: ["id"], - }, - }, - { - name: "create_job", - description: "Create a new job in Jobber", - inputSchema: { - type: "object", - properties: { - clientId: { type: "string", description: "Client ID to associate job with" }, - title: { type: "string", description: "Job title" }, - instructions: { type: "string", description: "Job instructions/notes" }, - startAt: { type: "string", description: "Start date/time (ISO 8601)" }, - endAt: { type: "string", description: "End date/time (ISO 8601)" }, - lineItems: { - type: "array", - description: "Line items for the job", - items: { - type: "object", - properties: { - name: { type: "string" }, - description: { type: "string" }, - quantity: { type: "number" }, - unitPrice: { type: "number" }, - }, - }, - }, - }, - required: ["clientId", "title"], - }, - }, - { - name: "list_quotes", - description: "List quotes from Jobber with pagination", - inputSchema: { - type: "object", - properties: { - first: { type: "number", description: "Number of quotes to return (max 100)" }, - after: { type: "string", description: "Cursor for pagination" }, - }, - }, - }, - { - name: "create_quote", - description: "Create a new quote in Jobber", - inputSchema: { - type: "object", - properties: { - clientId: { type: "string", description: "Client ID to associate quote with" }, - title: { type: "string", description: "Quote title" }, - message: { type: "string", description: "Quote message to client" }, - lineItems: { - type: "array", - description: "Line items for the quote", - items: { - type: "object", - properties: { - name: { type: "string" }, - description: { type: "string" }, - quantity: { type: "number" }, - unitPrice: { type: "number" }, - }, - }, - }, - }, - required: ["clientId", "title"], - }, - }, - { - name: "list_invoices", - description: "List invoices from Jobber with pagination", - inputSchema: { - type: "object", - properties: { - first: { type: "number", description: "Number of invoices to return (max 100)" }, - after: { type: "string", description: "Cursor for pagination" }, - }, - }, - }, - { - name: "list_clients", - description: "List clients from Jobber with optional search", - inputSchema: { - type: "object", - properties: { - first: { type: "number", description: "Number of clients to return (max 100)" }, - after: { type: "string", description: "Cursor for pagination" }, - searchTerm: { type: "string", description: "Search term to filter clients" }, - }, - }, - }, - { - name: "create_client", - description: "Create a new client in Jobber", - inputSchema: { - type: "object", - properties: { - firstName: { type: "string", description: "Client first name" }, - lastName: { type: "string", description: "Client last name" }, - companyName: { type: "string", description: "Company name (for business clients)" }, - isCompany: { type: "boolean", description: "Whether this is a business client" }, - email: { type: "string", description: "Client email address" }, - phone: { type: "string", description: "Client phone number" }, - street1: { type: "string", description: "Street address" }, - city: { type: "string", description: "City" }, - province: { type: "string", description: "State/Province" }, - postalCode: { type: "string", description: "Postal/ZIP code" }, - }, - required: ["firstName", "lastName"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_jobs": { - const { first = 25, after } = args; - return await client.query(QUERIES.listJobs, { first, after }); - } - case "get_job": { - const { id } = args; - return await client.query(QUERIES.getJob, { id }); - } - case "create_job": { - const { clientId, title, instructions, startAt, endAt, lineItems } = args; - const input = { clientId, title }; - if (instructions) - input.instructions = instructions; - if (startAt) - input.startAt = startAt; - if (endAt) - input.endAt = endAt; - if (lineItems) - input.lineItems = lineItems; - return await client.query(MUTATIONS.createJob, { input }); - } - case "list_quotes": { - const { first = 25, after } = args; - return await client.query(QUERIES.listQuotes, { first, after }); - } - case "create_quote": { - const { clientId, title, message, lineItems } = args; - const input = { clientId, title }; - if (message) - input.message = message; - if (lineItems) - input.lineItems = lineItems; - return await client.query(MUTATIONS.createQuote, { input }); - } - case "list_invoices": { - const { first = 25, after } = args; - return await client.query(QUERIES.listInvoices, { first, after }); - } - case "list_clients": { - const { first = 25, after, searchTerm } = args; - return await client.query(QUERIES.listClients, { first, after, searchTerm }); - } - case "create_client": { - const { firstName, lastName, companyName, isCompany, email, phone, street1, city, province, postalCode } = args; - const input = { firstName, lastName }; - if (companyName) - input.companyName = companyName; - if (isCompany !== undefined) - input.isCompany = isCompany; - if (email) - input.emails = [{ address: email, primary: true }]; - if (phone) - input.phones = [{ number: phone, primary: true }]; - if (street1) { - input.billingAddress = { street1 }; - if (city) - input.billingAddress.city = city; - if (province) - input.billingAddress.province = province; - if (postalCode) - input.billingAddress.postalCode = postalCode; - } - return await client.query(MUTATIONS.createClient, { input }); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.JOBBER_ACCESS_TOKEN; - if (!accessToken) { - console.error("Error: JOBBER_ACCESS_TOKEN environment variable required"); - console.error("Obtain via OAuth2 flow at https://developer.getjobber.com"); - process.exit(1); - } - const client = new JobberClient(accessToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/keap/dist/index.d.ts b/mcp-diagrams/mcp-servers/keap/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/keap/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/keap/dist/index.js b/mcp-diagrams/mcp-servers/keap/dist/index.js deleted file mode 100644 index bc79326..0000000 --- a/mcp-diagrams/mcp-servers/keap/dist/index.js +++ /dev/null @@ -1,439 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "keap"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.infusionsoft.com/crm/rest/v1"; -// ============================================ -// API CLIENT - Keap uses OAuth2 Bearer token -// ============================================ -class KeapClient { - accessToken; - baseUrl; - constructor(accessToken) { - this.accessToken = accessToken; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Keap API error: ${response.status} ${response.statusText} - ${errorText}`); - } - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async patch(endpoint, data) { - return this.request(endpoint, { - method: "PATCH", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_contacts", - description: "List contacts with optional filtering and pagination", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max results to return (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - email: { type: "string", description: "Filter by email address" }, - given_name: { type: "string", description: "Filter by first name" }, - family_name: { type: "string", description: "Filter by last name" }, - order: { type: "string", description: "Field to order by (e.g., 'email', 'date_created')" }, - order_direction: { type: "string", enum: ["ASCENDING", "DESCENDING"], description: "Sort direction" }, - since: { type: "string", description: "Return contacts modified since this date (ISO 8601)" }, - until: { type: "string", description: "Return contacts modified before this date (ISO 8601)" }, - }, - }, - }, - { - name: "get_contact", - description: "Get a specific contact by ID with full details", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Contact ID" }, - optional_properties: { - type: "array", - items: { type: "string" }, - description: "Additional fields to include: custom_fields, fax_numbers, invoices, etc.", - }, - }, - required: ["id"], - }, - }, - { - name: "create_contact", - description: "Create a new contact in Keap", - inputSchema: { - type: "object", - properties: { - email_addresses: { - type: "array", - items: { - type: "object", - properties: { - email: { type: "string" }, - field: { type: "string", enum: ["EMAIL1", "EMAIL2", "EMAIL3"] }, - }, - }, - description: "Email addresses for the contact", - }, - given_name: { type: "string", description: "First name" }, - family_name: { type: "string", description: "Last name" }, - phone_numbers: { - type: "array", - items: { - type: "object", - properties: { - number: { type: "string" }, - field: { type: "string", enum: ["PHONE1", "PHONE2", "PHONE3", "PHONE4", "PHONE5"] }, - }, - }, - description: "Phone numbers", - }, - addresses: { - type: "array", - items: { - type: "object", - properties: { - line1: { type: "string" }, - line2: { type: "string" }, - locality: { type: "string", description: "City" }, - region: { type: "string", description: "State/Province" }, - postal_code: { type: "string" }, - country_code: { type: "string" }, - field: { type: "string", enum: ["BILLING", "SHIPPING", "OTHER"] }, - }, - }, - description: "Addresses", - }, - company: { - type: "object", - properties: { - company_name: { type: "string" }, - }, - description: "Company information", - }, - job_title: { type: "string", description: "Job title" }, - lead_source_id: { type: "number", description: "Lead source ID" }, - opt_in_reason: { type: "string", description: "Reason for opting in to marketing" }, - source_type: { type: "string", enum: ["WEBFORM", "LANDINGPAGE", "IMPORT", "MANUAL", "API", "OTHER"], description: "Source type" }, - custom_fields: { - type: "array", - items: { - type: "object", - properties: { - id: { type: "number" }, - content: { type: "string" }, - }, - }, - description: "Custom field values", - }, - }, - }, - }, - { - name: "update_contact", - description: "Update an existing contact", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Contact ID" }, - email_addresses: { type: "array", items: { type: "object" }, description: "Updated email addresses" }, - given_name: { type: "string", description: "First name" }, - family_name: { type: "string", description: "Last name" }, - phone_numbers: { type: "array", items: { type: "object" }, description: "Phone numbers" }, - addresses: { type: "array", items: { type: "object" }, description: "Addresses" }, - company: { type: "object", description: "Company information" }, - job_title: { type: "string", description: "Job title" }, - custom_fields: { type: "array", items: { type: "object" }, description: "Custom field values" }, - }, - required: ["id"], - }, - }, - { - name: "list_opportunities", - description: "List sales opportunities/deals", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max results (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - user_id: { type: "number", description: "Filter by assigned user ID" }, - stage_id: { type: "number", description: "Filter by pipeline stage ID" }, - search_term: { type: "string", description: "Search opportunities by title" }, - order: { type: "string", description: "Field to order by" }, - }, - }, - }, - { - name: "list_tasks", - description: "List tasks with optional filtering", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max results (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - contact_id: { type: "number", description: "Filter by contact ID" }, - user_id: { type: "number", description: "Filter by assigned user ID" }, - completed: { type: "boolean", description: "Filter by completion status" }, - since: { type: "string", description: "Tasks created/updated since (ISO 8601)" }, - until: { type: "string", description: "Tasks created/updated before (ISO 8601)" }, - order: { type: "string", description: "Field to order by" }, - }, - }, - }, - { - name: "create_task", - description: "Create a new task", - inputSchema: { - type: "object", - properties: { - title: { type: "string", description: "Task title (required)" }, - description: { type: "string", description: "Task description" }, - contact: { - type: "object", - properties: { - id: { type: "number" }, - }, - description: "Contact to associate the task with", - }, - due_date: { type: "string", description: "Due date in ISO 8601 format" }, - priority: { type: "number", description: "Priority (1-5, 5 being highest)" }, - type: { type: "string", description: "Task type (e.g., 'Call', 'Email', 'Appointment', 'Other')" }, - user_id: { type: "number", description: "User ID to assign the task to" }, - remind_time: { type: "number", description: "Reminder time in minutes before due date" }, - }, - required: ["title"], - }, - }, - { - name: "list_tags", - description: "List all tags available in the account", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max results (default 50, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - category: { type: "number", description: "Filter by tag category ID" }, - name: { type: "string", description: "Filter by tag name (partial match)" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_contacts": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.offset) - params.append("offset", args.offset.toString()); - if (args.email) - params.append("email", args.email); - if (args.given_name) - params.append("given_name", args.given_name); - if (args.family_name) - params.append("family_name", args.family_name); - if (args.order) - params.append("order", args.order); - if (args.order_direction) - params.append("order_direction", args.order_direction); - if (args.since) - params.append("since", args.since); - if (args.until) - params.append("until", args.until); - const query = params.toString(); - return await client.get(`/contacts${query ? `?${query}` : ""}`); - } - case "get_contact": { - const { id, optional_properties } = args; - let endpoint = `/contacts/${id}`; - if (optional_properties && optional_properties.length > 0) { - endpoint += `?optional_properties=${optional_properties.join(",")}`; - } - return await client.get(endpoint); - } - case "create_contact": { - const payload = {}; - if (args.email_addresses) - payload.email_addresses = args.email_addresses; - if (args.given_name) - payload.given_name = args.given_name; - if (args.family_name) - payload.family_name = args.family_name; - if (args.phone_numbers) - payload.phone_numbers = args.phone_numbers; - if (args.addresses) - payload.addresses = args.addresses; - if (args.company) - payload.company = args.company; - if (args.job_title) - payload.job_title = args.job_title; - if (args.lead_source_id) - payload.lead_source_id = args.lead_source_id; - if (args.opt_in_reason) - payload.opt_in_reason = args.opt_in_reason; - if (args.source_type) - payload.source_type = args.source_type; - if (args.custom_fields) - payload.custom_fields = args.custom_fields; - return await client.post("/contacts", payload); - } - case "update_contact": { - const { id, ...updates } = args; - return await client.patch(`/contacts/${id}`, updates); - } - case "list_opportunities": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.offset) - params.append("offset", args.offset.toString()); - if (args.user_id) - params.append("user_id", args.user_id.toString()); - if (args.stage_id) - params.append("stage_id", args.stage_id.toString()); - if (args.search_term) - params.append("search_term", args.search_term); - if (args.order) - params.append("order", args.order); - const query = params.toString(); - return await client.get(`/opportunities${query ? `?${query}` : ""}`); - } - case "list_tasks": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.offset) - params.append("offset", args.offset.toString()); - if (args.contact_id) - params.append("contact_id", args.contact_id.toString()); - if (args.user_id) - params.append("user_id", args.user_id.toString()); - if (args.completed !== undefined) - params.append("completed", args.completed.toString()); - if (args.since) - params.append("since", args.since); - if (args.until) - params.append("until", args.until); - if (args.order) - params.append("order", args.order); - const query = params.toString(); - return await client.get(`/tasks${query ? `?${query}` : ""}`); - } - case "create_task": { - const payload = { - title: args.title, - }; - if (args.description) - payload.description = args.description; - if (args.contact) - payload.contact = args.contact; - if (args.due_date) - payload.due_date = args.due_date; - if (args.priority) - payload.priority = args.priority; - if (args.type) - payload.type = args.type; - if (args.user_id) - payload.user_id = args.user_id; - if (args.remind_time) - payload.remind_time = args.remind_time; - return await client.post("/tasks", payload); - } - case "list_tags": { - const params = new URLSearchParams(); - if (args.limit) - params.append("limit", args.limit.toString()); - if (args.offset) - params.append("offset", args.offset.toString()); - if (args.category) - params.append("category", args.category.toString()); - if (args.name) - params.append("name", args.name); - const query = params.toString(); - return await client.get(`/tags${query ? `?${query}` : ""}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.KEAP_ACCESS_TOKEN; - if (!accessToken) { - console.error("Error: KEAP_ACCESS_TOKEN environment variable required"); - console.error("Get your access token from the Keap Developer Portal after OAuth2 authorization"); - process.exit(1); - } - const client = new KeapClient(accessToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/lightspeed/dist/index.d.ts b/mcp-diagrams/mcp-servers/lightspeed/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/lightspeed/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/lightspeed/dist/index.js b/mcp-diagrams/mcp-servers/lightspeed/dist/index.js deleted file mode 100644 index d68ff20..0000000 --- a/mcp-diagrams/mcp-servers/lightspeed/dist/index.js +++ /dev/null @@ -1,331 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// LIGHTSPEED RETAIL (R-SERIES) MCP SERVER -// API Docs: https://developers.lightspeedhq.com/retail/ -// ============================================ -const MCP_NAME = "lightspeed"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.lightspeedapp.com/API/V3/Account"; -// ============================================ -// API CLIENT - OAuth2 Authentication -// ============================================ -class LightspeedClient { - accessToken; - accountId; - baseUrl; - constructor(accessToken, accountId) { - this.accessToken = accessToken; - this.accountId = accountId; - this.baseUrl = `${API_BASE_URL}/${accountId}`; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}.json`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Lightspeed API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint, params) { - const queryString = params ? '?' + new URLSearchParams(params).toString() : ''; - return this.request(`${endpoint}${queryString}`, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_sales", - description: "List sales/transactions from Lightspeed Retail. Returns completed sales with line items, payments, and customer info.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max sales to return (default 100, max 100)" }, - offset: { type: "number", description: "Pagination offset" }, - completed: { type: "boolean", description: "Filter by completed status" }, - timeStamp: { type: "string", description: "Filter by timestamp (e.g., '>=,2024-01-01' or '<=,2024-12-31')" }, - employeeID: { type: "string", description: "Filter by employee ID" }, - shopID: { type: "string", description: "Filter by shop/location ID" }, - load_relations: { type: "string", description: "Comma-separated relations to load (e.g., 'SaleLines,SalePayments,Customer')" }, - }, - }, - }, - { - name: "get_sale", - description: "Get a specific sale by ID with full details including line items, payments, and customer", - inputSchema: { - type: "object", - properties: { - sale_id: { type: "string", description: "Sale ID" }, - load_relations: { type: "string", description: "Comma-separated relations (e.g., 'SaleLines,SalePayments,Customer,SaleLines.Item')" }, - }, - required: ["sale_id"], - }, - }, - { - name: "list_items", - description: "List inventory items from Lightspeed Retail catalog", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max items to return (default 100, max 100)" }, - offset: { type: "number", description: "Pagination offset" }, - categoryID: { type: "string", description: "Filter by category ID" }, - manufacturerID: { type: "string", description: "Filter by manufacturer ID" }, - description: { type: "string", description: "Search by description (supports ~ for contains)" }, - upc: { type: "string", description: "Filter by UPC barcode" }, - customSku: { type: "string", description: "Filter by custom SKU" }, - archived: { type: "boolean", description: "Include archived items" }, - load_relations: { type: "string", description: "Comma-separated relations (e.g., 'ItemShops,Category,Manufacturer')" }, - }, - }, - }, - { - name: "get_item", - description: "Get a specific inventory item by ID with full details", - inputSchema: { - type: "object", - properties: { - item_id: { type: "string", description: "Item ID" }, - load_relations: { type: "string", description: "Comma-separated relations (e.g., 'ItemShops,Category,Manufacturer,Prices')" }, - }, - required: ["item_id"], - }, - }, - { - name: "update_inventory", - description: "Update inventory quantity for an item at a specific shop location", - inputSchema: { - type: "object", - properties: { - item_shop_id: { type: "string", description: "ItemShop ID (the item-location relationship ID)" }, - qoh: { type: "number", description: "New quantity on hand" }, - reorderPoint: { type: "number", description: "Reorder point threshold" }, - reorderLevel: { type: "number", description: "Reorder quantity level" }, - }, - required: ["item_shop_id", "qoh"], - }, - }, - { - name: "list_customers", - description: "List customers from Lightspeed Retail", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max customers to return (default 100, max 100)" }, - offset: { type: "number", description: "Pagination offset" }, - firstName: { type: "string", description: "Filter by first name (supports ~ for contains)" }, - lastName: { type: "string", description: "Filter by last name (supports ~ for contains)" }, - email: { type: "string", description: "Filter by email address" }, - phone: { type: "string", description: "Filter by phone number" }, - customerTypeID: { type: "string", description: "Filter by customer type ID" }, - load_relations: { type: "string", description: "Comma-separated relations (e.g., 'Contact,CustomerType')" }, - }, - }, - }, - { - name: "list_categories", - description: "List product categories from Lightspeed Retail catalog", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max categories to return (default 100, max 100)" }, - offset: { type: "number", description: "Pagination offset" }, - parentID: { type: "string", description: "Filter by parent category ID (0 for root categories)" }, - name: { type: "string", description: "Filter by category name (supports ~ for contains)" }, - load_relations: { type: "string", description: "Comma-separated relations (e.g., 'Items')" }, - }, - }, - }, - { - name: "get_register", - description: "Get register/POS terminal information and status", - inputSchema: { - type: "object", - properties: { - register_id: { type: "string", description: "Register ID (optional - lists all if not provided)" }, - shopID: { type: "string", description: "Filter by shop/location ID" }, - load_relations: { type: "string", description: "Comma-separated relations (e.g., 'Shop,RegisterCounts')" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_sales": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.offset) - params.offset = String(args.offset); - if (args.completed !== undefined) - params.completed = args.completed ? 'true' : 'false'; - if (args.timeStamp) - params.timeStamp = args.timeStamp; - if (args.employeeID) - params.employeeID = args.employeeID; - if (args.shopID) - params.shopID = args.shopID; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - return await client.get("/Sale", params); - } - case "get_sale": { - const params = {}; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - return await client.get(`/Sale/${args.sale_id}`, params); - } - case "list_items": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.offset) - params.offset = String(args.offset); - if (args.categoryID) - params.categoryID = args.categoryID; - if (args.manufacturerID) - params.manufacturerID = args.manufacturerID; - if (args.description) - params.description = args.description; - if (args.upc) - params.upc = args.upc; - if (args.customSku) - params.customSku = args.customSku; - if (args.archived !== undefined) - params.archived = args.archived ? 'true' : 'false'; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - return await client.get("/Item", params); - } - case "get_item": { - const params = {}; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - return await client.get(`/Item/${args.item_id}`, params); - } - case "update_inventory": { - const data = { qoh: args.qoh }; - if (args.reorderPoint !== undefined) - data.reorderPoint = args.reorderPoint; - if (args.reorderLevel !== undefined) - data.reorderLevel = args.reorderLevel; - return await client.put(`/ItemShop/${args.item_shop_id}`, data); - } - case "list_customers": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.offset) - params.offset = String(args.offset); - if (args.firstName) - params.firstName = args.firstName; - if (args.lastName) - params.lastName = args.lastName; - if (args.email) - params['Contact.email'] = args.email; - if (args.phone) - params['Contact.phone'] = args.phone; - if (args.customerTypeID) - params.customerTypeID = args.customerTypeID; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - return await client.get("/Customer", params); - } - case "list_categories": { - const params = {}; - if (args.limit) - params.limit = String(args.limit); - if (args.offset) - params.offset = String(args.offset); - if (args.parentID) - params.parentID = args.parentID; - if (args.name) - params.name = args.name; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - return await client.get("/Category", params); - } - case "get_register": { - const params = {}; - if (args.shopID) - params.shopID = args.shopID; - if (args.load_relations) - params.load_relations = `["${args.load_relations.split(',').join('","')}"]`; - if (args.register_id) { - return await client.get(`/Register/${args.register_id}`, params); - } - return await client.get("/Register", params); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.LIGHTSPEED_ACCESS_TOKEN; - const accountId = process.env.LIGHTSPEED_ACCOUNT_ID; - if (!accessToken) { - console.error("Error: LIGHTSPEED_ACCESS_TOKEN environment variable required"); - process.exit(1); - } - if (!accountId) { - console.error("Error: LIGHTSPEED_ACCOUNT_ID environment variable required"); - process.exit(1); - } - const client = new LightspeedClient(accessToken, accountId); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/mailchimp/dist/index.d.ts b/mcp-diagrams/mcp-servers/mailchimp/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/mailchimp/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/mailchimp/dist/index.js b/mcp-diagrams/mcp-servers/mailchimp/dist/index.js deleted file mode 100644 index 05a07b2..0000000 --- a/mcp-diagrams/mcp-servers/mailchimp/dist/index.js +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -import { createHash } from "crypto"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "mailchimp"; -const MCP_VERSION = "1.0.0"; -// ============================================ -// API CLIENT -// ============================================ -class MailchimpClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - // Extract data center from API key (format: key-dc) - const dc = apiKey.split("-").pop() || "us1"; - this.baseUrl = `https://${dc}.api.mailchimp.com/3.0`; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Mailchimp API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async patch(endpoint, data) { - return this.request(endpoint, { - method: "PATCH", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - // Helper to hash email for subscriber operations - hashEmail(email) { - return createHash("md5").update(email.toLowerCase()).digest("hex"); - } - // Campaign endpoints - async listCampaigns(count, offset, status, type) { - const params = new URLSearchParams(); - if (count) - params.append("count", count.toString()); - if (offset) - params.append("offset", offset.toString()); - if (status) - params.append("status", status); - if (type) - params.append("type", type); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/campaigns${query}`); - } - async getCampaign(campaignId) { - return this.get(`/campaigns/${campaignId}`); - } - async createCampaign(type, settings, recipients) { - const payload = { type, settings }; - if (recipients) - payload.recipients = recipients; - return this.post("/campaigns", payload); - } - async sendCampaign(campaignId) { - return this.post(`/campaigns/${campaignId}/actions/send`, {}); - } - // List/Audience endpoints - async listLists(count, offset) { - const params = new URLSearchParams(); - if (count) - params.append("count", count.toString()); - if (offset) - params.append("offset", offset.toString()); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/lists${query}`); - } - async addSubscriber(listId, email, status, mergeFields, tags) { - const payload = { - email_address: email, - status: status, // subscribed, unsubscribed, cleaned, pending, transactional - }; - if (mergeFields) - payload.merge_fields = mergeFields; - if (tags) - payload.tags = tags; - return this.post(`/lists/${listId}/members`, payload); - } - async getSubscriber(listId, email) { - const hash = this.hashEmail(email); - return this.get(`/lists/${listId}/members/${hash}`); - } - // Template endpoints - async listTemplates(count, offset, type) { - const params = new URLSearchParams(); - if (count) - params.append("count", count.toString()); - if (offset) - params.append("offset", offset.toString()); - if (type) - params.append("type", type); - const query = params.toString() ? `?${params.toString()}` : ""; - return this.get(`/templates${query}`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_campaigns", - description: "List email campaigns in Mailchimp", - inputSchema: { - type: "object", - properties: { - count: { type: "number", description: "Number of campaigns to return (max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - status: { - type: "string", - description: "Filter by status: save, paused, schedule, sending, sent", - enum: ["save", "paused", "schedule", "sending", "sent"] - }, - type: { - type: "string", - description: "Filter by type: regular, plaintext, absplit, rss, variate", - enum: ["regular", "plaintext", "absplit", "rss", "variate"] - }, - }, - }, - }, - { - name: "get_campaign", - description: "Get details of a specific campaign", - inputSchema: { - type: "object", - properties: { - campaign_id: { type: "string", description: "The campaign ID" }, - }, - required: ["campaign_id"], - }, - }, - { - name: "create_campaign", - description: "Create a new email campaign", - inputSchema: { - type: "object", - properties: { - type: { - type: "string", - description: "Campaign type: regular, plaintext, absplit, rss, variate", - enum: ["regular", "plaintext", "absplit", "rss", "variate"] - }, - list_id: { type: "string", description: "The list/audience ID to send to" }, - subject_line: { type: "string", description: "Email subject line" }, - preview_text: { type: "string", description: "Preview text (snippet)" }, - title: { type: "string", description: "Internal campaign title" }, - from_name: { type: "string", description: "Sender name" }, - reply_to: { type: "string", description: "Reply-to email address" }, - }, - required: ["type", "list_id", "subject_line", "from_name", "reply_to"], - }, - }, - { - name: "send_campaign", - description: "Send a campaign immediately (campaign must be ready to send)", - inputSchema: { - type: "object", - properties: { - campaign_id: { type: "string", description: "The campaign ID to send" }, - }, - required: ["campaign_id"], - }, - }, - { - name: "list_lists", - description: "List all audiences/lists in the account", - inputSchema: { - type: "object", - properties: { - count: { type: "number", description: "Number of lists to return" }, - offset: { type: "number", description: "Pagination offset" }, - }, - }, - }, - { - name: "add_subscriber", - description: "Add a new subscriber to an audience/list", - inputSchema: { - type: "object", - properties: { - list_id: { type: "string", description: "The list/audience ID" }, - email: { type: "string", description: "Subscriber email address" }, - status: { - type: "string", - description: "Subscription status", - enum: ["subscribed", "unsubscribed", "cleaned", "pending", "transactional"] - }, - first_name: { type: "string", description: "Subscriber first name" }, - last_name: { type: "string", description: "Subscriber last name" }, - tags: { - type: "array", - items: { type: "string" }, - description: "Tags to apply to subscriber" - }, - }, - required: ["list_id", "email", "status"], - }, - }, - { - name: "get_subscriber", - description: "Get subscriber information by email address", - inputSchema: { - type: "object", - properties: { - list_id: { type: "string", description: "The list/audience ID" }, - email: { type: "string", description: "Subscriber email address" }, - }, - required: ["list_id", "email"], - }, - }, - { - name: "list_templates", - description: "List available email templates", - inputSchema: { - type: "object", - properties: { - count: { type: "number", description: "Number of templates to return" }, - offset: { type: "number", description: "Pagination offset" }, - type: { - type: "string", - description: "Filter by template type: user, base, gallery", - enum: ["user", "base", "gallery"] - }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_campaigns": { - const { count, offset, status, type } = args; - return await client.listCampaigns(count, offset, status, type); - } - case "get_campaign": { - const { campaign_id } = args; - return await client.getCampaign(campaign_id); - } - case "create_campaign": { - const { type, list_id, subject_line, preview_text, title, from_name, reply_to } = args; - const settings = { - subject_line, - from_name, - reply_to, - }; - if (preview_text) - settings.preview_text = preview_text; - if (title) - settings.title = title; - const recipients = { list_id }; - return await client.createCampaign(type, settings, recipients); - } - case "send_campaign": { - const { campaign_id } = args; - return await client.sendCampaign(campaign_id); - } - case "list_lists": { - const { count, offset } = args; - return await client.listLists(count, offset); - } - case "add_subscriber": { - const { list_id, email, status, first_name, last_name, tags } = args; - const mergeFields = {}; - if (first_name) - mergeFields.FNAME = first_name; - if (last_name) - mergeFields.LNAME = last_name; - return await client.addSubscriber(list_id, email, status, Object.keys(mergeFields).length > 0 ? mergeFields : undefined, tags); - } - case "get_subscriber": { - const { list_id, email } = args; - return await client.getSubscriber(list_id, email); - } - case "list_templates": { - const { count, offset, type } = args; - return await client.listTemplates(count, offset, type); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.MAILCHIMP_API_KEY; - if (!apiKey) { - console.error("Error: MAILCHIMP_API_KEY environment variable required"); - console.error("Format: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us1 (key-datacenter)"); - process.exit(1); - } - const client = new MailchimpClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/pipedrive/dist/index.d.ts b/mcp-diagrams/mcp-servers/pipedrive/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/pipedrive/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/pipedrive/dist/index.js b/mcp-diagrams/mcp-servers/pipedrive/dist/index.js deleted file mode 100644 index c3a8108..0000000 --- a/mcp-diagrams/mcp-servers/pipedrive/dist/index.js +++ /dev/null @@ -1,302 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "pipedrive"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.pipedrive.com/v1"; -// ============================================ -// API CLIENT -// ============================================ -class PipedriveClient { - apiToken; - baseUrl; - constructor(apiToken) { - this.apiToken = apiToken; - this.baseUrl = API_BASE_URL; - } - buildUrl(endpoint, params = {}) { - const url = new URL(`${this.baseUrl}${endpoint}`); - url.searchParams.set("api_token", this.apiToken); - for (const [key, value] of Object.entries(params)) { - if (value !== undefined && value !== null) { - url.searchParams.set(key, String(value)); - } - } - return url.toString(); - } - async request(endpoint, options = {}, params = {}) { - const url = this.buildUrl(endpoint, options.method === "GET" ? params : {}); - const response = await fetch(url, { - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const error = await response.text(); - throw new Error(`Pipedrive API error: ${response.status} - ${error}`); - } - return response.json(); - } - async get(endpoint, params = {}) { - return this.request(endpoint, { method: "GET" }, params); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_deals", - description: "List all deals from Pipedrive. Returns paginated list of deals with their details.", - inputSchema: { - type: "object", - properties: { - status: { - type: "string", - description: "Filter by deal status", - enum: ["open", "won", "lost", "deleted", "all_not_deleted"] - }, - start: { type: "number", description: "Pagination start (default 0)" }, - limit: { type: "number", description: "Items per page (default 100, max 500)" }, - sort: { type: "string", description: "Field to sort by (e.g., 'add_time DESC')" }, - user_id: { type: "number", description: "Filter by owner user ID" }, - stage_id: { type: "number", description: "Filter by pipeline stage ID" }, - pipeline_id: { type: "number", description: "Filter by pipeline ID" }, - }, - }, - }, - { - name: "get_deal", - description: "Get details of a specific deal by ID", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Deal ID" }, - }, - required: ["id"], - }, - }, - { - name: "create_deal", - description: "Create a new deal in Pipedrive", - inputSchema: { - type: "object", - properties: { - title: { type: "string", description: "Deal title (required)" }, - value: { type: "number", description: "Deal value/amount" }, - currency: { type: "string", description: "Currency code (e.g., USD, EUR)" }, - person_id: { type: "number", description: "ID of person to link" }, - org_id: { type: "number", description: "ID of organization to link" }, - pipeline_id: { type: "number", description: "Pipeline ID" }, - stage_id: { type: "number", description: "Stage ID within pipeline" }, - status: { type: "string", enum: ["open", "won", "lost"], description: "Deal status" }, - expected_close_date: { type: "string", description: "Expected close date (YYYY-MM-DD)" }, - probability: { type: "number", description: "Deal success probability (0-100)" }, - visible_to: { type: "number", description: "Visibility (1=owner, 3=entire company)" }, - }, - required: ["title"], - }, - }, - { - name: "update_deal", - description: "Update an existing deal", - inputSchema: { - type: "object", - properties: { - id: { type: "number", description: "Deal ID to update" }, - title: { type: "string", description: "Deal title" }, - value: { type: "number", description: "Deal value/amount" }, - currency: { type: "string", description: "Currency code" }, - person_id: { type: "number", description: "ID of person to link" }, - org_id: { type: "number", description: "ID of organization to link" }, - stage_id: { type: "number", description: "Stage ID within pipeline" }, - status: { type: "string", enum: ["open", "won", "lost"], description: "Deal status" }, - expected_close_date: { type: "string", description: "Expected close date (YYYY-MM-DD)" }, - probability: { type: "number", description: "Deal success probability (0-100)" }, - lost_reason: { type: "string", description: "Reason for losing (if status=lost)" }, - won_time: { type: "string", description: "Won timestamp (if status=won)" }, - lost_time: { type: "string", description: "Lost timestamp (if status=lost)" }, - }, - required: ["id"], - }, - }, - { - name: "list_persons", - description: "List all persons (contacts) from Pipedrive", - inputSchema: { - type: "object", - properties: { - start: { type: "number", description: "Pagination start (default 0)" }, - limit: { type: "number", description: "Items per page (default 100, max 500)" }, - sort: { type: "string", description: "Field to sort by" }, - filter_id: { type: "number", description: "Filter ID to apply" }, - first_char: { type: "string", description: "Filter by first character of name" }, - }, - }, - }, - { - name: "create_person", - description: "Create a new person (contact) in Pipedrive", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Person's name (required)" }, - email: { - type: "array", - items: { type: "object" }, - description: "Email addresses [{value: 'email@example.com', primary: true, label: 'work'}]" - }, - phone: { - type: "array", - items: { type: "object" }, - description: "Phone numbers [{value: '+1234567890', primary: true, label: 'work'}]" - }, - org_id: { type: "number", description: "Organization ID to link" }, - visible_to: { type: "number", description: "Visibility (1=owner, 3=entire company)" }, - add_time: { type: "string", description: "Creation time (YYYY-MM-DD HH:MM:SS)" }, - }, - required: ["name"], - }, - }, - { - name: "list_activities", - description: "List all activities from Pipedrive", - inputSchema: { - type: "object", - properties: { - start: { type: "number", description: "Pagination start (default 0)" }, - limit: { type: "number", description: "Items per page (default 100, max 500)" }, - user_id: { type: "number", description: "Filter by user ID" }, - type: { type: "string", description: "Activity type (call, meeting, task, deadline, email, lunch)" }, - done: { type: "number", description: "Filter by done status (0 or 1)" }, - start_date: { type: "string", description: "Start date filter (YYYY-MM-DD)" }, - end_date: { type: "string", description: "End date filter (YYYY-MM-DD)" }, - }, - }, - }, - { - name: "add_activity", - description: "Add a new activity to Pipedrive", - inputSchema: { - type: "object", - properties: { - subject: { type: "string", description: "Activity subject (required)" }, - type: { - type: "string", - description: "Activity type (call, meeting, task, deadline, email, lunch)" - }, - due_date: { type: "string", description: "Due date (YYYY-MM-DD)" }, - due_time: { type: "string", description: "Due time (HH:MM)" }, - duration: { type: "string", description: "Duration (HH:MM)" }, - deal_id: { type: "number", description: "Deal ID to link" }, - person_id: { type: "number", description: "Person ID to link" }, - org_id: { type: "number", description: "Organization ID to link" }, - note: { type: "string", description: "Activity note/description" }, - done: { type: "number", description: "Mark as done (0 or 1)" }, - busy_flag: { type: "boolean", description: "Mark as busy in calendar" }, - participants: { - type: "array", - items: { type: "object" }, - description: "Participants [{person_id: 1, primary_flag: true}]" - }, - }, - required: ["subject"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_deals": { - const { status, start, limit, sort, user_id, stage_id, pipeline_id } = args; - return await client.get("/deals", { - status, start, limit, sort, user_id, stage_id, pipeline_id - }); - } - case "get_deal": { - const { id } = args; - return await client.get(`/deals/${id}`); - } - case "create_deal": { - const { id, ...data } = args; - return await client.post("/deals", data); - } - case "update_deal": { - const { id, ...data } = args; - return await client.put(`/deals/${id}`, data); - } - case "list_persons": { - const { start, limit, sort, filter_id, first_char } = args; - return await client.get("/persons", { start, limit, sort, filter_id, first_char }); - } - case "create_person": { - return await client.post("/persons", args); - } - case "list_activities": { - const { start, limit, user_id, type, done, start_date, end_date } = args; - return await client.get("/activities", { - start, limit, user_id, type, done, start_date, end_date - }); - } - case "add_activity": { - return await client.post("/activities", args); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiToken = process.env.PIPEDRIVE_API_TOKEN; - if (!apiToken) { - console.error("Error: PIPEDRIVE_API_TOKEN environment variable required"); - process.exit(1); - } - const client = new PipedriveClient(apiToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/rippling/dist/index.d.ts b/mcp-diagrams/mcp-servers/rippling/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/rippling/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/rippling/dist/index.js b/mcp-diagrams/mcp-servers/rippling/dist/index.js deleted file mode 100644 index 86b0000..0000000 --- a/mcp-diagrams/mcp-servers/rippling/dist/index.js +++ /dev/null @@ -1,320 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "rippling"; -const MCP_VERSION = "1.0.0"; -// Rippling API base URL -const API_BASE_URL = "https://api.rippling.com/platform/api"; -// ============================================ -// API CLIENT -// ============================================ -class RipplingClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Rippling API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_employees", - description: "List employees in the organization. Returns employee details including name, email, department, and employment status.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max employees to return (default 100, max 1000)" }, - offset: { type: "number", description: "Pagination offset" }, - include_terminated: { type: "boolean", description: "Include terminated employees (default false)" }, - }, - }, - }, - { - name: "get_employee", - description: "Get detailed information about a specific employee including personal info, employment details, and manager.", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Employee ID (Rippling unique identifier)" }, - }, - required: ["employee_id"], - }, - }, - { - name: "list_departments", - description: "List all departments in the organization with their names and hierarchy.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max departments to return" }, - offset: { type: "number", description: "Pagination offset" }, - }, - }, - }, - { - name: "list_teams", - description: "List all teams in the organization. Teams are groups of employees that can span departments.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max teams to return" }, - offset: { type: "number", description: "Pagination offset" }, - }, - }, - }, - { - name: "get_payroll", - description: "Get payroll information and pay runs. Requires payroll read permissions.", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Filter by specific employee ID" }, - start_date: { type: "string", description: "Filter pay runs starting on or after (YYYY-MM-DD)" }, - end_date: { type: "string", description: "Filter pay runs ending on or before (YYYY-MM-DD)" }, - }, - }, - }, - { - name: "list_devices", - description: "List devices managed by Rippling IT. Includes computers, phones, and other equipment assigned to employees.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max devices to return" }, - offset: { type: "number", description: "Pagination offset" }, - employee_id: { type: "string", description: "Filter by assigned employee" }, - device_type: { type: "string", description: "Filter by type: laptop, desktop, phone, tablet" }, - }, - }, - }, - { - name: "list_apps", - description: "List applications integrated with Rippling. Shows apps available for provisioning to employees.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max apps to return" }, - offset: { type: "number", description: "Pagination offset" }, - }, - }, - }, - { - name: "get_company", - description: "Get information about the current company including name, EIN, and settings.", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "list_groups", - description: "List custom groups defined in Rippling. Groups can be used for access control and app provisioning.", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "list_levels", - description: "List job levels defined in the organization (e.g., IC1, IC2, Manager, Director).", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max levels to return" }, - offset: { type: "number", description: "Pagination offset" }, - }, - }, - }, - { - name: "list_work_locations", - description: "List work locations/offices defined in the organization.", - inputSchema: { - type: "object", - properties: { - limit: { type: "number", description: "Max locations to return" }, - offset: { type: "number", description: "Pagination offset" }, - }, - }, - }, - { - name: "get_leave_requests", - description: "Get leave/time-off requests. Filter by employee, status, or date range.", - inputSchema: { - type: "object", - properties: { - employee_id: { type: "string", description: "Filter by employee ID" }, - status: { type: "string", description: "Filter by status: pending, approved, denied, cancelled" }, - start_date: { type: "string", description: "Filter leave starting on or after (YYYY-MM-DD)" }, - end_date: { type: "string", description: "Filter leave ending on or before (YYYY-MM-DD)" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_employees": { - const { limit = 100, offset = 0, include_terminated = false } = args; - const params = new URLSearchParams(); - params.append("limit", String(Math.min(limit, 1000))); - params.append("offset", String(offset)); - const endpoint = include_terminated - ? `/employees?${params}&includeTerminated=true` - : `/employees?${params}`; - return await client.get(endpoint); - } - case "get_employee": { - const { employee_id } = args; - return await client.get(`/employees/${employee_id}`); - } - case "list_departments": { - const { limit = 100, offset = 0 } = args; - const params = new URLSearchParams(); - params.append("limit", String(limit)); - params.append("offset", String(offset)); - return await client.get(`/departments?${params}`); - } - case "list_teams": { - const { limit = 100, offset = 0 } = args; - const params = new URLSearchParams(); - params.append("limit", String(limit)); - params.append("offset", String(offset)); - return await client.get(`/teams?${params}`); - } - case "get_payroll": { - const { employee_id, start_date, end_date } = args; - const params = new URLSearchParams(); - if (employee_id) - params.append("employeeId", employee_id); - if (start_date) - params.append("startDate", start_date); - if (end_date) - params.append("endDate", end_date); - const query = params.toString(); - return await client.get(`/payroll${query ? `?${query}` : ""}`); - } - case "list_devices": { - const { limit = 100, offset = 0, employee_id, device_type } = args; - const params = new URLSearchParams(); - params.append("limit", String(limit)); - params.append("offset", String(offset)); - if (employee_id) - params.append("employeeId", employee_id); - if (device_type) - params.append("deviceType", device_type); - return await client.get(`/devices?${params}`); - } - case "list_apps": { - const { limit = 100, offset = 0 } = args; - const params = new URLSearchParams(); - params.append("limit", String(limit)); - params.append("offset", String(offset)); - return await client.get(`/apps?${params}`); - } - case "get_company": { - return await client.get("/companies/current"); - } - case "list_groups": { - return await client.get("/groups"); - } - case "list_levels": { - const { limit = 100, offset = 0 } = args; - const params = new URLSearchParams(); - params.append("limit", String(limit)); - params.append("offset", String(offset)); - return await client.get(`/levels?${params}`); - } - case "list_work_locations": { - const { limit = 100, offset = 0 } = args; - const params = new URLSearchParams(); - params.append("limit", String(limit)); - params.append("offset", String(offset)); - return await client.get(`/work-locations?${params}`); - } - case "get_leave_requests": { - const { employee_id, status, start_date, end_date } = args; - const params = new URLSearchParams(); - if (employee_id) - params.append("requestedBy", employee_id); - if (status) - params.append("status", status); - if (start_date) - params.append("from", start_date); - if (end_date) - params.append("to", end_date); - const query = params.toString(); - return await client.get(`/leave-requests${query ? `?${query}` : ""}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.RIPPLING_API_KEY; - if (!apiKey) { - console.error("Error: RIPPLING_API_KEY environment variable required"); - process.exit(1); - } - const client = new RipplingClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/servicetitan/dist/index.d.ts b/mcp-diagrams/mcp-servers/servicetitan/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/servicetitan/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/servicetitan/dist/index.js b/mcp-diagrams/mcp-servers/servicetitan/dist/index.js deleted file mode 100644 index 9c0e1ca..0000000 --- a/mcp-diagrams/mcp-servers/servicetitan/dist/index.js +++ /dev/null @@ -1,367 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "servicetitan"; -const MCP_VERSION = "1.0.0"; -// ServiceTitan API base URL -const API_BASE_URL = "https://api.servicetitan.io"; -const AUTH_URL = "https://auth.servicetitan.io/connect/token"; -// ============================================ -// API CLIENT -// ============================================ -class ServiceTitanClient { - clientId; - clientSecret; - tenantId; - baseUrl; - accessToken = null; - tokenExpiry = 0; - constructor(clientId, clientSecret, tenantId) { - this.clientId = clientId; - this.clientSecret = clientSecret; - this.tenantId = tenantId; - this.baseUrl = API_BASE_URL; - } - async getAccessToken() { - // Return cached token if still valid (with 5 min buffer) - if (this.accessToken && Date.now() < this.tokenExpiry - 300000) { - return this.accessToken; - } - // Request new token using client credentials - const response = await fetch(AUTH_URL, { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: new URLSearchParams({ - grant_type: "client_credentials", - client_id: this.clientId, - client_secret: this.clientSecret, - }), - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`ServiceTitan auth error: ${response.status} - ${errorText}`); - } - const data = await response.json(); - this.accessToken = data.access_token; - this.tokenExpiry = Date.now() + (data.expires_in * 1000); - return this.accessToken; - } - async request(endpoint, options = {}) { - const token = await this.getAccessToken(); - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${token}`, - "Content-Type": "application/json", - "ST-App-Key": this.clientId, - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`ServiceTitan API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - getTenantId() { - return this.tenantId; - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_jobs", - description: "List jobs/work orders. Jobs represent scheduled service work including location, customer, and technician assignments.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Results per page (default 50, max 100)" }, - status: { type: "string", description: "Filter by status: Scheduled, InProgress, Completed, Canceled" }, - customerId: { type: "number", description: "Filter by customer ID" }, - technicianId: { type: "number", description: "Filter by technician ID" }, - createdOnOrAfter: { type: "string", description: "Filter jobs created on or after (ISO 8601)" }, - completedOnOrAfter: { type: "string", description: "Filter jobs completed on or after (ISO 8601)" }, - }, - }, - }, - { - name: "get_job", - description: "Get detailed information about a specific job including line items, equipment, and history.", - inputSchema: { - type: "object", - properties: { - job_id: { type: "number", description: "Job ID" }, - }, - required: ["job_id"], - }, - }, - { - name: "create_job", - description: "Create a new job/work order. Requires customer, location, and job type.", - inputSchema: { - type: "object", - properties: { - customerId: { type: "number", description: "Customer ID" }, - locationId: { type: "number", description: "Service location ID" }, - jobTypeId: { type: "number", description: "Job type ID" }, - priority: { type: "string", description: "Priority: Low, Normal, High, Urgent" }, - businessUnitId: { type: "number", description: "Business unit ID" }, - campaignId: { type: "number", description: "Marketing campaign ID" }, - summary: { type: "string", description: "Job summary/description" }, - scheduledStart: { type: "string", description: "Scheduled start time (ISO 8601)" }, - scheduledEnd: { type: "string", description: "Scheduled end time (ISO 8601)" }, - }, - required: ["customerId", "locationId", "jobTypeId"], - }, - }, - { - name: "list_customers", - description: "List customers in the CRM. Includes contact info, locations, and account details.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Results per page (default 50, max 100)" }, - name: { type: "string", description: "Filter by customer name (partial match)" }, - email: { type: "string", description: "Filter by email address" }, - phone: { type: "string", description: "Filter by phone number" }, - createdOnOrAfter: { type: "string", description: "Filter customers created on or after (ISO 8601)" }, - active: { type: "boolean", description: "Filter by active status" }, - }, - }, - }, - { - name: "get_customer", - description: "Get detailed customer information including all locations, contacts, and service history.", - inputSchema: { - type: "object", - properties: { - customer_id: { type: "number", description: "Customer ID" }, - }, - required: ["customer_id"], - }, - }, - { - name: "list_invoices", - description: "List invoices. Includes amounts, status, line items, and payment information.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Results per page (default 50, max 100)" }, - status: { type: "string", description: "Filter by status: Pending, Posted, Exported" }, - customerId: { type: "number", description: "Filter by customer ID" }, - jobId: { type: "number", description: "Filter by job ID" }, - createdOnOrAfter: { type: "string", description: "Filter invoices created on or after (ISO 8601)" }, - total_gte: { type: "number", description: "Filter by minimum total amount" }, - }, - }, - }, - { - name: "list_technicians", - description: "List technicians/field workers. Includes contact info, skills, and availability.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Results per page (default 50, max 100)" }, - active: { type: "boolean", description: "Filter by active status" }, - businessUnitId: { type: "number", description: "Filter by business unit" }, - }, - }, - }, - { - name: "list_appointments", - description: "List scheduled appointments. Shows booking windows, assigned technicians, and status.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Results per page (default 50, max 100)" }, - startsOnOrAfter: { type: "string", description: "Filter appointments starting on or after (ISO 8601)" }, - startsOnOrBefore: { type: "string", description: "Filter appointments starting on or before (ISO 8601)" }, - technicianId: { type: "number", description: "Filter by assigned technician" }, - jobId: { type: "number", description: "Filter by job ID" }, - }, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - const tenantId = client.getTenantId(); - switch (name) { - case "list_jobs": { - const { page = 1, pageSize = 50, status, customerId, technicianId, createdOnOrAfter, completedOnOrAfter } = args; - const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(Math.min(pageSize, 100))); - if (status) - params.append("status", status); - if (customerId) - params.append("customerId", String(customerId)); - if (technicianId) - params.append("technicianId", String(technicianId)); - if (createdOnOrAfter) - params.append("createdOnOrAfter", createdOnOrAfter); - if (completedOnOrAfter) - params.append("completedOnOrAfter", completedOnOrAfter); - return await client.get(`/jpm/v2/tenant/${tenantId}/jobs?${params}`); - } - case "get_job": { - const { job_id } = args; - return await client.get(`/jpm/v2/tenant/${tenantId}/jobs/${job_id}`); - } - case "create_job": { - const { customerId, locationId, jobTypeId, priority = "Normal", businessUnitId, campaignId, summary, scheduledStart, scheduledEnd } = args; - const jobData = { - customerId, - locationId, - jobTypeId, - priority, - }; - if (businessUnitId) - jobData.businessUnitId = businessUnitId; - if (campaignId) - jobData.campaignId = campaignId; - if (summary) - jobData.summary = summary; - if (scheduledStart) - jobData.start = scheduledStart; - if (scheduledEnd) - jobData.end = scheduledEnd; - return await client.post(`/jpm/v2/tenant/${tenantId}/jobs`, jobData); - } - case "list_customers": { - const { page = 1, pageSize = 50, name, email, phone, createdOnOrAfter, active } = args; - const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(Math.min(pageSize, 100))); - if (name) - params.append("name", name); - if (email) - params.append("email", email); - if (phone) - params.append("phone", phone); - if (createdOnOrAfter) - params.append("createdOnOrAfter", createdOnOrAfter); - if (active !== undefined) - params.append("active", String(active)); - return await client.get(`/crm/v2/tenant/${tenantId}/customers?${params}`); - } - case "get_customer": { - const { customer_id } = args; - return await client.get(`/crm/v2/tenant/${tenantId}/customers/${customer_id}`); - } - case "list_invoices": { - const { page = 1, pageSize = 50, status, customerId, jobId, createdOnOrAfter, total_gte } = args; - const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(Math.min(pageSize, 100))); - if (status) - params.append("status", status); - if (customerId) - params.append("customerId", String(customerId)); - if (jobId) - params.append("jobId", String(jobId)); - if (createdOnOrAfter) - params.append("createdOnOrAfter", createdOnOrAfter); - if (total_gte) - params.append("total", `>=${total_gte}`); - return await client.get(`/accounting/v2/tenant/${tenantId}/invoices?${params}`); - } - case "list_technicians": { - const { page = 1, pageSize = 50, active, businessUnitId } = args; - const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(Math.min(pageSize, 100))); - if (active !== undefined) - params.append("active", String(active)); - if (businessUnitId) - params.append("businessUnitId", String(businessUnitId)); - return await client.get(`/dispatch/v2/tenant/${tenantId}/technicians?${params}`); - } - case "list_appointments": { - const { page = 1, pageSize = 50, startsOnOrAfter, startsOnOrBefore, technicianId, jobId } = args; - const params = new URLSearchParams(); - params.append("page", String(page)); - params.append("pageSize", String(Math.min(pageSize, 100))); - if (startsOnOrAfter) - params.append("startsOnOrAfter", startsOnOrAfter); - if (startsOnOrBefore) - params.append("startsOnOrBefore", startsOnOrBefore); - if (technicianId) - params.append("technicianId", String(technicianId)); - if (jobId) - params.append("jobId", String(jobId)); - return await client.get(`/dispatch/v2/tenant/${tenantId}/appointments?${params}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const clientId = process.env.SERVICETITAN_CLIENT_ID; - const clientSecret = process.env.SERVICETITAN_CLIENT_SECRET; - const tenantId = process.env.SERVICETITAN_TENANT_ID; - if (!clientId) { - console.error("Error: SERVICETITAN_CLIENT_ID environment variable required"); - process.exit(1); - } - if (!clientSecret) { - console.error("Error: SERVICETITAN_CLIENT_SECRET environment variable required"); - process.exit(1); - } - if (!tenantId) { - console.error("Error: SERVICETITAN_TENANT_ID environment variable required"); - process.exit(1); - } - const client = new ServiceTitanClient(clientId, clientSecret, tenantId); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/squarespace/dist/index.d.ts b/mcp-diagrams/mcp-servers/squarespace/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/squarespace/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/squarespace/dist/index.js b/mcp-diagrams/mcp-servers/squarespace/dist/index.js deleted file mode 100644 index 6bd6cb6..0000000 --- a/mcp-diagrams/mcp-servers/squarespace/dist/index.js +++ /dev/null @@ -1,257 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "squarespace"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.squarespace.com/1.0"; -// ============================================ -// API CLIENT - Squarespace uses Bearer Token (OAuth2) -// ============================================ -class SquarespaceClient { - apiKey; - baseUrl; - constructor(apiKey) { - this.apiKey = apiKey; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "Content-Type": "application/json", - "User-Agent": "MCP-Squarespace-Server/1.0", - ...options.headers, - }, - }); - if (!response.ok) { - const text = await response.text(); - throw new Error(`Squarespace API error: ${response.status} ${response.statusText} - ${text}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_pages", - description: "List all pages for the website", - inputSchema: { - type: "object", - properties: { - cursor: { type: "string", description: "Pagination cursor" }, - }, - }, - }, - { - name: "get_page", - description: "Get a specific page by ID", - inputSchema: { - type: "object", - properties: { - pageId: { type: "string", description: "Page ID" }, - }, - required: ["pageId"], - }, - }, - { - name: "list_products", - description: "List all products from the commerce store", - inputSchema: { - type: "object", - properties: { - cursor: { type: "string", description: "Pagination cursor" }, - modifiedAfter: { type: "string", description: "Filter by modified date (ISO 8601)" }, - modifiedBefore: { type: "string", description: "Filter by modified date (ISO 8601)" }, - type: { type: "string", description: "Product type filter (PHYSICAL, DIGITAL, SERVICE, GIFT_CARD)" }, - }, - }, - }, - { - name: "get_product", - description: "Get a specific product by ID", - inputSchema: { - type: "object", - properties: { - productId: { type: "string", description: "Product ID" }, - }, - required: ["productId"], - }, - }, - { - name: "list_orders", - description: "List orders from the commerce store", - inputSchema: { - type: "object", - properties: { - cursor: { type: "string", description: "Pagination cursor" }, - modifiedAfter: { type: "string", description: "Filter by modified date (ISO 8601)" }, - modifiedBefore: { type: "string", description: "Filter by modified date (ISO 8601)" }, - fulfillmentStatus: { type: "string", description: "Filter by status (PENDING, FULFILLED, CANCELED)" }, - }, - }, - }, - { - name: "get_order", - description: "Get a specific order by ID", - inputSchema: { - type: "object", - properties: { - orderId: { type: "string", description: "Order ID" }, - }, - required: ["orderId"], - }, - }, - { - name: "list_inventory", - description: "List inventory for all product variants", - inputSchema: { - type: "object", - properties: { - cursor: { type: "string", description: "Pagination cursor" }, - }, - }, - }, - { - name: "update_inventory", - description: "Update inventory quantity for a product variant", - inputSchema: { - type: "object", - properties: { - variantId: { type: "string", description: "Product variant ID" }, - quantity: { type: "number", description: "New quantity to set" }, - quantityDelta: { type: "number", description: "Quantity change (+/-)" }, - isUnlimited: { type: "boolean", description: "Set to unlimited stock" }, - }, - required: ["variantId"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_pages": { - const params = new URLSearchParams(); - if (args.cursor) - params.append("cursor", args.cursor); - const query = params.toString(); - return await client.get(`/commerce/pages${query ? `?${query}` : ""}`); - } - case "get_page": { - return await client.get(`/commerce/pages/${args.pageId}`); - } - case "list_products": { - const params = new URLSearchParams(); - if (args.cursor) - params.append("cursor", args.cursor); - if (args.modifiedAfter) - params.append("modifiedAfter", args.modifiedAfter); - if (args.modifiedBefore) - params.append("modifiedBefore", args.modifiedBefore); - if (args.type) - params.append("type", args.type); - const query = params.toString(); - return await client.get(`/commerce/products${query ? `?${query}` : ""}`); - } - case "get_product": { - return await client.get(`/commerce/products/${args.productId}`); - } - case "list_orders": { - const params = new URLSearchParams(); - if (args.cursor) - params.append("cursor", args.cursor); - if (args.modifiedAfter) - params.append("modifiedAfter", args.modifiedAfter); - if (args.modifiedBefore) - params.append("modifiedBefore", args.modifiedBefore); - if (args.fulfillmentStatus) - params.append("fulfillmentStatus", args.fulfillmentStatus); - const query = params.toString(); - return await client.get(`/commerce/orders${query ? `?${query}` : ""}`); - } - case "get_order": { - return await client.get(`/commerce/orders/${args.orderId}`); - } - case "list_inventory": { - const params = new URLSearchParams(); - if (args.cursor) - params.append("cursor", args.cursor); - const query = params.toString(); - return await client.get(`/commerce/inventory${query ? `?${query}` : ""}`); - } - case "update_inventory": { - const payload = {}; - if (args.quantity !== undefined) - payload.quantity = args.quantity; - if (args.quantityDelta !== undefined) - payload.quantityDelta = args.quantityDelta; - if (args.isUnlimited !== undefined) - payload.isUnlimited = args.isUnlimited; - return await client.post(`/commerce/inventory/${args.variantId}`, payload); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.SQUARESPACE_API_KEY; - if (!apiKey) { - console.error("Error: SQUARESPACE_API_KEY environment variable required"); - process.exit(1); - } - const client = new SquarespaceClient(apiKey); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/toast/dist/index.d.ts b/mcp-diagrams/mcp-servers/toast/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/toast/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/toast/dist/index.js b/mcp-diagrams/mcp-servers/toast/dist/index.js deleted file mode 100644 index ff4cd79..0000000 --- a/mcp-diagrams/mcp-servers/toast/dist/index.js +++ /dev/null @@ -1,372 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// TOAST POS MCP SERVER -// API Docs: https://doc.toasttab.com/doc/devguide/apiOverview.html -// ============================================ -const MCP_NAME = "toast"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://ws-api.toasttab.com"; -// ============================================ -// API CLIENT - OAuth2 Client Credentials Authentication -// ============================================ -class ToastClient { - clientId; - clientSecret; - restaurantGuid; - accessToken = null; - tokenExpiry = 0; - constructor(clientId, clientSecret, restaurantGuid) { - this.clientId = clientId; - this.clientSecret = clientSecret; - this.restaurantGuid = restaurantGuid; - } - async getAccessToken() { - // Return cached token if still valid - if (this.accessToken && Date.now() < this.tokenExpiry - 60000) { - return this.accessToken; - } - // Fetch new token using client credentials - const response = await fetch(`${API_BASE_URL}/authentication/v1/authentication/login`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - clientId: this.clientId, - clientSecret: this.clientSecret, - userAccessType: "TOAST_MACHINE_CLIENT", - }), - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Toast auth error: ${response.status} - ${errorText}`); - } - const data = await response.json(); - this.accessToken = data.token.accessToken; - // Token typically valid for 1 hour - this.tokenExpiry = Date.now() + (data.token.expiresIn || 3600) * 1000; - return this.accessToken; - } - async request(endpoint, options = {}) { - const token = await this.getAccessToken(); - const url = `${API_BASE_URL}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${token}`, - "Toast-Restaurant-External-ID": this.restaurantGuid, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`Toast API error: ${response.status} ${response.statusText} - ${errorText}`); - } - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async get(endpoint, params) { - const queryString = params ? '?' + new URLSearchParams(params).toString() : ''; - return this.request(`${endpoint}${queryString}`, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async patch(endpoint, data) { - return this.request(endpoint, { - method: "PATCH", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - getRestaurantGuid() { - return this.restaurantGuid; - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_orders", - description: "List orders from Toast POS within a time range. Returns order summaries with checks, items, and payment info.", - inputSchema: { - type: "object", - properties: { - start_date: { type: "string", description: "Start date/time in ISO 8601 format (required, e.g., 2024-01-01T00:00:00.000Z)" }, - end_date: { type: "string", description: "End date/time in ISO 8601 format (required)" }, - page_size: { type: "number", description: "Number of orders per page (default 100, max 100)" }, - page_token: { type: "string", description: "Pagination token from previous response" }, - business_date: { type: "string", description: "Filter by business date (YYYYMMDD format)" }, - }, - required: ["start_date", "end_date"], - }, - }, - { - name: "get_order", - description: "Get a specific order by GUID with full details including checks, selections, payments", - inputSchema: { - type: "object", - properties: { - order_guid: { type: "string", description: "Order GUID" }, - }, - required: ["order_guid"], - }, - }, - { - name: "list_menu_items", - description: "List menu items from Toast menus API. Returns items with prices, modifiers, and availability.", - inputSchema: { - type: "object", - properties: { - menu_guid: { type: "string", description: "Specific menu GUID to fetch (optional - fetches all menus if not provided)" }, - include_modifiers: { type: "boolean", description: "Include modifier groups and options (default true)" }, - }, - }, - }, - { - name: "update_menu_item", - description: "Update a menu item's stock status (86'd status) or visibility", - inputSchema: { - type: "object", - properties: { - item_guid: { type: "string", description: "Menu item GUID (required)" }, - quantity: { type: "string", description: "Stock quantity: 'OUT_OF_STOCK', number, or 'UNLIMITED'" }, - status: { type: "string", description: "Item status: IN_STOCK, OUT_OF_STOCK" }, - }, - required: ["item_guid"], - }, - }, - { - name: "list_employees", - description: "List employees from Toast labor API", - inputSchema: { - type: "object", - properties: { - page_size: { type: "number", description: "Number of employees per page (default 100)" }, - page_token: { type: "string", description: "Pagination token from previous response" }, - include_archived: { type: "boolean", description: "Include archived/inactive employees" }, - }, - }, - }, - { - name: "get_labor", - description: "Get labor/time entry data for shifts within a date range", - inputSchema: { - type: "object", - properties: { - start_date: { type: "string", description: "Start date in ISO 8601 format (required)" }, - end_date: { type: "string", description: "End date in ISO 8601 format (required)" }, - employee_guid: { type: "string", description: "Filter by specific employee GUID" }, - page_size: { type: "number", description: "Number of entries per page (default 100)" }, - page_token: { type: "string", description: "Pagination token" }, - }, - required: ["start_date", "end_date"], - }, - }, - { - name: "list_checks", - description: "List checks (tabs) from orders within a time range", - inputSchema: { - type: "object", - properties: { - start_date: { type: "string", description: "Start date/time in ISO 8601 format (required)" }, - end_date: { type: "string", description: "End date/time in ISO 8601 format (required)" }, - page_size: { type: "number", description: "Number of checks per page (default 100)" }, - page_token: { type: "string", description: "Pagination token" }, - check_status: { type: "string", description: "Filter by status: OPEN, CLOSED, VOID" }, - }, - required: ["start_date", "end_date"], - }, - }, - { - name: "void_check", - description: "Void a check (requires proper permissions). This action cannot be undone.", - inputSchema: { - type: "object", - properties: { - order_guid: { type: "string", description: "Order GUID containing the check (required)" }, - check_guid: { type: "string", description: "Check GUID to void (required)" }, - void_reason: { type: "string", description: "Reason for voiding the check" }, - void_business_date: { type: "number", description: "Business date for void (YYYYMMDD format)" }, - }, - required: ["order_guid", "check_guid"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - const restaurantGuid = client.getRestaurantGuid(); - switch (name) { - case "list_orders": { - const params = { - startDate: args.start_date, - endDate: args.end_date, - }; - if (args.page_size) - params.pageSize = String(args.page_size); - if (args.page_token) - params.pageToken = args.page_token; - if (args.business_date) - params.businessDate = args.business_date; - return await client.get(`/orders/v2/orders`, params); - } - case "get_order": { - return await client.get(`/orders/v2/orders/${args.order_guid}`); - } - case "list_menu_items": { - // Get menus with full item details - if (args.menu_guid) { - return await client.get(`/menus/v2/menus/${args.menu_guid}`); - } - // Get all menus - return await client.get(`/menus/v2/menus`); - } - case "update_menu_item": { - // Use stock API to update item availability - const stockData = {}; - if (args.quantity !== undefined) { - stockData.quantity = args.quantity; - } - if (args.status) { - stockData.status = args.status; - } - return await client.post(`/stock/v1/items/${args.item_guid}`, stockData); - } - case "list_employees": { - const params = {}; - if (args.page_size) - params.pageSize = String(args.page_size); - if (args.page_token) - params.pageToken = args.page_token; - if (args.include_archived) - params.includeArchived = String(args.include_archived); - return await client.get(`/labor/v1/employees`, params); - } - case "get_labor": { - const params = { - startDate: args.start_date, - endDate: args.end_date, - }; - if (args.employee_guid) - params.employeeId = args.employee_guid; - if (args.page_size) - params.pageSize = String(args.page_size); - if (args.page_token) - params.pageToken = args.page_token; - return await client.get(`/labor/v1/timeEntries`, params); - } - case "list_checks": { - // Checks are part of orders - fetch orders and extract checks - const params = { - startDate: args.start_date, - endDate: args.end_date, - }; - if (args.page_size) - params.pageSize = String(args.page_size); - if (args.page_token) - params.pageToken = args.page_token; - const ordersResponse = await client.get(`/orders/v2/orders`, params); - // Extract checks from orders - const checks = []; - if (ordersResponse.orders) { - for (const order of ordersResponse.orders) { - if (order.checks) { - for (const check of order.checks) { - // Filter by status if specified - if (args.check_status && check.voidStatus !== args.check_status) { - continue; - } - checks.push({ - ...check, - orderGuid: order.guid, - orderOpenedDate: order.openedDate, - }); - } - } - } - } - return { - checks, - nextPageToken: ordersResponse.nextPageToken, - }; - } - case "void_check": { - const voidData = { - voidReason: args.void_reason || "Voided via API", - }; - if (args.void_business_date) { - voidData.voidBusinessDate = args.void_business_date; - } - // PATCH the check to void it - return await client.patch(`/orders/v2/orders/${args.order_guid}/checks/${args.check_guid}`, { - voidStatus: "VOID", - ...voidData, - }); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const clientId = process.env.TOAST_CLIENT_ID; - const clientSecret = process.env.TOAST_CLIENT_SECRET; - const restaurantGuid = process.env.TOAST_RESTAURANT_GUID; - if (!clientId) { - console.error("Error: TOAST_CLIENT_ID environment variable required"); - process.exit(1); - } - if (!clientSecret) { - console.error("Error: TOAST_CLIENT_SECRET environment variable required"); - process.exit(1); - } - if (!restaurantGuid) { - console.error("Error: TOAST_RESTAURANT_GUID environment variable required"); - process.exit(1); - } - const client = new ToastClient(clientId, clientSecret, restaurantGuid); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/touchbistro/dist/index.d.ts b/mcp-diagrams/mcp-servers/touchbistro/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/touchbistro/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/touchbistro/dist/index.js b/mcp-diagrams/mcp-servers/touchbistro/dist/index.js deleted file mode 100644 index ddb0257..0000000 --- a/mcp-diagrams/mcp-servers/touchbistro/dist/index.js +++ /dev/null @@ -1,328 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "touchbistro"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://cloud.touchbistro.com/api/v1"; -// ============================================ -// API CLIENT -// ============================================ -class TouchBistroClient { - apiKey; - venueId; - baseUrl; - constructor(apiKey, venueId) { - this.apiKey = apiKey; - this.venueId = venueId; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.apiKey}`, - "X-Venue-Id": this.venueId, - "Content-Type": "application/json", - "Accept": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorText = await response.text(); - throw new Error(`TouchBistro API error: ${response.status} ${response.statusText} - ${errorText}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } - // Orders - async listOrders(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.status) - query.append("status", params.status); - if (params.orderType) - query.append("orderType", params.orderType); - if (params.startDate) - query.append("startDate", params.startDate); - if (params.endDate) - query.append("endDate", params.endDate); - return this.get(`/orders?${query.toString()}`); - } - async getOrder(id) { - return this.get(`/orders/${id}`); - } - // Menu Items - async listMenuItems(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.categoryId) - query.append("categoryId", params.categoryId); - if (params.active !== undefined) - query.append("active", params.active.toString()); - return this.get(`/menu/items?${query.toString()}`); - } - // Reservations - async listReservations(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.date) - query.append("date", params.date); - if (params.status) - query.append("status", params.status); - if (params.partySize) - query.append("partySize", params.partySize.toString()); - return this.get(`/reservations?${query.toString()}`); - } - async createReservation(data) { - return this.post("/reservations", data); - } - // Staff - async listStaff(params) { - const query = new URLSearchParams(); - if (params.page) - query.append("page", params.page.toString()); - if (params.pageSize) - query.append("pageSize", params.pageSize.toString()); - if (params.role) - query.append("role", params.role); - if (params.active !== undefined) - query.append("active", params.active.toString()); - return this.get(`/staff?${query.toString()}`); - } - // Reports - async getSalesReport(params) { - const query = new URLSearchParams(); - query.append("startDate", params.startDate); - query.append("endDate", params.endDate); - if (params.groupBy) - query.append("groupBy", params.groupBy); - if (params.includeVoids !== undefined) - query.append("includeVoids", params.includeVoids.toString()); - if (params.includeRefunds !== undefined) - query.append("includeRefunds", params.includeRefunds.toString()); - return this.get(`/reports/sales?${query.toString()}`); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_orders", - description: "List orders from TouchBistro POS. Filter by status, order type, and date range.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination (default: 1)" }, - pageSize: { type: "number", description: "Number of results per page (default: 25, max: 100)" }, - status: { - type: "string", - description: "Filter by order status", - enum: ["open", "closed", "voided", "refunded"] - }, - orderType: { - type: "string", - description: "Filter by order type", - enum: ["dine_in", "takeout", "delivery", "bar"] - }, - startDate: { type: "string", description: "Filter by order date (start) in YYYY-MM-DD format" }, - endDate: { type: "string", description: "Filter by order date (end) in YYYY-MM-DD format" }, - }, - }, - }, - { - name: "get_order", - description: "Get detailed information about a specific order by ID, including all items, modifiers, payments, and discounts", - inputSchema: { - type: "object", - properties: { - id: { type: "string", description: "The order ID" }, - }, - required: ["id"], - }, - }, - { - name: "list_menu_items", - description: "List menu items from TouchBistro. Get all items available for ordering.", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - categoryId: { type: "string", description: "Filter by menu category ID" }, - active: { type: "boolean", description: "Filter by active status (true = available for ordering)" }, - }, - }, - }, - { - name: "list_reservations", - description: "List reservations from TouchBistro", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - date: { type: "string", description: "Filter by reservation date in YYYY-MM-DD format" }, - status: { - type: "string", - description: "Filter by reservation status", - enum: ["pending", "confirmed", "seated", "completed", "cancelled", "no_show"] - }, - partySize: { type: "number", description: "Filter by party size" }, - }, - }, - }, - { - name: "create_reservation", - description: "Create a new reservation in TouchBistro", - inputSchema: { - type: "object", - properties: { - customerName: { type: "string", description: "Customer name (required)" }, - customerPhone: { type: "string", description: "Customer phone number" }, - customerEmail: { type: "string", description: "Customer email address" }, - partySize: { type: "number", description: "Number of guests (required)" }, - date: { type: "string", description: "Reservation date in YYYY-MM-DD format (required)" }, - time: { type: "string", description: "Reservation time in HH:MM format (required)" }, - tableId: { type: "string", description: "Specific table ID to reserve" }, - notes: { type: "string", description: "Special requests or notes" }, - source: { - type: "string", - description: "Reservation source", - enum: ["phone", "walk_in", "online", "third_party"] - }, - }, - required: ["customerName", "partySize", "date", "time"], - }, - }, - { - name: "list_staff", - description: "List staff members from TouchBistro", - inputSchema: { - type: "object", - properties: { - page: { type: "number", description: "Page number for pagination" }, - pageSize: { type: "number", description: "Number of results per page (max: 100)" }, - role: { - type: "string", - description: "Filter by staff role", - enum: ["server", "bartender", "host", "manager", "kitchen", "cashier"] - }, - active: { type: "boolean", description: "Filter by active employment status" }, - }, - }, - }, - { - name: "get_sales_report", - description: "Get sales report data from TouchBistro for analysis and reporting", - inputSchema: { - type: "object", - properties: { - startDate: { type: "string", description: "Report start date in YYYY-MM-DD format (required)" }, - endDate: { type: "string", description: "Report end date in YYYY-MM-DD format (required)" }, - groupBy: { - type: "string", - description: "How to group the report data", - enum: ["day", "week", "month", "category", "item", "server"] - }, - includeVoids: { type: "boolean", description: "Include voided orders in the report" }, - includeRefunds: { type: "boolean", description: "Include refunded orders in the report" }, - }, - required: ["startDate", "endDate"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_orders": - return await client.listOrders(args); - case "get_order": - return await client.getOrder(args.id); - case "list_menu_items": - return await client.listMenuItems(args); - case "list_reservations": - return await client.listReservations(args); - case "create_reservation": - return await client.createReservation(args); - case "list_staff": - return await client.listStaff(args); - case "get_sales_report": - return await client.getSalesReport(args); - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.TOUCHBISTRO_API_KEY; - const venueId = process.env.TOUCHBISTRO_VENUE_ID; - if (!apiKey) { - console.error("Error: TOUCHBISTRO_API_KEY environment variable required"); - process.exit(1); - } - if (!venueId) { - console.error("Error: TOUCHBISTRO_VENUE_ID environment variable required"); - process.exit(1); - } - const client = new TouchBistroClient(apiKey, venueId); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/trello/dist/index.d.ts b/mcp-diagrams/mcp-servers/trello/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/trello/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/trello/dist/index.js b/mcp-diagrams/mcp-servers/trello/dist/index.js deleted file mode 100644 index e6a9e86..0000000 --- a/mcp-diagrams/mcp-servers/trello/dist/index.js +++ /dev/null @@ -1,413 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "trello"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://api.trello.com/1"; -// ============================================ -// API CLIENT - Trello REST API -// ============================================ -class TrelloClient { - apiKey; - token; - baseUrl; - constructor(apiKey, token) { - this.apiKey = apiKey; - this.token = token; - this.baseUrl = API_BASE_URL; - } - addAuth(url) { - const separator = url.includes('?') ? '&' : '?'; - return `${url}${separator}key=${this.apiKey}&token=${this.token}`; - } - async request(endpoint, options = {}) { - const url = this.addAuth(`${this.baseUrl}${endpoint}`); - const response = await fetch(url, { - ...options, - headers: { - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Trello API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - // Handle 200 OK with no content - const text = await response.text(); - if (!text) - return { success: true }; - return JSON.parse(text); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: data ? JSON.stringify(data) : undefined, - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: data ? JSON.stringify(data) : undefined, - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS - Trello API -// ============================================ -const tools = [ - { - name: "list_boards", - description: "List all boards for the authenticated user", - inputSchema: { - type: "object", - properties: { - filter: { - type: "string", - enum: ["all", "closed", "members", "open", "organization", "public", "starred"], - description: "Filter boards by type" - }, - fields: { type: "string", description: "Comma-separated list of fields to return (default: name,url)" }, - }, - }, - }, - { - name: "get_board", - description: "Get a specific board by ID with detailed information", - inputSchema: { - type: "object", - properties: { - board_id: { type: "string", description: "The board ID or shortLink" }, - lists: { type: "string", enum: ["all", "closed", "none", "open"], description: "Include lists on the board" }, - cards: { type: "string", enum: ["all", "closed", "none", "open", "visible"], description: "Include cards on the board" }, - members: { type: "boolean", description: "Include board members" }, - }, - required: ["board_id"], - }, - }, - { - name: "list_lists", - description: "List all lists on a board", - inputSchema: { - type: "object", - properties: { - board_id: { type: "string", description: "The board ID" }, - filter: { type: "string", enum: ["all", "closed", "none", "open"], description: "Filter lists" }, - cards: { type: "string", enum: ["all", "closed", "none", "open"], description: "Include cards in each list" }, - }, - required: ["board_id"], - }, - }, - { - name: "list_cards", - description: "List all cards on a board or in a specific list", - inputSchema: { - type: "object", - properties: { - board_id: { type: "string", description: "The board ID (required if no list_id)" }, - list_id: { type: "string", description: "The list ID (optional, filters to specific list)" }, - filter: { type: "string", enum: ["all", "closed", "none", "open", "visible"], description: "Filter cards" }, - fields: { type: "string", description: "Comma-separated list of fields to return" }, - }, - }, - }, - { - name: "get_card", - description: "Get a specific card by ID with detailed information", - inputSchema: { - type: "object", - properties: { - card_id: { type: "string", description: "The card ID or shortLink" }, - members: { type: "boolean", description: "Include card members" }, - checklists: { type: "string", enum: ["all", "none"], description: "Include checklists" }, - attachments: { type: "boolean", description: "Include attachments" }, - }, - required: ["card_id"], - }, - }, - { - name: "create_card", - description: "Create a new card on a list", - inputSchema: { - type: "object", - properties: { - list_id: { type: "string", description: "The list ID to create the card in" }, - name: { type: "string", description: "Card name/title" }, - desc: { type: "string", description: "Card description (supports Markdown)" }, - pos: { type: "string", description: "Position: 'top', 'bottom', or a positive number" }, - due: { type: "string", description: "Due date (ISO 8601 format or null)" }, - dueComplete: { type: "boolean", description: "Whether the due date is complete" }, - idMembers: { type: "array", items: { type: "string" }, description: "Member IDs to assign" }, - idLabels: { type: "array", items: { type: "string" }, description: "Label IDs to apply" }, - urlSource: { type: "string", description: "URL to attach to the card" }, - }, - required: ["list_id", "name"], - }, - }, - { - name: "update_card", - description: "Update an existing card's properties", - inputSchema: { - type: "object", - properties: { - card_id: { type: "string", description: "The card ID" }, - name: { type: "string", description: "New card name" }, - desc: { type: "string", description: "New description" }, - closed: { type: "boolean", description: "Archive/unarchive the card" }, - due: { type: "string", description: "New due date (ISO 8601 format or null to remove)" }, - dueComplete: { type: "boolean", description: "Mark due date complete/incomplete" }, - pos: { type: "string", description: "New position: 'top', 'bottom', or a positive number" }, - }, - required: ["card_id"], - }, - }, - { - name: "move_card", - description: "Move a card to a different list or board", - inputSchema: { - type: "object", - properties: { - card_id: { type: "string", description: "The card ID to move" }, - list_id: { type: "string", description: "Destination list ID" }, - board_id: { type: "string", description: "Destination board ID (optional, for cross-board moves)" }, - pos: { type: "string", description: "Position in destination list: 'top', 'bottom', or number" }, - }, - required: ["card_id", "list_id"], - }, - }, - { - name: "add_comment", - description: "Add a comment to a card", - inputSchema: { - type: "object", - properties: { - card_id: { type: "string", description: "The card ID" }, - text: { type: "string", description: "Comment text" }, - }, - required: ["card_id", "text"], - }, - }, - { - name: "create_list", - description: "Create a new list on a board", - inputSchema: { - type: "object", - properties: { - board_id: { type: "string", description: "The board ID" }, - name: { type: "string", description: "List name" }, - pos: { type: "string", description: "Position: 'top', 'bottom', or a positive number" }, - }, - required: ["board_id", "name"], - }, - }, - { - name: "archive_card", - description: "Archive (close) a card", - inputSchema: { - type: "object", - properties: { - card_id: { type: "string", description: "The card ID to archive" }, - }, - required: ["card_id"], - }, - }, - { - name: "delete_card", - description: "Permanently delete a card (cannot be undone)", - inputSchema: { - type: "object", - properties: { - card_id: { type: "string", description: "The card ID to delete" }, - }, - required: ["card_id"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_boards": { - const params = new URLSearchParams(); - params.append("filter", args.filter || "open"); - params.append("fields", args.fields || "name,url,shortLink,desc,closed"); - return await client.get(`/members/me/boards?${params.toString()}`); - } - case "get_board": { - const { board_id, lists, cards, members } = args; - const params = new URLSearchParams(); - if (lists) - params.append("lists", lists); - if (cards) - params.append("cards", cards); - if (members) - params.append("members", "true"); - const queryString = params.toString(); - return await client.get(`/boards/${board_id}${queryString ? '?' + queryString : ''}`); - } - case "list_lists": { - const { board_id, filter, cards } = args; - const params = new URLSearchParams(); - if (filter) - params.append("filter", filter); - if (cards) - params.append("cards", cards); - const queryString = params.toString(); - return await client.get(`/boards/${board_id}/lists${queryString ? '?' + queryString : ''}`); - } - case "list_cards": { - const { board_id, list_id, filter, fields } = args; - const params = new URLSearchParams(); - if (filter) - params.append("filter", filter); - if (fields) - params.append("fields", fields); - const queryString = params.toString(); - if (list_id) { - return await client.get(`/lists/${list_id}/cards${queryString ? '?' + queryString : ''}`); - } - else if (board_id) { - return await client.get(`/boards/${board_id}/cards${queryString ? '?' + queryString : ''}`); - } - else { - throw new Error("Either board_id or list_id is required"); - } - } - case "get_card": { - const { card_id, members, checklists, attachments } = args; - const params = new URLSearchParams(); - if (members) - params.append("members", "true"); - if (checklists) - params.append("checklists", checklists); - if (attachments) - params.append("attachments", "true"); - const queryString = params.toString(); - return await client.get(`/cards/${card_id}${queryString ? '?' + queryString : ''}`); - } - case "create_card": { - const { list_id, name, desc, pos, due, dueComplete, idMembers, idLabels, urlSource } = args; - const params = new URLSearchParams(); - params.append("idList", list_id); - params.append("name", name); - if (desc) - params.append("desc", desc); - if (pos) - params.append("pos", pos); - if (due) - params.append("due", due); - if (dueComplete !== undefined) - params.append("dueComplete", String(dueComplete)); - if (idMembers) - params.append("idMembers", idMembers.join(",")); - if (idLabels) - params.append("idLabels", idLabels.join(",")); - if (urlSource) - params.append("urlSource", urlSource); - return await client.post(`/cards?${params.toString()}`); - } - case "update_card": { - const { card_id, name, desc, closed, due, dueComplete, pos } = args; - const params = new URLSearchParams(); - if (name) - params.append("name", name); - if (desc !== undefined) - params.append("desc", desc); - if (closed !== undefined) - params.append("closed", String(closed)); - if (due !== undefined) - params.append("due", due || "null"); - if (dueComplete !== undefined) - params.append("dueComplete", String(dueComplete)); - if (pos) - params.append("pos", pos); - return await client.put(`/cards/${card_id}?${params.toString()}`); - } - case "move_card": { - const { card_id, list_id, board_id, pos } = args; - const params = new URLSearchParams(); - params.append("idList", list_id); - if (board_id) - params.append("idBoard", board_id); - if (pos) - params.append("pos", pos); - return await client.put(`/cards/${card_id}?${params.toString()}`); - } - case "add_comment": { - const { card_id, text } = args; - const params = new URLSearchParams(); - params.append("text", text); - return await client.post(`/cards/${card_id}/actions/comments?${params.toString()}`); - } - case "create_list": { - const { board_id, name, pos } = args; - const params = new URLSearchParams(); - params.append("name", name); - params.append("idBoard", board_id); - if (pos) - params.append("pos", pos); - return await client.post(`/lists?${params.toString()}`); - } - case "archive_card": { - const { card_id } = args; - return await client.put(`/cards/${card_id}?closed=true`); - } - case "delete_card": { - const { card_id } = args; - return await client.delete(`/cards/${card_id}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiKey = process.env.TRELLO_API_KEY; - const token = process.env.TRELLO_TOKEN; - if (!apiKey || !token) { - console.error("Error: Required environment variables:"); - console.error(" TRELLO_API_KEY - Your Trello API key"); - console.error(" TRELLO_TOKEN - Your Trello auth token"); - console.error("\nGet your API key from: https://trello.com/power-ups/admin"); - console.error("Generate a token from: https://trello.com/1/authorize?expiration=never&scope=read,write&response_type=token&name=MCP-Server&key=YOUR_API_KEY"); - process.exit(1); - } - const client = new TrelloClient(apiKey, token); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/wave/dist/index.d.ts b/mcp-diagrams/mcp-servers/wave/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/wave/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/wave/dist/index.js b/mcp-diagrams/mcp-servers/wave/dist/index.js deleted file mode 100644 index c38545e..0000000 --- a/mcp-diagrams/mcp-servers/wave/dist/index.js +++ /dev/null @@ -1,533 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "wave"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://gql.waveapps.com/graphql/public"; -// ============================================ -// GRAPHQL CLIENT -// ============================================ -class WaveClient { - apiToken; - constructor(apiToken) { - this.apiToken = apiToken; - } - async query(query, variables = {}) { - const response = await fetch(API_BASE_URL, { - method: "POST", - headers: { - "Authorization": `Bearer ${this.apiToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ query, variables }), - }); - if (!response.ok) { - throw new Error(`Wave API error: ${response.status} ${response.statusText}`); - } - const result = await response.json(); - if (result.errors) { - throw new Error(`GraphQL error: ${JSON.stringify(result.errors)}`); - } - return result.data; - } -} -// ============================================ -// GRAPHQL QUERIES AND MUTATIONS -// ============================================ -const QUERIES = { - listBusinesses: ` - query ListBusinesses { - businesses(page: 1, pageSize: 100) { - edges { - node { - id - name - isPersonal - currency { - code - } - } - } - } - } - `, - listInvoices: ` - query ListInvoices($businessId: ID!, $page: Int, $pageSize: Int) { - business(id: $businessId) { - invoices(page: $page, pageSize: $pageSize) { - edges { - node { - id - invoiceNumber - invoiceDate - dueDate - status - customer { - id - name - } - amountDue { - value - currency { - code - } - } - amountPaid { - value - currency { - code - } - } - total { - value - currency { - code - } - } - } - } - pageInfo { - currentPage - totalPages - totalCount - } - } - } - } - `, - listCustomers: ` - query ListCustomers($businessId: ID!, $page: Int, $pageSize: Int) { - business(id: $businessId) { - customers(page: $page, pageSize: $pageSize) { - edges { - node { - id - name - email - address { - addressLine1 - addressLine2 - city - provinceCode - postalCode - countryCode - } - currency { - code - } - } - } - pageInfo { - currentPage - totalPages - totalCount - } - } - } - } - `, - listAccounts: ` - query ListAccounts($businessId: ID!, $page: Int, $pageSize: Int) { - business(id: $businessId) { - accounts(page: $page, pageSize: $pageSize) { - edges { - node { - id - name - description - displayId - type { - name - value - } - subtype { - name - value - } - normalBalanceType - isArchived - } - } - pageInfo { - currentPage - totalPages - totalCount - } - } - } - } - `, - listTransactions: ` - query ListTransactions($businessId: ID!, $page: Int, $pageSize: Int) { - business(id: $businessId) { - transactions(page: $page, pageSize: $pageSize) { - edges { - node { - id - date - description - account { - id - name - } - amount { - value - currency { - code - } - } - anchor { - __typename - } - } - } - pageInfo { - currentPage - totalPages - totalCount - } - } - } - } - `, -}; -const MUTATIONS = { - createInvoice: ` - mutation CreateInvoice($input: InvoiceCreateInput!) { - invoiceCreate(input: $input) { - didSucceed - inputErrors { - code - message - path - } - invoice { - id - invoiceNumber - invoiceDate - dueDate - status - } - } - } - `, - createCustomer: ` - mutation CreateCustomer($input: CustomerCreateInput!) { - customerCreate(input: $input) { - didSucceed - inputErrors { - code - message - path - } - customer { - id - name - email - } - } - } - `, - createExpense: ` - mutation CreateExpense($input: MoneyTransactionCreateInput!) { - moneyTransactionCreate(input: $input) { - didSucceed - inputErrors { - code - message - path - } - transaction { - id - } - } - } - `, -}; -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_businesses", - description: "List all businesses in the Wave account", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "list_invoices", - description: "List invoices for a business", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Items per page (default 25)" }, - }, - required: ["businessId"], - }, - }, - { - name: "create_invoice", - description: "Create a new invoice", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - customerId: { type: "string", description: "Customer ID" }, - invoiceDate: { type: "string", description: "Invoice date (YYYY-MM-DD)" }, - dueDate: { type: "string", description: "Due date (YYYY-MM-DD)" }, - items: { - type: "array", - description: "Invoice line items", - items: { - type: "object", - properties: { - productId: { type: "string", description: "Product/Service ID" }, - description: { type: "string", description: "Line item description" }, - quantity: { type: "number", description: "Quantity" }, - unitPrice: { type: "number", description: "Unit price" }, - }, - }, - }, - memo: { type: "string", description: "Invoice memo/notes" }, - }, - required: ["businessId", "customerId", "items"], - }, - }, - { - name: "list_customers", - description: "List customers for a business", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Items per page (default 25)" }, - }, - required: ["businessId"], - }, - }, - { - name: "create_customer", - description: "Create a new customer", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - name: { type: "string", description: "Customer name" }, - email: { type: "string", description: "Customer email" }, - firstName: { type: "string", description: "First name" }, - lastName: { type: "string", description: "Last name" }, - phone: { type: "string", description: "Phone number" }, - addressLine1: { type: "string", description: "Street address line 1" }, - addressLine2: { type: "string", description: "Street address line 2" }, - city: { type: "string", description: "City" }, - provinceCode: { type: "string", description: "State/Province code" }, - postalCode: { type: "string", description: "Postal/ZIP code" }, - countryCode: { type: "string", description: "Country code (e.g., US, CA)" }, - currency: { type: "string", description: "Currency code (e.g., USD, CAD)" }, - }, - required: ["businessId", "name"], - }, - }, - { - name: "list_accounts", - description: "List chart of accounts for a business", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Items per page (default 25)" }, - }, - required: ["businessId"], - }, - }, - { - name: "list_transactions", - description: "List transactions for a business", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - page: { type: "number", description: "Page number (default 1)" }, - pageSize: { type: "number", description: "Items per page (default 25)" }, - }, - required: ["businessId"], - }, - }, - { - name: "create_expense", - description: "Create a new expense/money transaction", - inputSchema: { - type: "object", - properties: { - businessId: { type: "string", description: "Business ID" }, - externalId: { type: "string", description: "External reference ID" }, - date: { type: "string", description: "Transaction date (YYYY-MM-DD)" }, - description: { type: "string", description: "Transaction description" }, - anchor: { - type: "object", - description: "Anchor account details", - properties: { - accountId: { type: "string", description: "Bank/payment account ID" }, - amount: { type: "number", description: "Amount (positive value)" }, - direction: { type: "string", description: "WITHDRAWAL or DEPOSIT" }, - }, - }, - lineItems: { - type: "array", - description: "Expense line items", - items: { - type: "object", - properties: { - accountId: { type: "string", description: "Expense account ID" }, - amount: { type: "number", description: "Amount" }, - description: { type: "string", description: "Line item description" }, - }, - }, - }, - }, - required: ["businessId", "date", "description", "anchor", "lineItems"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_businesses": { - return await client.query(QUERIES.listBusinesses); - } - case "list_invoices": { - const { businessId, page = 1, pageSize = 25 } = args; - return await client.query(QUERIES.listInvoices, { businessId, page, pageSize }); - } - case "create_invoice": { - const { businessId, customerId, invoiceDate, dueDate, items, memo } = args; - const today = new Date().toISOString().split('T')[0]; - const input = { - businessId, - customerId, - invoiceDate: invoiceDate || today, - items: items.map((item) => ({ - productId: item.productId, - description: item.description, - quantity: item.quantity || 1, - unitPrice: item.unitPrice, - })), - }; - if (dueDate) - input.dueDate = dueDate; - if (memo) - input.memo = memo; - return await client.query(MUTATIONS.createInvoice, { input }); - } - case "list_customers": { - const { businessId, page = 1, pageSize = 25 } = args; - return await client.query(QUERIES.listCustomers, { businessId, page, pageSize }); - } - case "create_customer": { - const { businessId, name, email, firstName, lastName, phone, addressLine1, addressLine2, city, provinceCode, postalCode, countryCode, currency } = args; - const input = { businessId, name }; - if (email) - input.email = email; - if (firstName) - input.firstName = firstName; - if (lastName) - input.lastName = lastName; - if (phone) - input.phone = phone; - if (currency) - input.currency = currency; - if (addressLine1) { - input.address = { addressLine1 }; - if (addressLine2) - input.address.addressLine2 = addressLine2; - if (city) - input.address.city = city; - if (provinceCode) - input.address.provinceCode = provinceCode; - if (postalCode) - input.address.postalCode = postalCode; - if (countryCode) - input.address.countryCode = countryCode; - } - return await client.query(MUTATIONS.createCustomer, { input }); - } - case "list_accounts": { - const { businessId, page = 1, pageSize = 25 } = args; - return await client.query(QUERIES.listAccounts, { businessId, page, pageSize }); - } - case "list_transactions": { - const { businessId, page = 1, pageSize = 25 } = args; - return await client.query(QUERIES.listTransactions, { businessId, page, pageSize }); - } - case "create_expense": { - const { businessId, externalId, date, description, anchor, lineItems } = args; - const input = { - businessId, - externalId: externalId || `exp-${Date.now()}`, - date, - description, - anchor: { - accountId: anchor.accountId, - amount: anchor.amount, - direction: anchor.direction || "WITHDRAWAL", - }, - lineItems: lineItems.map((item) => ({ - accountId: item.accountId, - amount: item.amount, - description: item.description, - })), - }; - return await client.query(MUTATIONS.createExpense, { input }); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const apiToken = process.env.WAVE_API_TOKEN; - if (!apiToken) { - console.error("Error: WAVE_API_TOKEN environment variable required"); - console.error("Get your API token at https://developer.waveapps.com"); - process.exit(1); - } - const client = new WaveClient(apiToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/wrike/dist/index.d.ts b/mcp-diagrams/mcp-servers/wrike/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/wrike/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/wrike/dist/index.js b/mcp-diagrams/mcp-servers/wrike/dist/index.js deleted file mode 100644 index 6e56931..0000000 --- a/mcp-diagrams/mcp-servers/wrike/dist/index.js +++ /dev/null @@ -1,327 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "wrike"; -const MCP_VERSION = "1.0.0"; -const API_BASE_URL = "https://www.wrike.com/api/v4"; -// ============================================ -// API CLIENT -// ============================================ -class WrikeClient { - accessToken; - baseUrl; - constructor(accessToken) { - this.accessToken = accessToken; - this.baseUrl = API_BASE_URL; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": `Bearer ${this.accessToken}`, - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const text = await response.text(); - throw new Error(`Wrike API error: ${response.status} ${response.statusText} - ${text}`); - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } - // Task methods - async listTasks(folderId, options) { - let endpoint = folderId ? `/folders/${folderId}/tasks` : "/tasks"; - const params = new URLSearchParams(); - if (options?.status) - params.append("status", options.status); - if (options?.limit) - params.append("pageSize", options.limit.toString()); - if (params.toString()) - endpoint += `?${params.toString()}`; - return this.get(endpoint); - } - async getTask(taskId) { - return this.get(`/tasks/${taskId}`); - } - async createTask(folderId, data) { - return this.post(`/folders/${folderId}/tasks`, data); - } - async updateTask(taskId, data) { - return this.put(`/tasks/${taskId}`, data); - } - // Folder methods - async listFolders(parentFolderId) { - const endpoint = parentFolderId ? `/folders/${parentFolderId}/folders` : "/folders"; - return this.get(endpoint); - } - // Project methods (projects are folders with project=true) - async listProjects() { - return this.get("/folders?project=true"); - } - // Comment methods - async addComment(taskId, text) { - return this.post(`/tasks/${taskId}/comments`, { text }); - } - // User/Contact methods - async listUsers() { - return this.get("/contacts"); - } -} -// ============================================ -// TOOL DEFINITIONS -// ============================================ -const tools = [ - { - name: "list_tasks", - description: "List tasks from Wrike. Can filter by folder and status.", - inputSchema: { - type: "object", - properties: { - folder_id: { type: "string", description: "Optional folder ID to filter tasks" }, - status: { - type: "string", - description: "Filter by status: Active, Completed, Deferred, Cancelled", - enum: ["Active", "Completed", "Deferred", "Cancelled"] - }, - limit: { type: "number", description: "Max tasks to return (default 100)" }, - }, - }, - }, - { - name: "get_task", - description: "Get a specific task by ID from Wrike", - inputSchema: { - type: "object", - properties: { - task_id: { type: "string", description: "The task ID" }, - }, - required: ["task_id"], - }, - }, - { - name: "create_task", - description: "Create a new task in Wrike", - inputSchema: { - type: "object", - properties: { - folder_id: { type: "string", description: "Folder ID to create task in" }, - title: { type: "string", description: "Task title" }, - description: { type: "string", description: "Task description" }, - status: { - type: "string", - description: "Task status", - enum: ["Active", "Completed", "Deferred", "Cancelled"] - }, - importance: { - type: "string", - description: "Task importance", - enum: ["High", "Normal", "Low"] - }, - start_date: { type: "string", description: "Start date (YYYY-MM-DD)" }, - due_date: { type: "string", description: "Due date (YYYY-MM-DD)" }, - responsibles: { - type: "array", - items: { type: "string" }, - description: "Array of user IDs to assign" - }, - }, - required: ["folder_id", "title"], - }, - }, - { - name: "update_task", - description: "Update an existing task in Wrike", - inputSchema: { - type: "object", - properties: { - task_id: { type: "string", description: "Task ID to update" }, - title: { type: "string", description: "New task title" }, - description: { type: "string", description: "New task description" }, - status: { - type: "string", - description: "Task status", - enum: ["Active", "Completed", "Deferred", "Cancelled"] - }, - importance: { - type: "string", - description: "Task importance", - enum: ["High", "Normal", "Low"] - }, - start_date: { type: "string", description: "Start date (YYYY-MM-DD)" }, - due_date: { type: "string", description: "Due date (YYYY-MM-DD)" }, - add_responsibles: { - type: "array", - items: { type: "string" }, - description: "User IDs to add as assignees" - }, - remove_responsibles: { - type: "array", - items: { type: "string" }, - description: "User IDs to remove from assignees" - }, - }, - required: ["task_id"], - }, - }, - { - name: "list_folders", - description: "List folders from Wrike. Can get child folders of a parent.", - inputSchema: { - type: "object", - properties: { - parent_folder_id: { type: "string", description: "Optional parent folder ID" }, - }, - }, - }, - { - name: "list_projects", - description: "List all projects from Wrike", - inputSchema: { - type: "object", - properties: {}, - }, - }, - { - name: "add_comment", - description: "Add a comment to a task in Wrike", - inputSchema: { - type: "object", - properties: { - task_id: { type: "string", description: "Task ID to comment on" }, - text: { type: "string", description: "Comment text (supports markdown)" }, - }, - required: ["task_id", "text"], - }, - }, - { - name: "list_users", - description: "List all users/contacts in Wrike workspace", - inputSchema: { - type: "object", - properties: {}, - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_tasks": { - return await client.listTasks(args.folder_id, { - status: args.status, - limit: args.limit, - }); - } - case "get_task": { - return await client.getTask(args.task_id); - } - case "create_task": { - const dates = {}; - if (args.start_date) - dates.start = args.start_date; - if (args.due_date) - dates.due = args.due_date; - return await client.createTask(args.folder_id, { - title: args.title, - description: args.description, - status: args.status, - importance: args.importance, - dates: Object.keys(dates).length ? dates : undefined, - responsibles: args.responsibles, - }); - } - case "update_task": { - const dates = {}; - if (args.start_date) - dates.start = args.start_date; - if (args.due_date) - dates.due = args.due_date; - return await client.updateTask(args.task_id, { - title: args.title, - description: args.description, - status: args.status, - importance: args.importance, - dates: Object.keys(dates).length ? dates : undefined, - addResponsibles: args.add_responsibles, - removeResponsibles: args.remove_responsibles, - }); - } - case "list_folders": { - return await client.listFolders(args.parent_folder_id); - } - case "list_projects": { - return await client.listProjects(); - } - case "add_comment": { - return await client.addComment(args.task_id, args.text); - } - case "list_users": { - return await client.listUsers(); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const accessToken = process.env.WRIKE_ACCESS_TOKEN; - if (!accessToken) { - console.error("Error: WRIKE_ACCESS_TOKEN environment variable required"); - process.exit(1); - } - const client = new WrikeClient(accessToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - // List available tools - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - // Handle tool calls - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - // Start server - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/mcp-diagrams/mcp-servers/zendesk/dist/index.d.ts b/mcp-diagrams/mcp-servers/zendesk/dist/index.d.ts deleted file mode 100644 index b798801..0000000 --- a/mcp-diagrams/mcp-servers/zendesk/dist/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -export {}; diff --git a/mcp-diagrams/mcp-servers/zendesk/dist/index.js b/mcp-diagrams/mcp-servers/zendesk/dist/index.js deleted file mode 100644 index bfde437..0000000 --- a/mcp-diagrams/mcp-servers/zendesk/dist/index.js +++ /dev/null @@ -1,338 +0,0 @@ -#!/usr/bin/env node -import { Server } from "@modelcontextprotocol/sdk/server/index.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; -// ============================================ -// CONFIGURATION -// ============================================ -const MCP_NAME = "zendesk"; -const MCP_VERSION = "1.0.0"; -// ============================================ -// API CLIENT - Zendesk API v2 -// ============================================ -class ZendeskClient { - email; - apiToken; - subdomain; - baseUrl; - constructor(subdomain, email, apiToken) { - this.subdomain = subdomain; - this.email = email; - this.apiToken = apiToken; - this.baseUrl = `https://${subdomain}.zendesk.com/api/v2`; - } - getAuthHeader() { - // Zendesk uses email/token:api_token for API token auth - const credentials = Buffer.from(`${this.email}/token:${this.apiToken}`).toString('base64'); - return `Basic ${credentials}`; - } - async request(endpoint, options = {}) { - const url = `${this.baseUrl}${endpoint}`; - const response = await fetch(url, { - ...options, - headers: { - "Authorization": this.getAuthHeader(), - "Content-Type": "application/json", - ...options.headers, - }, - }); - if (!response.ok) { - const errorBody = await response.text(); - throw new Error(`Zendesk API error: ${response.status} ${response.statusText} - ${errorBody}`); - } - // Handle 204 No Content responses - if (response.status === 204) { - return { success: true }; - } - return response.json(); - } - async get(endpoint) { - return this.request(endpoint, { method: "GET" }); - } - async post(endpoint, data) { - return this.request(endpoint, { - method: "POST", - body: JSON.stringify(data), - }); - } - async put(endpoint, data) { - return this.request(endpoint, { - method: "PUT", - body: JSON.stringify(data), - }); - } - async delete(endpoint) { - return this.request(endpoint, { method: "DELETE" }); - } -} -// ============================================ -// TOOL DEFINITIONS - Zendesk Support API -// ============================================ -const tools = [ - { - name: "list_tickets", - description: "List tickets. Can filter by status, requester, or other criteria.", - inputSchema: { - type: "object", - properties: { - status: { - type: "string", - enum: ["new", "open", "pending", "hold", "solved", "closed"], - description: "Filter by ticket status" - }, - sort_by: { type: "string", description: "Sort field (created_at, updated_at, priority, status, ticket_type)" }, - sort_order: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Results per page (max 100)" }, - }, - }, - }, - { - name: "get_ticket", - description: "Get a specific ticket by ID with all its details", - inputSchema: { - type: "object", - properties: { - ticket_id: { type: "number", description: "The ticket ID" }, - }, - required: ["ticket_id"], - }, - }, - { - name: "create_ticket", - description: "Create a new support ticket", - inputSchema: { - type: "object", - properties: { - subject: { type: "string", description: "Ticket subject/title" }, - description: { type: "string", description: "Initial ticket description/comment" }, - requester_email: { type: "string", description: "Email of the requester" }, - requester_name: { type: "string", description: "Name of the requester" }, - priority: { type: "string", enum: ["urgent", "high", "normal", "low"], description: "Ticket priority" }, - type: { type: "string", enum: ["problem", "incident", "question", "task"], description: "Ticket type" }, - tags: { type: "array", items: { type: "string" }, description: "Tags to apply" }, - assignee_id: { type: "number", description: "ID of agent to assign ticket to" }, - group_id: { type: "number", description: "ID of group to assign ticket to" }, - }, - required: ["subject", "description"], - }, - }, - { - name: "update_ticket", - description: "Update an existing ticket's properties", - inputSchema: { - type: "object", - properties: { - ticket_id: { type: "number", description: "The ticket ID to update" }, - status: { type: "string", enum: ["new", "open", "pending", "hold", "solved", "closed"], description: "New status" }, - priority: { type: "string", enum: ["urgent", "high", "normal", "low"], description: "New priority" }, - type: { type: "string", enum: ["problem", "incident", "question", "task"], description: "Ticket type" }, - subject: { type: "string", description: "New subject" }, - assignee_id: { type: "number", description: "ID of agent to assign to" }, - group_id: { type: "number", description: "ID of group to assign to" }, - tags: { type: "array", items: { type: "string" }, description: "Tags to set (replaces existing)" }, - additional_tags: { type: "array", items: { type: "string" }, description: "Tags to add" }, - remove_tags: { type: "array", items: { type: "string" }, description: "Tags to remove" }, - }, - required: ["ticket_id"], - }, - }, - { - name: "add_comment", - description: "Add a comment to an existing ticket", - inputSchema: { - type: "object", - properties: { - ticket_id: { type: "number", description: "The ticket ID" }, - body: { type: "string", description: "Comment text (supports HTML)" }, - public: { type: "boolean", description: "Whether comment is public (visible to requester) or internal note" }, - author_id: { type: "number", description: "User ID of the comment author (optional)" }, - }, - required: ["ticket_id", "body"], - }, - }, - { - name: "list_users", - description: "List users in the Zendesk account", - inputSchema: { - type: "object", - properties: { - role: { type: "string", enum: ["end-user", "agent", "admin"], description: "Filter by user role" }, - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Results per page (max 100)" }, - }, - }, - }, - { - name: "search_tickets", - description: "Search tickets using Zendesk search syntax", - inputSchema: { - type: "object", - properties: { - query: { - type: "string", - description: "Search query. Examples: 'status:open', 'priority:urgent', 'assignee:me', 'subject:billing'" - }, - sort_by: { type: "string", description: "Sort field (created_at, updated_at, priority, status, ticket_type)" }, - sort_order: { type: "string", enum: ["asc", "desc"], description: "Sort order" }, - page: { type: "number", description: "Page number for pagination" }, - per_page: { type: "number", description: "Results per page (max 100)" }, - }, - required: ["query"], - }, - }, -]; -// ============================================ -// TOOL HANDLERS -// ============================================ -async function handleTool(client, name, args) { - switch (name) { - case "list_tickets": { - const params = new URLSearchParams(); - if (args.sort_by) - params.append("sort_by", args.sort_by); - if (args.sort_order) - params.append("sort_order", args.sort_order); - if (args.page) - params.append("page", String(args.page)); - if (args.per_page) - params.append("per_page", String(args.per_page)); - const queryString = params.toString(); - const result = await client.get(`/tickets.json${queryString ? '?' + queryString : ''}`); - // Filter by status client-side if specified (Zendesk list doesn't support status filter directly) - if (args.status && result.tickets) { - result.tickets = result.tickets.filter((t) => t.status === args.status); - } - return result; - } - case "get_ticket": { - const { ticket_id } = args; - return await client.get(`/tickets/${ticket_id}.json`); - } - case "create_ticket": { - const { subject, description, requester_email, requester_name, priority, type, tags, assignee_id, group_id } = args; - const ticket = { - subject, - comment: { body: description }, - }; - if (requester_email) { - ticket.requester = { email: requester_email }; - if (requester_name) - ticket.requester.name = requester_name; - } - if (priority) - ticket.priority = priority; - if (type) - ticket.type = type; - if (tags) - ticket.tags = tags; - if (assignee_id) - ticket.assignee_id = assignee_id; - if (group_id) - ticket.group_id = group_id; - return await client.post("/tickets.json", { ticket }); - } - case "update_ticket": { - const { ticket_id, status, priority, type, subject, assignee_id, group_id, tags, additional_tags, remove_tags } = args; - const ticket = {}; - if (status) - ticket.status = status; - if (priority) - ticket.priority = priority; - if (type) - ticket.type = type; - if (subject) - ticket.subject = subject; - if (assignee_id) - ticket.assignee_id = assignee_id; - if (group_id) - ticket.group_id = group_id; - if (tags) - ticket.tags = tags; - if (additional_tags) - ticket.additional_tags = additional_tags; - if (remove_tags) - ticket.remove_tags = remove_tags; - return await client.put(`/tickets/${ticket_id}.json`, { ticket }); - } - case "add_comment": { - const { ticket_id, body, public: isPublic = true, author_id } = args; - const comment = { - body, - public: isPublic, - }; - if (author_id) - comment.author_id = author_id; - return await client.put(`/tickets/${ticket_id}.json`, { - ticket: { comment } - }); - } - case "list_users": { - const params = new URLSearchParams(); - if (args.role) - params.append("role", args.role); - if (args.page) - params.append("page", String(args.page)); - if (args.per_page) - params.append("per_page", String(args.per_page)); - const queryString = params.toString(); - return await client.get(`/users.json${queryString ? '?' + queryString : ''}`); - } - case "search_tickets": { - const { query, sort_by, sort_order, page, per_page } = args; - const params = new URLSearchParams({ query: `type:ticket ${query}` }); - if (sort_by) - params.append("sort_by", sort_by); - if (sort_order) - params.append("sort_order", sort_order); - if (page) - params.append("page", String(page)); - if (per_page) - params.append("per_page", String(per_page)); - return await client.get(`/search.json?${params.toString()}`); - } - default: - throw new Error(`Unknown tool: ${name}`); - } -} -// ============================================ -// SERVER SETUP -// ============================================ -async function main() { - const subdomain = process.env.ZENDESK_SUBDOMAIN; - const email = process.env.ZENDESK_EMAIL; - const apiToken = process.env.ZENDESK_API_TOKEN; - if (!subdomain || !email || !apiToken) { - console.error("Error: Required environment variables:"); - console.error(" ZENDESK_SUBDOMAIN - Your Zendesk subdomain (e.g., 'mycompany' for mycompany.zendesk.com)"); - console.error(" ZENDESK_EMAIL - Your Zendesk agent email"); - console.error(" ZENDESK_API_TOKEN - Your Zendesk API token"); - console.error("\nGet your API token from: Admin Center > Apps and integrations > APIs > Zendesk API"); - process.exit(1); - } - const client = new ZendeskClient(subdomain, email, apiToken); - const server = new Server({ name: `${MCP_NAME}-mcp`, version: MCP_VERSION }, { capabilities: { tools: {} } }); - server.setRequestHandler(ListToolsRequestSchema, async () => ({ - tools, - })); - server.setRequestHandler(CallToolRequestSchema, async (request) => { - const { name, arguments: args } = request.params; - try { - const result = await handleTool(client, name, args || {}); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }], - }; - } - catch (error) { - const message = error instanceof Error ? error.message : String(error); - return { - content: [{ type: "text", text: `Error: ${message}` }], - isError: true, - }; - } - }); - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error(`${MCP_NAME} MCP server running on stdio`); -} -main().catch(console.error); diff --git a/reonomy-auth.json b/reonomy-auth.json deleted file mode 100644 index 0e6ba1f..0000000 --- a/reonomy-auth.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "cookies": [ - { - "name": "_csrf", - "value": "6jys7hEbP7ZvJ9xumYoMa5mH", - "domain": "auth.reonomy.com", - "path": "/usernamepassword/login", - "expires": 1770288255.301182, - "httpOnly": true, - "secure": true, - "sameSite": "Lax" - }, - { - "name": "session", - "value": "092da57b-8505-41b5-b444-9544cee051a3", - "domain": "app.reonomy.com", - "path": "/", - "expires": 1772102668.259811, - "httpOnly": true, - "secure": false, - "sameSite": "Lax" - }, - { - "name": "visid_incap_2934206", - "value": "hGnnWIAJT9C6z599eILcQHdFd2kAAAAAQUIPAAAAAAAQjKa9/zwLhqJ20EA9MJkC", - "domain": ".reonomy.com", - "path": "/", - "expires": 1800955975.508283, - "httpOnly": true, - "secure": false, - "sameSite": "Lax" - }, - { - "name": "nlbi_2934206", - "value": "SBh6U50ej1K0ap6KzbmGDgAAAAChcquNLQbeFePzq1How3JY", - "domain": ".reonomy.com", - "path": "/", - "expires": -1, - "httpOnly": true, - "secure": false, - "sameSite": "Lax" - }, - { - "name": "incap_ses_7222_2934206", - "value": "WLKaQxwO50+O/nd/SrM5ZHhFd2kAAAAAaLG8W1BVx506jU6zpH9QEw==", - "domain": ".reonomy.com", - "path": "/", - "expires": -1, - "httpOnly": false, - "secure": false, - "sameSite": "Lax" - }, - { - "name": "did", - "value": "s%3Av0%3A0a8b7115-0048-4409-8b7b-4bd767bc976a.Zu9u2z0d9taFc00P6UkrCZJRHiA5i23IDlQQs1ZeA6w", - "domain": "auth.reonomy.com", - "path": "/", - "expires": 1800981848.857363, - "httpOnly": true, - "secure": true, - "sameSite": "None" - }, - { - "name": "did_compat", - "value": "s%3Av0%3A0a8b7115-0048-4409-8b7b-4bd767bc976a.Zu9u2z0d9taFc00P6UkrCZJRHiA5i23IDlQQs1ZeA6w", - "domain": "auth.reonomy.com", - "path": "/", - "expires": 1800981848.85744, - "httpOnly": true, - "secure": true, - "sameSite": "Lax" - }, - { - "name": "_cfuvid", - "value": "p83RVhJpe5zNfhLqwr.aQIU_VF3XT8ELmqH9L.hC.AI-1769424248845-0.0.1.1-604800000", - "domain": ".auth.reonomy.com", - "path": "/", - "expires": -1, - "httpOnly": true, - "secure": true, - "sameSite": "None" - }, - { - "name": "auth0", - "value": "s%3AWGDFYzynMlIv7-5Kv6NKz-rXUk_PGr4R.RDL9WQo7wn41jSWskmvu21yF6EJq6JZu8PntXVKYlEY", - "domain": "auth.reonomy.com", - "path": "/", - "expires": 1769683467.194398, - "httpOnly": true, - "secure": true, - "sameSite": "None" - }, - { - "name": "auth0_compat", - "value": "s%3AWGDFYzynMlIv7-5Kv6NKz-rXUk_PGr4R.RDL9WQo7wn41jSWskmvu21yF6EJq6JZu8PntXVKYlEY", - "domain": "auth.reonomy.com", - "path": "/", - "expires": 1769683467.194518, - "httpOnly": true, - "secure": true, - "sameSite": "Lax" - }, - { - "name": "_legacy_auth0.is.authenticated", - "value": "true", - "domain": "app.reonomy.com", - "path": "/", - "expires": 1769510668, - "httpOnly": false, - "secure": true, - "sameSite": "Lax" - }, - { - "name": "auth0.is.authenticated", - "value": "true", - "domain": "app.reonomy.com", - "path": "/", - "expires": 1769510668, - "httpOnly": false, - "secure": true, - "sameSite": "None" - }, - { - "name": "_dd_s", - "value": "logs=1&id=fe9aa087-78af-4a1a-b143-48dc2a44b187&created=1769424268806&expire=1769425168806", - "domain": "app.reonomy.com", - "path": "/", - "expires": 1769425168, - "httpOnly": false, - "secure": false, - "sameSite": "Strict" - }, - { - "name": "ajs_anonymous_id", - "value": "86738591-aeb8-4319-b9ba-8ee8d28bc4df", - "domain": ".reonomy.com", - "path": "/", - "expires": 1800960269, - "httpOnly": false, - "secure": false, - "sameSite": "Lax" - }, - { - "name": "ajs_user_id", - "value": "8243a0ea-0050-45f4-b71e-c59fd20b96a3", - "domain": ".reonomy.com", - "path": "/", - "expires": 1800960269, - "httpOnly": false, - "secure": false, - "sameSite": "Lax" - } - ], - "origins": [ - { - "origin": "https://app.reonomy.com", - "localStorage": [ - { - "name": "_pendo_accountId.e1d67073-c553-48ac-506e-9dad9bfa6af0", - "value": "8243a0ea-0050-45f4-b71e-c59fd20b96a3" - }, - { - "name": "_pendo_visitorId.e1d67073-c553-48ac-506e-9dad9bfa6af0", - "value": "{\"ttl\":1778064268803,\"value\":\"8243a0ea-0050-45f4-b71e-c59fd20b96a3\"}" - }, - { - "name": "@@auth0spajs@@::UTqjIZf5jqE0RoRCJPD216aT9CWZrq2C::https://app.reonomy.com/v2/::openid profile email", - "value": "{\"body\":{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJUWkdOamN3TlVVMFJFTTJORGt6UlRNd1JVSTVSVGs1TlVZeE56UkRNVUUzUlVNd09UTkVOdyJ9.eyJpc3MiOiJodHRwczovL2F1dGgucmVvbm9teS5jb20vIiwic3ViIjoiYXV0aDB8Y2M1YzZhNDctZjU0MS00OWFhLWI0OTItNTkyZmRlN2I4MDAwIiwiYXVkIjpbImh0dHBzOi8vYXBwLnJlb25vbXkuY29tL3YyLyIsImh0dHBzOi8vcmVvbm9teS1wcmQuYXV0aDAuY29tL3VzZXJpbmZvIl0sImlhdCI6MTc2OTQyNDI2OCwiZXhwIjoxNzY5NTEwNjY4LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiYXpwIjoiVVRxaklaZjVqcUUwUm9SQ0pQRDIxNmFUOUNXWnJxMkMifQ.Jj4FAh2o6FJG1zCnh3f9ObEnpbHUQDD5_n2Fh4HwyPAq38o4pHyhYdT9EJGSh37S2mDyJYLRnaf8DXkfncd5j-qnBnGvD4WN1iy9lL7Nf_JSkhfx2CKDewgjurEJXT8K8s_sHuE98wRNXhVUfAofuRrMtmq5LeKOtO0XOAA7xUolluWvUFgtn-M7rooByzpo76Dpg0LJyOOVOBoELxInajREpqQB_C6_CUOam0dNI9SLMmRimRfWSuupGz1ZcQXMNrO0KLdKnspXBjz5l-5ujTGMbxlOQ2r73VuzCFTFrWeeC66UsC-Hau5kflUgRja18NvZOGhMpWmd6t0aSxBJ1A\",\"id_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJUWkdOamN3TlVVMFJFTTJORGt6UlRNd1JVSTVSVGs1TlVZeE56UkRNVUUzUlVNd09UTkVOdyJ9.eyJnaXZlbl9uYW1lIjoiSGVucnkiLCJmYW1pbHlfbmFtZSI6IjkwODIxNjY1MzIiLCJuaWNrbmFtZSI6ImhlbnJ5IiwibmFtZSI6ImhlbnJ5QHJlYWxlc3RhdGVlbmhhbmNlZC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvNzMwYTkzZDcwZGMxYzUyMDgyNjhhNGYzODNjNWI1ZmY_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZoZS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyNi0wMS0yNlQxMDo0NDoyMi42NDNaIiwiZW1haWwiOiJoZW5yeUByZWFsZXN0YXRlZW5oYW5jZWQuY29tIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLnJlb25vbXkuY29tLyIsImF1ZCI6IlVUcWpJWmY1anFFMFJvUkNKUEQyMTZhVDlDV1pycTJDIiwic3ViIjoiYXV0aDB8Y2M1YzZhNDctZjU0MS00OWFhLWI0OTItNTkyZmRlN2I4MDAwIiwiaWF0IjoxNzY5NDI0MjY4LCJleHAiOjE3Njk0NjAyNjgsInNpZCI6ImlvRmZCTmVZeWxRWThpTjl0a3FpMGVkQjNSYkhsRldTIiwibm9uY2UiOiJhMFoxZFVKSGQxbFphREpXU2pCUE16aFRaREpWTTJKQ1VIVlBOMU4zVFZWRmFqTXRTSEZzYzNKVmF3PT0ifQ.TMRkNOn8hE3LyI0MmOVs8kfNw3s2uj6fmAB9CmfvYobBluZM-i6RVnMI11qvWtYWaPbzsQ04Mzipr6dWDup9JaJ5_RXaBHG878D7yQi0qAQBOSuK6ZQE_7WTEdP7IDRu-NvfJtbjD6PJmxVrpx713_CAesWNoabJkd4WjOEBIYU-4Xy_p9dkBTdAjhvzcrW7I79Morkw1j_vGc-sr0VMehiXf4PwAxyHR_1Bv7Ythy9ki3YNx-EpfGx8KjPvXndgt_TbC73ZegwUGSsY50hEA3rPTnnfb9QsTGdViy16LaRdov-hXF4ZF8SZRw8TEKAWRJ_my8kicjhLOEOpCDOyRw\",\"scope\":\"openid profile email\",\"expires_in\":86400,\"token_type\":\"Bearer\",\"decodedToken\":{\"encoded\":{\"header\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJUWkdOamN3TlVVMFJFTTJORGt6UlRNd1JVSTVSVGs1TlVZeE56UkRNVUUzUlVNd09UTkVOdyJ9\",\"payload\":\"eyJnaXZlbl9uYW1lIjoiSGVucnkiLCJmYW1pbHlfbmFtZSI6IjkwODIxNjY1MzIiLCJuaWNrbmFtZSI6ImhlbnJ5IiwibmFtZSI6ImhlbnJ5QHJlYWxlc3RhdGVlbmhhbmNlZC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvNzMwYTkzZDcwZGMxYzUyMDgyNjhhNGYzODNjNWI1ZmY_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZoZS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyNi0wMS0yNlQxMDo0NDoyMi42NDNaIiwiZW1haWwiOiJoZW5yeUByZWFsZXN0YXRlZW5oYW5jZWQuY29tIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLnJlb25vbXkuY29tLyIsImF1ZCI6IlVUcWpJWmY1anFFMFJvUkNKUEQyMTZhVDlDV1pycTJDIiwic3ViIjoiYXV0aDB8Y2M1YzZhNDctZjU0MS00OWFhLWI0OTItNTkyZmRlN2I4MDAwIiwiaWF0IjoxNzY5NDI0MjY4LCJleHAiOjE3Njk0NjAyNjgsInNpZCI6ImlvRmZCTmVZeWxRWThpTjl0a3FpMGVkQjNSYkhsRldTIiwibm9uY2UiOiJhMFoxZFVKSGQxbFphREpXU2pCUE16aFRaREpWTTJKQ1VIVlBOMU4zVFZWRmFqTXRTSEZzYzNKVmF3PT0ifQ\",\"signature\":\"TMRkNOn8hE3LyI0MmOVs8kfNw3s2uj6fmAB9CmfvYobBluZM-i6RVnMI11qvWtYWaPbzsQ04Mzipr6dWDup9JaJ5_RXaBHG878D7yQi0qAQBOSuK6ZQE_7WTEdP7IDRu-NvfJtbjD6PJmxVrpx713_CAesWNoabJkd4WjOEBIYU-4Xy_p9dkBTdAjhvzcrW7I79Morkw1j_vGc-sr0VMehiXf4PwAxyHR_1Bv7Ythy9ki3YNx-EpfGx8KjPvXndgt_TbC73ZegwUGSsY50hEA3rPTnnfb9QsTGdViy16LaRdov-hXF4ZF8SZRw8TEKAWRJ_my8kicjhLOEOpCDOyRw\"},\"header\":{\"alg\":\"RS256\",\"typ\":\"JWT\",\"kid\":\"RTZGNjcwNUU0REM2NDkzRTMwRUI5RTk5NUYxNzRDMUE3RUMwOTNENw\"},\"claims\":{\"__raw\":\"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJUWkdOamN3TlVVMFJFTTJORGt6UlRNd1JVSTVSVGs1TlVZeE56UkRNVUUzUlVNd09UTkVOdyJ9.eyJnaXZlbl9uYW1lIjoiSGVucnkiLCJmYW1pbHlfbmFtZSI6IjkwODIxNjY1MzIiLCJuaWNrbmFtZSI6ImhlbnJ5IiwibmFtZSI6ImhlbnJ5QHJlYWxlc3RhdGVlbmhhbmNlZC5jb20iLCJwaWN0dXJlIjoiaHR0cHM6Ly9zLmdyYXZhdGFyLmNvbS9hdmF0YXIvNzMwYTkzZDcwZGMxYzUyMDgyNjhhNGYzODNjNWI1ZmY_cz00ODAmcj1wZyZkPWh0dHBzJTNBJTJGJTJGY2RuLmF1dGgwLmNvbSUyRmF2YXRhcnMlMkZoZS5wbmciLCJ1cGRhdGVkX2F0IjoiMjAyNi0wMS0yNlQxMDo0NDoyMi42NDNaIiwiZW1haWwiOiJoZW5yeUByZWFsZXN0YXRlZW5oYW5jZWQuY29tIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLnJlb25vbXkuY29tLyIsImF1ZCI6IlVUcWpJWmY1anFFMFJvUkNKUEQyMTZhVDlDV1pycTJDIiwic3ViIjoiYXV0aDB8Y2M1YzZhNDctZjU0MS00OWFhLWI0OTItNTkyZmRlN2I4MDAwIiwiaWF0IjoxNzY5NDI0MjY4LCJleHAiOjE3Njk0NjAyNjgsInNpZCI6ImlvRmZCTmVZeWxRWThpTjl0a3FpMGVkQjNSYkhsRldTIiwibm9uY2UiOiJhMFoxZFVKSGQxbFphREpXU2pCUE16aFRaREpWTTJKQ1VIVlBOMU4zVFZWRmFqTXRTSEZzYzNKVmF3PT0ifQ.TMRkNOn8hE3LyI0MmOVs8kfNw3s2uj6fmAB9CmfvYobBluZM-i6RVnMI11qvWtYWaPbzsQ04Mzipr6dWDup9JaJ5_RXaBHG878D7yQi0qAQBOSuK6ZQE_7WTEdP7IDRu-NvfJtbjD6PJmxVrpx713_CAesWNoabJkd4WjOEBIYU-4Xy_p9dkBTdAjhvzcrW7I79Morkw1j_vGc-sr0VMehiXf4PwAxyHR_1Bv7Ythy9ki3YNx-EpfGx8KjPvXndgt_TbC73ZegwUGSsY50hEA3rPTnnfb9QsTGdViy16LaRdov-hXF4ZF8SZRw8TEKAWRJ_my8kicjhLOEOpCDOyRw\",\"given_name\":\"Henry\",\"family_name\":\"9082166532\",\"nickname\":\"henry\",\"name\":\"henry@realestateenhanced.com\",\"picture\":\"https://s.gravatar.com/avatar/730a93d70dc1c5208268a4f383c5b5ff?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fhe.png\",\"updated_at\":\"2026-01-26T10:44:22.643Z\",\"email\":\"henry@realestateenhanced.com\",\"iss\":\"https://auth.reonomy.com/\",\"aud\":\"UTqjIZf5jqE0RoRCJPD216aT9CWZrq2C\",\"sub\":\"auth0|cc5c6a47-f541-49aa-b492-592fde7b8000\",\"iat\":1769424268,\"exp\":1769460268,\"sid\":\"ioFfBNeYylQY8iN9tkqi0edB3RbHlFWS\",\"nonce\":\"a0Z1dUJHd1lZaDJWSjBPMzhTZDJVM2JCUHVPN1N3TVVFajMtSHFsc3JVaw==\"},\"user\":{\"given_name\":\"Henry\",\"family_name\":\"9082166532\",\"nickname\":\"henry\",\"name\":\"henry@realestateenhanced.com\",\"picture\":\"https://s.gravatar.com/avatar/730a93d70dc1c5208268a4f383c5b5ff?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fhe.png\",\"updated_at\":\"2026-01-26T10:44:22.643Z\",\"email\":\"henry@realestateenhanced.com\",\"sub\":\"auth0|cc5c6a47-f541-49aa-b492-592fde7b8000\"}},\"audience\":\"https://app.reonomy.com/v2/\",\"client_id\":\"UTqjIZf5jqE0RoRCJPD216aT9CWZrq2C\"},\"expiresAt\":1769460268}" - }, - { - "name": "_pendo_meta.e1d67073-c553-48ac-506e-9dad9bfa6af0", - "value": "2730005740" - }, - { - "name": "_pendo_guides_blocked.e1d67073-c553-48ac-506e-9dad9bfa6af0", - "value": "{\"ttl\":1769426069089,\"value\":\"1\"}" - }, - { - "name": "ajs_anonymous_id", - "value": "\"86738591-aeb8-4319-b9ba-8ee8d28bc4df\"" - }, - { - "name": "ajs_user_id", - "value": "\"8243a0ea-0050-45f4-b71e-c59fd20b96a3\"" - }, - { - "name": "ajs_user_traits", - "value": "{\"firstName\":\"Henry\",\"lastName\":\"9082166532\",\"email\":\"henry@realestateenhanced.com\",\"isSegmented\":true}" - } - ] - } - ] -} \ No newline at end of file diff --git a/scripts/__pycache__/captcha_audio.cpython-314.pyc b/scripts/__pycache__/captcha_audio.cpython-314.pyc deleted file mode 100644 index 10d0177..0000000 Binary files a/scripts/__pycache__/captcha_audio.cpython-314.pyc and /dev/null differ diff --git a/textnow-integration/dist/src/api.d.ts b/textnow-integration/dist/src/api.d.ts deleted file mode 100644 index 437f518..0000000 --- a/textnow-integration/dist/src/api.d.ts +++ /dev/null @@ -1,140 +0,0 @@ -/** - * TextNow REST API Client - * Base URL: https://www.textnow.com - */ -import { TextNowAuth } from './auth.js'; -export declare class TextNowAPIError extends Error { - statusCode: number; - statusText: string; - body: unknown; - endpoint: string; - constructor(statusCode: number, statusText: string, body: unknown, endpoint: string); -} -export interface Message { - id: string; - message_direction: 1 | 2; - message_type: number; - message: string; - contact_value: string; - contact_type: number; - read: boolean; - date: string; - conversation_id: string; - media_type?: number; - message_media_url?: string; -} -export interface Conversation { - contact_value: string; - contact_name?: string; - contact_type: number; - messages: Message[]; - unread_count: number; - last_message_time: string; -} -export interface SendMessageRequest { - contact_value: string; - message: string; -} -export interface SendMessageResponse { - id: string; - message_direction: number; - message: string; - date: string; -} -export interface SendMediaRequest { - contact_value: string; - filePath?: string; - buffer?: Buffer; - filename?: string; - contentType?: string; - mediaType?: 'image' | 'audio'; -} -export interface AttachmentUrlResponse { - result: string; -} -export declare class TextNowAPI { - private baseUrl; - private auth; - constructor(auth: TextNowAuth, baseUrl?: string); - /** - * Get default headers for all requests - */ - private getHeaders; - /** - * Generic request handler with error handling - */ - private request; - /** - * Send an SMS message - * POST /api/users/{username}/messages - */ - send(to: string, message: string): Promise; - /** - * Get messages/conversations - * GET /api/users/{username}/messages - */ - getMessages(params?: { - limit?: number; - start_message_id?: string; - direction?: 'past' | 'future'; - contact_value?: string; - }): Promise<{ - messages: Message[]; - }>; - /** - * Get conversations list - * GET /api/users/{username}/conversations - */ - getConversations(params?: { - limit?: number; - offset?: number; - }): Promise<{ - conversations: Conversation[]; - }>; - /** - * Get a presigned URL for uploading media - * GET /api/v3/attachment_url?message_type=2 (images) or message_type=3 (audio) - */ - getUploadUrl(mediaType?: 'image' | 'audio'): Promise; - /** - * Upload a file to the presigned URL - * PUT to presigned URL with raw binary - */ - uploadToPresignedUrl(uploadUrl: string, data: Buffer, contentType: string): Promise; - /** - * Send media attachment - * POST /api/v3/send_attachment with form data - */ - sendMedia(options: SendMediaRequest): Promise; - /** - * Send an image file - */ - sendImage(to: string, filePath: string): Promise; - /** - * Send an image from buffer - */ - sendImageBuffer(to: string, buffer: Buffer, filename?: string, contentType?: string): Promise; - /** - * Send an audio file - */ - sendAudio(to: string, filePath: string): Promise; - /** - * Get messages from a specific contact - */ - getMessagesFrom(contactNumber: string, limit?: number): Promise; - /** - * Mark messages as read (if endpoint exists) - * This is a placeholder - actual endpoint may vary - */ - markAsRead(messageIds: string[]): Promise; -} -/** - * Create a TextNowAPI client from stored credentials - */ -export declare function createTextNowClient(): TextNowAPI; -/** - * Create a TextNowAPI client with explicit credentials - */ -export declare function createTextNowClientWithCredentials(username: string, cookies: string, save?: boolean): TextNowAPI; -export default TextNowAPI; -//# sourceMappingURL=api.d.ts.map \ No newline at end of file diff --git a/textnow-integration/dist/src/api.d.ts.map b/textnow-integration/dist/src/api.d.ts.map deleted file mode 100644 index 27dbdf4..0000000 --- a/textnow-integration/dist/src/api.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAQxC,qBAAa,eAAgB,SAAQ,KAAK;IAE/B,UAAU,EAAE,MAAM;IAClB,UAAU,EAAE,MAAM;IAClB,IAAI,EAAE,OAAO;IACb,QAAQ,EAAE,MAAM;gBAHhB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM;CAK1B;AAMD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,CAAC,GAAG,CAAC,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;CAChB;AAMD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,IAAI,CAAc;gBAEd,IAAI,EAAE,WAAW,EAAE,OAAO,GAAE,MAAiB;IAKzD;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;OAEG;YACW,OAAO;IAgErB;;;OAGG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAcrE;;;OAGG;IACG,WAAW,CAAC,MAAM,CAAC,EAAE;QACzB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAepC;;;OAGG;IACG,gBAAgB,CAAC,MAAM,CAAC,EAAE;QAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC;QAAE,aAAa,EAAE,YAAY,EAAE,CAAA;KAAE,CAAC;IAiB9C;;;OAGG;IACG,YAAY,CAAC,SAAS,GAAE,OAAO,GAAG,OAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ3E;;;OAGG;IACG,oBAAoB,CACxB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAmBhB;;;OAGG;IACG,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA2DxE;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAQ3E;;OAEG;IACG,eAAe,CACnB,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,QAAQ,GAAE,MAAoB,EAC9B,WAAW,GAAE,MAAqB,GACjC,OAAO,CAAC,mBAAmB,CAAC;IAU/B;;OAEG;IACG,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAQ3E;;OAEG;IACG,eAAe,CACnB,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,OAAO,EAAE,CAAC;IAQrB;;;OAGG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAQtD;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CAahD;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,OAAc,GACnB,UAAU,CAIZ;AAED,eAAe,UAAU,CAAC"} \ No newline at end of file diff --git a/textnow-integration/dist/src/api.js b/textnow-integration/dist/src/api.js deleted file mode 100644 index b6ceea1..0000000 --- a/textnow-integration/dist/src/api.js +++ /dev/null @@ -1,307 +0,0 @@ -/** - * TextNow REST API Client - * Base URL: https://www.textnow.com - */ -import { readFileSync } from 'node:fs'; -import { TextNowAuth } from './auth.js'; -const BASE_URL = 'https://www.textnow.com'; -// ============================================================================ -// Error Types -// ============================================================================ -export class TextNowAPIError extends Error { - statusCode; - statusText; - body; - endpoint; - constructor(statusCode, statusText, body, endpoint) { - super(`TextNow API Error [${statusCode}] ${statusText} at ${endpoint}`); - this.statusCode = statusCode; - this.statusText = statusText; - this.body = body; - this.endpoint = endpoint; - this.name = 'TextNowAPIError'; - } -} -// ============================================================================ -// TextNow API Client -// ============================================================================ -export class TextNowAPI { - baseUrl; - auth; - constructor(auth, baseUrl = BASE_URL) { - this.baseUrl = baseUrl; - this.auth = auth; - } - /** - * Get default headers for all requests - */ - getHeaders(contentType = 'application/json') { - const authHeaders = this.auth.getAuthHeaders(); - return { - ...authHeaders, - 'Content-Type': contentType, - }; - } - /** - * Generic request handler with error handling - */ - async request(method, endpoint, body, customHeaders) { - const url = `${this.baseUrl}${endpoint}`; - const headers = { ...this.getHeaders(), ...customHeaders }; - const options = { - method, - headers, - }; - if (body !== undefined && method !== 'GET') { - if (body instanceof FormData) { - // Remove Content-Type for FormData (browser sets it with boundary) - delete options.headers['Content-Type']; - options.body = body; - } - else if (Buffer.isBuffer(body)) { - options.body = body; - } - else { - options.body = JSON.stringify(body); - } - } - const response = await fetch(url, options); - if (!response.ok) { - let errorBody; - try { - errorBody = await response.json(); - } - catch { - errorBody = await response.text(); - } - throw new TextNowAPIError(response.status, response.statusText, errorBody, endpoint); - } - // Handle empty responses - if (response.status === 204) { - return {}; - } - const text = await response.text(); - if (!text) { - return {}; - } - try { - return JSON.parse(text); - } - catch { - return text; - } - } - // ========================================================================== - // Messaging Endpoints - // ========================================================================== - /** - * Send an SMS message - * POST /api/users/{username}/messages - */ - async send(to, message) { - const username = this.auth.getUsername(); - const endpoint = `/api/users/${username}/messages`; - const payload = { - contact_value: to, - message_direction: 2, // Outgoing - contact_type: 2, // Phone number - message: message, - }; - return this.request('POST', endpoint, payload); - } - /** - * Get messages/conversations - * GET /api/users/{username}/messages - */ - async getMessages(params) { - const username = this.auth.getUsername(); - const queryParams = new URLSearchParams(); - if (params?.limit) - queryParams.set('limit', params.limit.toString()); - if (params?.start_message_id) - queryParams.set('start_message_id', params.start_message_id); - if (params?.direction) - queryParams.set('direction', params.direction); - if (params?.contact_value) - queryParams.set('contact_value', params.contact_value); - const query = queryParams.toString(); - const endpoint = `/api/users/${username}/messages${query ? `?${query}` : ''}`; - return this.request('GET', endpoint); - } - /** - * Get conversations list - * GET /api/users/{username}/conversations - */ - async getConversations(params) { - const username = this.auth.getUsername(); - const queryParams = new URLSearchParams(); - if (params?.limit) - queryParams.set('limit', params.limit.toString()); - if (params?.offset) - queryParams.set('offset', params.offset.toString()); - const query = queryParams.toString(); - const endpoint = `/api/users/${username}/conversations${query ? `?${query}` : ''}`; - return this.request('GET', endpoint); - } - // ========================================================================== - // Media/Attachment Endpoints - // ========================================================================== - /** - * Get a presigned URL for uploading media - * GET /api/v3/attachment_url?message_type=2 (images) or message_type=3 (audio) - */ - async getUploadUrl(mediaType = 'image') { - const messageType = mediaType === 'image' ? 2 : 3; - const endpoint = `/api/v3/attachment_url?message_type=${messageType}`; - const response = await this.request('GET', endpoint); - return response.result; - } - /** - * Upload a file to the presigned URL - * PUT to presigned URL with raw binary - */ - async uploadToPresignedUrl(uploadUrl, data, contentType) { - const response = await fetch(uploadUrl, { - method: 'PUT', - headers: { - 'Content-Type': contentType, - }, - body: data, - }); - if (!response.ok) { - throw new TextNowAPIError(response.status, response.statusText, await response.text(), uploadUrl); - } - } - /** - * Send media attachment - * POST /api/v3/send_attachment with form data - */ - async sendMedia(options) { - const { contact_value, filePath, buffer, filename, contentType, mediaType = 'image' } = options; - // Get file data - let fileData; - let fileContentType = contentType || 'image/jpeg'; - let fileName = filename || 'attachment.jpg'; - if (buffer) { - fileData = buffer; - } - else if (filePath) { - fileData = readFileSync(filePath); - // Infer content type from extension if not provided - if (!contentType) { - const ext = filePath.split('.').pop()?.toLowerCase(); - const mimeTypes = { - 'jpg': 'image/jpeg', - 'jpeg': 'image/jpeg', - 'png': 'image/png', - 'gif': 'image/gif', - 'webp': 'image/webp', - 'mp3': 'audio/mpeg', - 'wav': 'audio/wav', - 'm4a': 'audio/mp4', - }; - fileContentType = mimeTypes[ext || ''] || 'application/octet-stream'; - } - fileName = filePath.split('/').pop() || fileName; - } - else { - throw new TextNowAPIError(400, 'Bad Request', 'Must provide filePath or buffer', '/api/v3/send_attachment'); - } - // Step 1: Get presigned upload URL - const uploadUrl = await this.getUploadUrl(mediaType); - // Step 2: Upload the file - await this.uploadToPresignedUrl(uploadUrl, fileData, fileContentType); - // Step 3: Send the attachment message - // Extract the file key/path from the upload URL - const url = new URL(uploadUrl); - const mediaUrl = `${url.origin}${url.pathname}`; - const formData = new FormData(); - formData.append('contact_value', contact_value); - formData.append('contact_type', '2'); // Phone number - formData.append('message_direction', '2'); // Outgoing - formData.append('message_type', mediaType === 'image' ? '2' : '3'); - formData.append('media_url', mediaUrl); - formData.append('filename', fileName); - const endpoint = '/api/v3/send_attachment'; - return this.request('POST', endpoint, formData); - } - // ========================================================================== - // Convenience Methods - // ========================================================================== - /** - * Send an image file - */ - async sendImage(to, filePath) { - return this.sendMedia({ - contact_value: to, - filePath, - mediaType: 'image', - }); - } - /** - * Send an image from buffer - */ - async sendImageBuffer(to, buffer, filename = 'image.jpg', contentType = 'image/jpeg') { - return this.sendMedia({ - contact_value: to, - buffer, - filename, - contentType, - mediaType: 'image', - }); - } - /** - * Send an audio file - */ - async sendAudio(to, filePath) { - return this.sendMedia({ - contact_value: to, - filePath, - mediaType: 'audio', - }); - } - /** - * Get messages from a specific contact - */ - async getMessagesFrom(contactNumber, limit = 50) { - const result = await this.getMessages({ - contact_value: contactNumber, - limit, - }); - return result.messages || []; - } - /** - * Mark messages as read (if endpoint exists) - * This is a placeholder - actual endpoint may vary - */ - async markAsRead(messageIds) { - const username = this.auth.getUsername(); - const endpoint = `/api/users/${username}/messages/read`; - await this.request('POST', endpoint, { - message_ids: messageIds, - }); - } -} -// ============================================================================ -// Factory Functions -// ============================================================================ -/** - * Create a TextNowAPI client from stored credentials - */ -export function createTextNowClient() { - const auth = new TextNowAuth(); - if (!auth.isAuthenticated()) { - throw new TextNowAPIError(401, 'Not Authenticated', 'No stored credentials found. Please set credentials first.', 'initialization'); - } - return new TextNowAPI(auth); -} -/** - * Create a TextNowAPI client with explicit credentials - */ -export function createTextNowClientWithCredentials(username, cookies, save = true) { - const auth = new TextNowAuth(); - auth.setCredentials(username, cookies, save); - return new TextNowAPI(auth); -} -export default TextNowAPI; -//# sourceMappingURL=api.js.map \ No newline at end of file diff --git a/textnow-integration/dist/src/api.js.map b/textnow-integration/dist/src/api.js.map deleted file mode 100644 index a17cbc6..0000000 --- a/textnow-integration/dist/src/api.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,QAAQ,GAAG,yBAAyB,CAAC;AAE3C,+EAA+E;AAC/E,cAAc;AACd,+EAA+E;AAE/E,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAE/B;IACA;IACA;IACA;IAJT,YACS,UAAkB,EAClB,UAAkB,EAClB,IAAa,EACb,QAAgB;QAEvB,KAAK,CAAC,sBAAsB,UAAU,KAAK,UAAU,OAAO,QAAQ,EAAE,CAAC,CAAC;QALjE,eAAU,GAAV,UAAU,CAAQ;QAClB,eAAU,GAAV,UAAU,CAAQ;QAClB,SAAI,GAAJ,IAAI,CAAS;QACb,aAAQ,GAAR,QAAQ,CAAQ;QAGvB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAsDD,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E,MAAM,OAAO,UAAU;IACb,OAAO,CAAS;IAChB,IAAI,CAAc;IAE1B,YAAY,IAAiB,EAAE,UAAkB,QAAQ;QACvD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;OAEG;IACK,UAAU,CAAC,cAAsB,kBAAkB;QACzD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;QAC/C,OAAO;YACL,GAAG,WAAW;YACd,cAAc,EAAE,WAAW;SAC5B,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,OAAO,CACnB,MAAyC,EACzC,QAAgB,EAChB,IAAc,EACd,aAAsC;QAEtC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,EAAE,EAAE,GAAG,aAAa,EAAE,CAAC;QAE3D,MAAM,OAAO,GAAgB;YAC3B,MAAM;YACN,OAAO;SACR,CAAC;QAEF,IAAI,IAAI,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YAC3C,IAAI,IAAI,YAAY,QAAQ,EAAE,CAAC;gBAC7B,mEAAmE;gBACnE,OAAQ,OAAO,CAAC,OAAkC,CAAC,cAAc,CAAC,CAAC;gBACnE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;YACtB,CAAC;iBAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;YACtB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAE3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,IAAI,SAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACpC,CAAC;YACD,MAAM,IAAI,eAAe,CACvB,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,UAAU,EACnB,SAAS,EACT,QAAQ,CACT,CAAC;QACJ,CAAC;QAED,yBAAyB;QACzB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,EAAO,CAAC;QACjB,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAO,CAAC;QACjB,CAAC;QAED,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAoB,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,sBAAsB;IACtB,6EAA6E;IAE7E;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,EAAU,EAAE,OAAe;QACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,cAAc,QAAQ,WAAW,CAAC;QAEnD,MAAM,OAAO,GAAG;YACd,aAAa,EAAE,EAAE;YACjB,iBAAiB,EAAE,CAAC,EAAE,WAAW;YACjC,YAAY,EAAE,CAAC,EAAE,eAAe;YAChC,OAAO,EAAE,OAAO;SACjB,CAAC;QAEF,OAAO,IAAI,CAAC,OAAO,CAAsB,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtE,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,MAKjB;QACC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAEzC,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE,CAAC;QAC1C,IAAI,MAAM,EAAE,KAAK;YAAE,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrE,IAAI,MAAM,EAAE,gBAAgB;YAAE,WAAW,CAAC,GAAG,CAAC,kBAAkB,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC;QAC3F,IAAI,MAAM,EAAE,SAAS;YAAE,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QACtE,IAAI,MAAM,EAAE,aAAa;YAAE,WAAW,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QAElF,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,cAAc,QAAQ,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAE9E,OAAO,IAAI,CAAC,OAAO,CAA0B,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChE,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB,CAAC,MAGtB;QACC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAEzC,MAAM,WAAW,GAAG,IAAI,eAAe,EAAE,CAAC;QAC1C,IAAI,MAAM,EAAE,KAAK;YAAE,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrE,IAAI,MAAM,EAAE,MAAM;YAAE,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAExE,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,cAAc,QAAQ,iBAAiB,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QAEnF,OAAO,IAAI,CAAC,OAAO,CAAoC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC1E,CAAC;IAED,6EAA6E;IAC7E,6BAA6B;IAC7B,6EAA6E;IAE7E;;;OAGG;IACH,KAAK,CAAC,YAAY,CAAC,YAA+B,OAAO;QACvD,MAAM,WAAW,GAAG,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAG,uCAAuC,WAAW,EAAE,CAAC;QAEtE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAwB,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC5E,OAAO,QAAQ,CAAC,MAAM,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,oBAAoB,CACxB,SAAiB,EACjB,IAAY,EACZ,WAAmB;QAEnB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;YACtC,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,cAAc,EAAE,WAAW;aAC5B;YACD,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,eAAe,CACvB,QAAQ,CAAC,MAAM,EACf,QAAQ,CAAC,UAAU,EACnB,MAAM,QAAQ,CAAC,IAAI,EAAE,EACrB,SAAS,CACV,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,SAAS,CAAC,OAAyB;QACvC,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC;QAEhG,gBAAgB;QAChB,IAAI,QAAgB,CAAC;QACrB,IAAI,eAAe,GAAG,WAAW,IAAI,YAAY,CAAC;QAClD,IAAI,QAAQ,GAAG,QAAQ,IAAI,gBAAgB,CAAC;QAE5C,IAAI,MAAM,EAAE,CAAC;YACX,QAAQ,GAAG,MAAM,CAAC;QACpB,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAClC,oDAAoD;YACpD,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;gBACrD,MAAM,SAAS,GAA2B;oBACxC,KAAK,EAAE,YAAY;oBACnB,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,WAAW;oBAClB,KAAK,EAAE,WAAW;oBAClB,MAAM,EAAE,YAAY;oBACpB,KAAK,EAAE,YAAY;oBACnB,KAAK,EAAE,WAAW;oBAClB,KAAK,EAAE,WAAW;iBACnB,CAAC;gBACF,eAAe,GAAG,SAAS,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,0BAA0B,CAAC;YACvE,CAAC;YACD,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,aAAa,EAAE,iCAAiC,EAAE,yBAAyB,CAAC,CAAC;QAC9G,CAAC;QAED,mCAAmC;QACnC,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAErD,0BAA0B;QAC1B,MAAM,IAAI,CAAC,oBAAoB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAEtE,sCAAsC;QACtC,gDAAgD;QAChD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;QAEhD,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;QAChC,QAAQ,CAAC,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,CAAC;QAChD,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC,CAAC,eAAe;QACrD,QAAQ,CAAC,MAAM,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW;QACtD,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACnE,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACvC,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAEtC,MAAM,QAAQ,GAAG,yBAAyB,CAAC;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAsB,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACvE,CAAC;IAED,6EAA6E;IAC7E,sBAAsB;IACtB,6EAA6E;IAE7E;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,QAAgB;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,aAAa,EAAE,EAAE;YACjB,QAAQ;YACR,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CACnB,EAAU,EACV,MAAc,EACd,WAAmB,WAAW,EAC9B,cAAsB,YAAY;QAElC,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,aAAa,EAAE,EAAE;YACjB,MAAM;YACN,QAAQ;YACR,WAAW;YACX,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,EAAU,EAAE,QAAgB;QAC1C,OAAO,IAAI,CAAC,SAAS,CAAC;YACpB,aAAa,EAAE,EAAE;YACjB,QAAQ;YACR,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CACnB,aAAqB,EACrB,QAAgB,EAAE;QAElB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC;YACpC,aAAa,EAAE,aAAa;YAC5B,KAAK;SACN,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,UAAoB;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACzC,MAAM,QAAQ,GAAG,cAAc,QAAQ,gBAAgB,CAAC;QAExD,MAAM,IAAI,CAAC,OAAO,CAAO,MAAM,EAAE,QAAQ,EAAE;YACzC,WAAW,EAAE,UAAU;SACxB,CAAC,CAAC;IACL,CAAC;CACF;AAED,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;IAE/B,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,eAAe,CACvB,GAAG,EACH,mBAAmB,EACnB,4DAA4D,EAC5D,gBAAgB,CACjB,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kCAAkC,CAChD,QAAgB,EAChB,OAAe,EACf,OAAgB,IAAI;IAEpB,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;IAC/B,IAAI,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7C,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,eAAe,UAAU,CAAC"} \ No newline at end of file diff --git a/textnow-integration/dist/src/auth.d.ts b/textnow-integration/dist/src/auth.d.ts deleted file mode 100644 index 9400143..0000000 --- a/textnow-integration/dist/src/auth.d.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * TextNow Authentication Module - * Handles cookie-based authentication, CSRF tokens, and credential storage - */ -export interface TextNowCredentials { - username: string; - cookies: string; - csrfToken: string; - savedAt: string; -} -export interface ParsedCookies { - connectSid?: string; - csrf?: string; - xsrfToken?: string; - raw: string; -} -export declare class TextNowAuthError extends Error { - code: string; - statusCode?: number | undefined; - constructor(message: string, code: string, statusCode?: number | undefined); -} -/** - * Parse a cookie string into its components - * Extracts connect.sid, _csrf, and XSRF-TOKEN - */ -export declare function parseCookies(cookieString: string): ParsedCookies; -/** - * Extract the CSRF token value from cookies - * IMPORTANT: Use XSRF-TOKEN value (NOT _csrf) for the X-CSRF-Token header - */ -export declare function extractCSRFToken(cookieString: string): string | null; -/** - * Validate that all required cookies are present - */ -export declare function validateCookies(cookies: ParsedCookies): boolean; -/** - * Save credentials to ~/.textnow/credentials.json - */ -export declare function saveCredentials(username: string, cookies: string, csrfToken: string): void; -/** - * Load credentials from ~/.textnow/credentials.json - */ -export declare function loadCredentials(): TextNowCredentials | null; -/** - * Check if stored credentials exist - */ -export declare function hasStoredCredentials(): boolean; -/** - * Delete stored credentials - */ -export declare function clearCredentials(): void; -export declare class TextNowAuth { - private username; - private cookies; - private csrfToken; - constructor(); - /** - * Set credentials from browser cookies - * @param username - TextNow username (for API endpoints) - * @param cookieString - Full cookie string from browser - * @param save - Whether to persist to disk (default: true) - */ - setCredentials(username: string, cookieString: string, save?: boolean): void; - /** - * Get the username for API calls - */ - getUsername(): string; - /** - * Get headers required for TextNow API requests - */ - getAuthHeaders(): Record; - /** - * Check if authenticated - */ - isAuthenticated(): boolean; - /** - * Clear authentication state - */ - logout(clearStored?: boolean): void; - /** - * Get the raw cookie string - */ - getCookies(): string | null; - /** - * Get the CSRF token - */ - getCSRFToken(): string | null; -} -export default TextNowAuth; -//# sourceMappingURL=auth.d.ts.map \ No newline at end of file diff --git a/textnow-integration/dist/src/auth.d.ts.map b/textnow-integration/dist/src/auth.d.ts.map deleted file mode 100644 index e9261da..0000000 --- a/textnow-integration/dist/src/auth.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IAGhC,IAAI,EAAE,MAAM;IACZ,UAAU,CAAC,EAAE,MAAM;gBAF1B,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,YAAA;CAK7B;AAaD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,CA6BhE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGpE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAE/D;AAeD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,IAAI,CAeN;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,kBAAkB,GAAG,IAAI,CAY3D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAMvC;AAMD,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,SAAS,CAAuB;;IAYxC;;;;;OAKG;IACH,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,OAAc,GACnB,IAAI;IAmBP;;OAEG;IACH,WAAW,IAAI,MAAM;IAOrB;;OAEG;IACH,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAexC;;OAEG;IACH,eAAe,IAAI,OAAO;IAI1B;;OAEG;IACH,MAAM,CAAC,WAAW,GAAE,OAAc,GAAG,IAAI;IAUzC;;OAEG;IACH,UAAU,IAAI,MAAM,GAAG,IAAI;IAI3B;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;CAG9B;AAED,eAAe,WAAW,CAAC"} \ No newline at end of file diff --git a/textnow-integration/dist/src/auth.js b/textnow-integration/dist/src/auth.js deleted file mode 100644 index 3db80b5..0000000 --- a/textnow-integration/dist/src/auth.js +++ /dev/null @@ -1,218 +0,0 @@ -/** - * TextNow Authentication Module - * Handles cookie-based authentication, CSRF tokens, and credential storage - */ -import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; -import { homedir } from 'node:os'; -import { join } from 'node:path'; -export class TextNowAuthError extends Error { - code; - statusCode; - constructor(message, code, statusCode) { - super(message); - this.code = code; - this.statusCode = statusCode; - this.name = 'TextNowAuthError'; - } -} -// ============================================================================ -// Constants -// ============================================================================ -const CREDENTIALS_DIR = join(homedir(), '.textnow'); -const CREDENTIALS_FILE = join(CREDENTIALS_DIR, 'credentials.json'); -// ============================================================================ -// Cookie Parsing -// ============================================================================ -/** - * Parse a cookie string into its components - * Extracts connect.sid, _csrf, and XSRF-TOKEN - */ -export function parseCookies(cookieString) { - const cookies = { raw: cookieString }; - // Parse individual cookies - const pairs = cookieString.split(';').map(s => s.trim()); - for (const pair of pairs) { - const [name, ...valueParts] = pair.split('='); - const value = valueParts.join('='); // Handle values with = in them - if (!name || !value) - continue; - const trimmedName = name.trim(); - const trimmedValue = value.trim(); - switch (trimmedName) { - case 'connect.sid': - cookies.connectSid = trimmedValue; - break; - case '_csrf': - cookies.csrf = trimmedValue; - break; - case 'XSRF-TOKEN': - cookies.xsrfToken = trimmedValue; - break; - } - } - return cookies; -} -/** - * Extract the CSRF token value from cookies - * IMPORTANT: Use XSRF-TOKEN value (NOT _csrf) for the X-CSRF-Token header - */ -export function extractCSRFToken(cookieString) { - const parsed = parseCookies(cookieString); - return parsed.xsrfToken || null; -} -/** - * Validate that all required cookies are present - */ -export function validateCookies(cookies) { - return !!(cookies.connectSid && cookies.xsrfToken); -} -// ============================================================================ -// Credential Storage -// ============================================================================ -/** - * Ensure the credentials directory exists - */ -function ensureCredentialsDir() { - if (!existsSync(CREDENTIALS_DIR)) { - mkdirSync(CREDENTIALS_DIR, { mode: 0o700, recursive: true }); - } -} -/** - * Save credentials to ~/.textnow/credentials.json - */ -export function saveCredentials(username, cookies, csrfToken) { - ensureCredentialsDir(); - const credentials = { - username, - cookies, - csrfToken, - savedAt: new Date().toISOString(), - }; - writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), { - mode: 0o600, // Read/write for owner only - }); - console.log(`[TextNowAuth] Credentials saved to ${CREDENTIALS_FILE}`); -} -/** - * Load credentials from ~/.textnow/credentials.json - */ -export function loadCredentials() { - if (!existsSync(CREDENTIALS_FILE)) { - return null; - } - try { - const data = readFileSync(CREDENTIALS_FILE, 'utf-8'); - return JSON.parse(data); - } - catch (err) { - console.error('[TextNowAuth] Failed to load credentials:', err); - return null; - } -} -/** - * Check if stored credentials exist - */ -export function hasStoredCredentials() { - return existsSync(CREDENTIALS_FILE); -} -/** - * Delete stored credentials - */ -export function clearCredentials() { - if (existsSync(CREDENTIALS_FILE)) { - const { unlinkSync } = require('node:fs'); - unlinkSync(CREDENTIALS_FILE); - console.log('[TextNowAuth] Credentials cleared'); - } -} -// ============================================================================ -// Auth Helper Class -// ============================================================================ -export class TextNowAuth { - username = null; - cookies = null; - csrfToken = null; - constructor() { - // Try to load stored credentials on init - const stored = loadCredentials(); - if (stored) { - this.username = stored.username; - this.cookies = stored.cookies; - this.csrfToken = stored.csrfToken; - } - } - /** - * Set credentials from browser cookies - * @param username - TextNow username (for API endpoints) - * @param cookieString - Full cookie string from browser - * @param save - Whether to persist to disk (default: true) - */ - setCredentials(username, cookieString, save = true) { - const parsed = parseCookies(cookieString); - if (!validateCookies(parsed)) { - throw new TextNowAuthError('Missing required cookies (connect.sid or XSRF-TOKEN)', 'INVALID_COOKIES'); - } - this.username = username; - this.cookies = cookieString; - this.csrfToken = parsed.xsrfToken; - if (save) { - saveCredentials(username, cookieString, this.csrfToken); - } - } - /** - * Get the username for API calls - */ - getUsername() { - if (!this.username) { - throw new TextNowAuthError('Not authenticated', 'NOT_AUTHENTICATED'); - } - return this.username; - } - /** - * Get headers required for TextNow API requests - */ - getAuthHeaders() { - if (!this.cookies || !this.csrfToken) { - throw new TextNowAuthError('Not authenticated', 'NOT_AUTHENTICATED'); - } - return { - 'Cookie': this.cookies, - 'X-CSRF-Token': this.csrfToken, - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', - 'X-Requested-With': 'XMLHttpRequest', - 'Referer': 'https://www.textnow.com/messaging', - 'Origin': 'https://www.textnow.com', - }; - } - /** - * Check if authenticated - */ - isAuthenticated() { - return !!(this.username && this.cookies && this.csrfToken); - } - /** - * Clear authentication state - */ - logout(clearStored = true) { - this.username = null; - this.cookies = null; - this.csrfToken = null; - if (clearStored) { - clearCredentials(); - } - } - /** - * Get the raw cookie string - */ - getCookies() { - return this.cookies; - } - /** - * Get the CSRF token - */ - getCSRFToken() { - return this.csrfToken; - } -} -export default TextNowAuth; -//# sourceMappingURL=auth.js.map \ No newline at end of file diff --git a/textnow-integration/dist/src/auth.js.map b/textnow-integration/dist/src/auth.js.map deleted file mode 100644 index d59c203..0000000 --- a/textnow-integration/dist/src/auth.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAoBjC,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAGhC;IACA;IAHT,YACE,OAAe,EACR,IAAY,EACZ,UAAmB;QAE1B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAS;QAG1B,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAAC;AAEnE,+EAA+E;AAC/E,iBAAiB;AACjB,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,YAAoB;IAC/C,MAAM,OAAO,GAAkB,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC;IAErD,2BAA2B;IAC3B,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEzD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC9C,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,+BAA+B;QAEnE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;YAAE,SAAS;QAE9B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAElC,QAAQ,WAAW,EAAE,CAAC;YACpB,KAAK,aAAa;gBAChB,OAAO,CAAC,UAAU,GAAG,YAAY,CAAC;gBAClC,MAAM;YACR,KAAK,OAAO;gBACV,OAAO,CAAC,IAAI,GAAG,YAAY,CAAC;gBAC5B,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,CAAC,SAAS,GAAG,YAAY,CAAC;gBACjC,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoB;IACnD,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,SAAS,IAAI,IAAI,CAAC;AAClC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAsB;IACpD,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;AACrD,CAAC;AAED,+EAA+E;AAC/E,qBAAqB;AACrB,+EAA+E;AAE/E;;GAEG;AACH,SAAS,oBAAoB;IAC3B,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,SAAS,CAAC,eAAe,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,QAAgB,EAChB,OAAe,EACf,SAAiB;IAEjB,oBAAoB,EAAE,CAAC;IAEvB,MAAM,WAAW,GAAuB;QACtC,QAAQ;QACR,OAAO;QACP,SAAS;QACT,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KAClC,CAAC;IAEF,aAAa,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QACpE,IAAI,EAAE,KAAK,EAAE,4BAA4B;KAC1C,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,sCAAsC,gBAAgB,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAuB,CAAC;IAChD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,UAAU,CAAC,gBAAgB,CAAC,CAAC;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACjC,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,UAAU,CAAC,gBAAgB,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACnD,CAAC;AACH,CAAC;AAED,+EAA+E;AAC/E,oBAAoB;AACpB,+EAA+E;AAE/E,MAAM,OAAO,WAAW;IACd,QAAQ,GAAkB,IAAI,CAAC;IAC/B,OAAO,GAAkB,IAAI,CAAC;IAC9B,SAAS,GAAkB,IAAI,CAAC;IAExC;QACE,yCAAyC;QACzC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YAChC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YAC9B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACpC,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,cAAc,CACZ,QAAgB,EAChB,YAAoB,EACpB,OAAgB,IAAI;QAEpB,MAAM,MAAM,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAE1C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,gBAAgB,CACxB,sDAAsD,EACtD,iBAAiB,CAClB,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAU,CAAC;QAEnC,IAAI,IAAI,EAAE,CAAC;YACT,eAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAED;;OAEG;IACH,WAAW;QACT,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,MAAM,IAAI,gBAAgB,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACrC,MAAM,IAAI,gBAAgB,CAAC,mBAAmB,EAAE,mBAAmB,CAAC,CAAC;QACvE,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,OAAO;YACtB,cAAc,EAAE,IAAI,CAAC,SAAS;YAC9B,YAAY,EAAE,uHAAuH;YACrI,kBAAkB,EAAE,gBAAgB;YACpC,SAAS,EAAE,mCAAmC;YAC9C,QAAQ,EAAE,yBAAyB;SACpC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,cAAuB,IAAI;QAChC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;QAEtB,IAAI,WAAW,EAAE,CAAC;YAChB,gBAAgB,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF;AAED,eAAe,WAAW,CAAC"} \ No newline at end of file diff --git a/textnow-integration/dist/src/index.d.ts b/textnow-integration/dist/src/index.d.ts deleted file mode 100644 index 5668a18..0000000 --- a/textnow-integration/dist/src/index.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * TextNow Unofficial API - * TypeScript client for TextNow messaging service - */ -export { TextNowAuth, TextNowAuthError, type TextNowCredentials, type ParsedCookies, parseCookies, extractCSRFToken, validateCookies, saveCredentials, loadCredentials, hasStoredCredentials, clearCredentials, } from './auth.js'; -export { TextNowAPI, TextNowAPIError, type Message, type Conversation, type SendMessageRequest, type SendMessageResponse, type SendMediaRequest, type AttachmentUrlResponse, createTextNowClient, createTextNowClientWithCredentials, } from './api.js'; -export { TextNowAPI as default } from './api.js'; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/textnow-integration/dist/src/index.d.ts.map b/textnow-integration/dist/src/index.d.ts.map deleted file mode 100644 index fa046bc..0000000 --- a/textnow-integration/dist/src/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,UAAU,EACV,eAAe,EACf,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,qBAAqB,EAC1B,mBAAmB,EACnB,kCAAkC,GACnC,MAAM,UAAU,CAAC;AAGlB,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,UAAU,CAAC"} \ No newline at end of file diff --git a/textnow-integration/dist/src/index.js b/textnow-integration/dist/src/index.js deleted file mode 100644 index 4f9c8a8..0000000 --- a/textnow-integration/dist/src/index.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * TextNow Unofficial API - * TypeScript client for TextNow messaging service - */ -// Auth exports -export { TextNowAuth, TextNowAuthError, parseCookies, extractCSRFToken, validateCookies, saveCredentials, loadCredentials, hasStoredCredentials, clearCredentials, } from './auth.js'; -// API exports -export { TextNowAPI, TextNowAPIError, createTextNowClient, createTextNowClientWithCredentials, } from './api.js'; -// Default export -export { TextNowAPI as default } from './api.js'; -//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/textnow-integration/dist/src/index.js.map b/textnow-integration/dist/src/index.js.map deleted file mode 100644 index e45cd49..0000000 --- a/textnow-integration/dist/src/index.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAe;AACf,OAAO,EACL,WAAW,EACX,gBAAgB,EAGhB,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AAEnB,cAAc;AACd,OAAO,EACL,UAAU,EACV,eAAe,EAOf,mBAAmB,EACnB,kCAAkC,GACnC,MAAM,UAAU,CAAC;AAElB,iBAAiB;AACjB,OAAO,EAAE,UAAU,IAAI,OAAO,EAAE,MAAM,UAAU,CAAC"} \ No newline at end of file