lemonsqueezy-mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ENV_EXAMPLE.md +83 -0
- package/LICENSE +21 -0
- package/README.md +141 -0
- package/SETUP.md +244 -0
- package/dist/config.d.ts +25 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +80 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +55 -0
- package/dist/config.test.js.map +1 -0
- package/dist/connections/firebase.d.ts +3 -0
- package/dist/connections/firebase.d.ts.map +1 -0
- package/dist/connections/firebase.js +62 -0
- package/dist/connections/firebase.js.map +1 -0
- package/dist/connections/salesforce.d.ts +3 -0
- package/dist/connections/salesforce.d.ts.map +1 -0
- package/dist/connections/salesforce.js +307 -0
- package/dist/connections/salesforce.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/resources/payment-context.d.ts +14 -0
- package/dist/resources/payment-context.d.ts.map +1 -0
- package/dist/resources/payment-context.js +111 -0
- package/dist/resources/payment-context.js.map +1 -0
- package/dist/server.d.ts +36 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +14 -0
- package/dist/server.js.map +1 -0
- package/dist/sync-last-purchase.d.ts +3 -0
- package/dist/sync-last-purchase.d.ts.map +1 -0
- package/dist/sync-last-purchase.js +113 -0
- package/dist/sync-last-purchase.js.map +1 -0
- package/dist/tools/definitions.d.ts +3768 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +753 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/handlers/analytics.d.ts +21 -0
- package/dist/tools/handlers/analytics.d.ts.map +1 -0
- package/dist/tools/handlers/analytics.js +398 -0
- package/dist/tools/handlers/analytics.js.map +1 -0
- package/dist/tools/handlers/lemonsqueezy.d.ts +436 -0
- package/dist/tools/handlers/lemonsqueezy.d.ts.map +1 -0
- package/dist/tools/handlers/lemonsqueezy.js +481 -0
- package/dist/tools/handlers/lemonsqueezy.js.map +1 -0
- package/dist/tools/handlers/salesforce.d.ts +13 -0
- package/dist/tools/handlers/salesforce.d.ts.map +1 -0
- package/dist/tools/handlers/salesforce.js +54 -0
- package/dist/tools/handlers/salesforce.js.map +1 -0
- package/dist/tools/handlers/vos.d.ts +26 -0
- package/dist/tools/handlers/vos.d.ts.map +1 -0
- package/dist/tools/handlers/vos.js +207 -0
- package/dist/tools/handlers/vos.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +202 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +24 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/logger.d.ts +3 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +8 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/response.d.ts +14 -0
- package/dist/utils/response.d.ts.map +1 -0
- package/dist/utils/response.js +17 -0
- package/dist/utils/response.js.map +1 -0
- package/dist/utils/retry.d.ts +11 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +36 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/secrets/provider.d.ts +30 -0
- package/dist/utils/secrets/provider.d.ts.map +1 -0
- package/dist/utils/secrets/provider.js +51 -0
- package/dist/utils/secrets/provider.js.map +1 -0
- package/dist/utils/secrets.d.ts +7 -0
- package/dist/utils/secrets.d.ts.map +1 -0
- package/dist/utils/secrets.js +16 -0
- package/dist/utils/secrets.js.map +1 -0
- package/dist/utils/validation.d.ts +580 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +250 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/webhooks/listener.d.ts +17 -0
- package/dist/webhooks/listener.d.ts.map +1 -0
- package/dist/webhooks/listener.js +140 -0
- package/dist/webhooks/listener.js.map +1 -0
- package/dist/webhooks/ngrok.d.ts +8 -0
- package/dist/webhooks/ngrok.d.ts.map +1 -0
- package/dist/webhooks/ngrok.js +50 -0
- package/dist/webhooks/ngrok.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase.d.ts","sourceRoot":"","sources":["../../src/connections/firebase.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,gBAAgB,CAAC;AAmDnC,wBAAsB,cAAc,IAAI,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAqB7D"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import admin from "firebase-admin";
|
|
2
|
+
import { readFile } from "fs/promises";
|
|
3
|
+
import { GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
|
|
4
|
+
import { config } from "../config.js";
|
|
5
|
+
import { getSecretsManagerClient } from "../utils/secrets.js";
|
|
6
|
+
let firebaseApp = null;
|
|
7
|
+
let firebaseInitializationPromise = null;
|
|
8
|
+
async function getFirebaseCredentials() {
|
|
9
|
+
const secretName = config.awsFirebaseSecretName;
|
|
10
|
+
if (secretName) {
|
|
11
|
+
try {
|
|
12
|
+
const client = getSecretsManagerClient();
|
|
13
|
+
const command = new GetSecretValueCommand({ SecretId: secretName });
|
|
14
|
+
const response = await client.send(command);
|
|
15
|
+
if (!response.SecretString) {
|
|
16
|
+
throw new Error(`Secret ${secretName} exists but has no SecretString value`);
|
|
17
|
+
}
|
|
18
|
+
return JSON.parse(response.SecretString);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
throw new Error(`Failed to retrieve Firebase credentials from AWS Secrets Manager (${secretName}): ${error instanceof Error ? error.message : String(error)}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const serviceAccountKey = config.firebaseServiceAccountKey;
|
|
25
|
+
if (serviceAccountKey) {
|
|
26
|
+
try {
|
|
27
|
+
// Check if it's a JSON string
|
|
28
|
+
if (serviceAccountKey.trim().startsWith("{")) {
|
|
29
|
+
return JSON.parse(serviceAccountKey);
|
|
30
|
+
}
|
|
31
|
+
// Otherwise treat as a path
|
|
32
|
+
const content = await readFile(serviceAccountKey, "utf8");
|
|
33
|
+
return JSON.parse(content);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new Error(`Failed to parse FIREBASE_SERVICE_ACCOUNT_KEY: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
throw new Error("Firebase credentials not configured. Set AWS_FIREBASE_SECRET_NAME or FIREBASE_SERVICE_ACCOUNT_KEY.");
|
|
40
|
+
}
|
|
41
|
+
export async function getFirebaseApp() {
|
|
42
|
+
if (firebaseApp)
|
|
43
|
+
return firebaseApp;
|
|
44
|
+
if (firebaseInitializationPromise)
|
|
45
|
+
return firebaseInitializationPromise;
|
|
46
|
+
firebaseInitializationPromise = (async () => {
|
|
47
|
+
try {
|
|
48
|
+
const credentials = await getFirebaseCredentials();
|
|
49
|
+
firebaseApp = admin.initializeApp({
|
|
50
|
+
credential: admin.credential.cert(credentials),
|
|
51
|
+
projectId: config.firebaseProjectId || credentials.project_id,
|
|
52
|
+
});
|
|
53
|
+
return firebaseApp;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
firebaseInitializationPromise = null;
|
|
57
|
+
throw new Error(`Failed to initialize Firebase: ${error instanceof Error ? error.message : String(error)}`);
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
return firebaseInitializationPromise;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=firebase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firebase.js","sourceRoot":"","sources":["../../src/connections/firebase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salesforce.d.ts","sourceRoot":"","sources":["../../src/connections/salesforce.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAyB,MAAM,aAAa,CAAC;AAuR/E,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAyF7E"}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { Connection } from "jsforce";
|
|
2
|
+
import jwt from "jsonwebtoken";
|
|
3
|
+
import { GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
|
|
4
|
+
import { config } from "../config.js";
|
|
5
|
+
import { getSecretsManagerClient } from "../utils/secrets.js";
|
|
6
|
+
import { getSecretsProvider } from "../utils/secrets/provider.js";
|
|
7
|
+
let salesforceConnection = null;
|
|
8
|
+
let salesforceConnectionPromise = null;
|
|
9
|
+
async function getSalesforceCredentials() {
|
|
10
|
+
// Option 1: Check if secrets provider is configured (new flexible approach)
|
|
11
|
+
const secretName = config.awsSalesforceSecretName;
|
|
12
|
+
const secretsProviderType = process.env.SECRETS_PROVIDER;
|
|
13
|
+
if (secretName && secretsProviderType && secretsProviderType.toLowerCase() !== "env") {
|
|
14
|
+
try {
|
|
15
|
+
// Use the pluggable secrets provider
|
|
16
|
+
const provider = getSecretsProvider();
|
|
17
|
+
const secretString = await provider.getSecret(secretName);
|
|
18
|
+
// Parse the secret (can be JSON string or plain text)
|
|
19
|
+
let secretData;
|
|
20
|
+
try {
|
|
21
|
+
secretData = JSON.parse(secretString);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// If not JSON, treat as plain text and try to parse as key=value pairs
|
|
25
|
+
const lines = secretString.split("\n");
|
|
26
|
+
secretData = {};
|
|
27
|
+
for (const line of lines) {
|
|
28
|
+
const [key, ...valueParts] = line.split("=");
|
|
29
|
+
if (key && valueParts.length > 0) {
|
|
30
|
+
secretData[key.trim()] = valueParts.join("=").trim();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Check for JWT authentication (client_id, username, private_key)
|
|
35
|
+
const clientId = secretData.client_id ||
|
|
36
|
+
secretData.CLIENT_ID ||
|
|
37
|
+
secretData.clientId ||
|
|
38
|
+
secretData.CLIENTID;
|
|
39
|
+
const username = secretData.username ||
|
|
40
|
+
secretData.USERNAME ||
|
|
41
|
+
secretData.SALESFORCE_USERNAME ||
|
|
42
|
+
secretData.user;
|
|
43
|
+
const privateKey = secretData.private_key ||
|
|
44
|
+
secretData.PRIVATE_KEY ||
|
|
45
|
+
secretData.privateKey ||
|
|
46
|
+
secretData.PRIVATEKEY;
|
|
47
|
+
if (clientId && username && privateKey) {
|
|
48
|
+
// JWT authentication
|
|
49
|
+
// Format private key: handle escaped newlines, space-separated format, and ensure proper PEM format
|
|
50
|
+
let formattedPrivateKey = privateKey
|
|
51
|
+
.replace(/\\n/g, "\n") // Replace escaped newlines (from JSON)
|
|
52
|
+
.replace(/\\r/g, "") // Remove escaped carriage returns
|
|
53
|
+
.trim();
|
|
54
|
+
// If key is still a single line (no actual newlines), it might be space-separated
|
|
55
|
+
// Format: "-----BEGIN PRIVATE KEY----- <base64> -----END PRIVATE KEY-----"
|
|
56
|
+
if (!formattedPrivateKey.includes("\n")) {
|
|
57
|
+
const match = formattedPrivateKey.match(/^(-----BEGIN PRIVATE KEY-----) (.+) (-----END PRIVATE KEY-----)$/);
|
|
58
|
+
if (match) {
|
|
59
|
+
const [, header, body, footer] = match;
|
|
60
|
+
// Split body into 64-character lines (standard PEM format)
|
|
61
|
+
const lines = [];
|
|
62
|
+
for (let i = 0; i < body.length; i += 64) {
|
|
63
|
+
lines.push(body.substring(i, i + 64));
|
|
64
|
+
}
|
|
65
|
+
formattedPrivateKey = `${header}\n${lines.join("\n")}\n${footer}`;
|
|
66
|
+
}
|
|
67
|
+
else if (!formattedPrivateKey.includes("BEGIN")) {
|
|
68
|
+
// If key doesn't have PEM headers, add them (assuming it's just the key content)
|
|
69
|
+
const keyContent = formattedPrivateKey.replace(/\s/g, "");
|
|
70
|
+
formattedPrivateKey = `-----BEGIN PRIVATE KEY-----\n${keyContent}\n-----END PRIVATE KEY-----`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
type: "jwt",
|
|
75
|
+
clientId,
|
|
76
|
+
username,
|
|
77
|
+
privateKey: formattedPrivateKey,
|
|
78
|
+
loginUrl: secretData.loginUrl || secretData.LOGIN_URL || config.salesforceLoginUrl,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// Fallback to username/password authentication
|
|
82
|
+
const password = secretData.password ||
|
|
83
|
+
secretData.PASSWORD ||
|
|
84
|
+
secretData.SALESFORCE_PASSWORD ||
|
|
85
|
+
secretData.pass;
|
|
86
|
+
const securityToken = secretData.securityToken ||
|
|
87
|
+
secretData.SECURITY_TOKEN ||
|
|
88
|
+
secretData.SALESFORCE_TOKEN ||
|
|
89
|
+
secretData.token ||
|
|
90
|
+
secretData.TOKEN;
|
|
91
|
+
if (!username || !password || !securityToken) {
|
|
92
|
+
throw new Error(`Secret ${secretName} must contain either: (1) client_id, username, and private_key for JWT authentication, or (2) username, password, and securityToken for username/password authentication. Found keys: ${Object.keys(secretData).join(", ")}`);
|
|
93
|
+
}
|
|
94
|
+
return { type: "username_password", username, password, securityToken };
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
throw new Error(`Failed to retrieve Salesforce credentials from secrets provider (${secretName}): ${error instanceof Error ? error.message : String(error)}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Option 2: Legacy AWS Secrets Manager (if AWS_SALESFORCE_SECRET_NAME is set but SECRETS_PROVIDER is not)
|
|
101
|
+
if (secretName && (!secretsProviderType || secretsProviderType.toLowerCase() === "env")) {
|
|
102
|
+
try {
|
|
103
|
+
const client = getSecretsManagerClient();
|
|
104
|
+
const command = new GetSecretValueCommand({ SecretId: secretName });
|
|
105
|
+
const response = await client.send(command);
|
|
106
|
+
if (!response.SecretString) {
|
|
107
|
+
throw new Error(`Secret ${secretName} exists but has no SecretString value`);
|
|
108
|
+
}
|
|
109
|
+
// Parse the secret (can be JSON string or plain text)
|
|
110
|
+
let secretData;
|
|
111
|
+
try {
|
|
112
|
+
secretData = JSON.parse(response.SecretString);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// If not JSON, treat as plain text and try to parse as key=value pairs
|
|
116
|
+
const lines = response.SecretString.split("\n");
|
|
117
|
+
secretData = {};
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
const [key, ...valueParts] = line.split("=");
|
|
120
|
+
if (key && valueParts.length > 0) {
|
|
121
|
+
secretData[key.trim()] = valueParts.join("=").trim();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Check for JWT authentication (client_id, username, private_key)
|
|
126
|
+
const clientId = secretData.client_id ||
|
|
127
|
+
secretData.CLIENT_ID ||
|
|
128
|
+
secretData.clientId ||
|
|
129
|
+
secretData.CLIENTID;
|
|
130
|
+
const username = secretData.username ||
|
|
131
|
+
secretData.USERNAME ||
|
|
132
|
+
secretData.SALESFORCE_USERNAME ||
|
|
133
|
+
secretData.user;
|
|
134
|
+
const privateKey = secretData.private_key ||
|
|
135
|
+
secretData.PRIVATE_KEY ||
|
|
136
|
+
secretData.privateKey ||
|
|
137
|
+
secretData.PRIVATEKEY;
|
|
138
|
+
if (clientId && username && privateKey) {
|
|
139
|
+
// JWT authentication
|
|
140
|
+
// Format private key: handle escaped newlines, space-separated format, and ensure proper PEM format
|
|
141
|
+
let formattedPrivateKey = privateKey
|
|
142
|
+
.replace(/\\n/g, "\n") // Replace escaped newlines (from JSON)
|
|
143
|
+
.replace(/\\r/g, "") // Remove escaped carriage returns
|
|
144
|
+
.trim();
|
|
145
|
+
// If key is still a single line (no actual newlines), it might be space-separated
|
|
146
|
+
// Format: "-----BEGIN PRIVATE KEY----- <base64> -----END PRIVATE KEY-----"
|
|
147
|
+
if (!formattedPrivateKey.includes("\n")) {
|
|
148
|
+
const match = formattedPrivateKey.match(/^(-----BEGIN PRIVATE KEY-----) (.+) (-----END PRIVATE KEY-----)$/);
|
|
149
|
+
if (match) {
|
|
150
|
+
const [, header, body, footer] = match;
|
|
151
|
+
// Split body into 64-character lines (standard PEM format)
|
|
152
|
+
const lines = [];
|
|
153
|
+
for (let i = 0; i < body.length; i += 64) {
|
|
154
|
+
lines.push(body.substring(i, i + 64));
|
|
155
|
+
}
|
|
156
|
+
formattedPrivateKey = `${header}\n${lines.join("\n")}\n${footer}`;
|
|
157
|
+
}
|
|
158
|
+
else if (!formattedPrivateKey.includes("BEGIN")) {
|
|
159
|
+
// If key doesn't have PEM headers, add them (assuming it's just the key content)
|
|
160
|
+
const keyContent = formattedPrivateKey.replace(/\s/g, "");
|
|
161
|
+
formattedPrivateKey = `-----BEGIN PRIVATE KEY-----\n${keyContent}\n-----END PRIVATE KEY-----`;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
type: "jwt",
|
|
166
|
+
clientId,
|
|
167
|
+
username,
|
|
168
|
+
privateKey: formattedPrivateKey,
|
|
169
|
+
loginUrl: secretData.loginUrl || secretData.LOGIN_URL || config.salesforceLoginUrl,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
// Fallback to username/password authentication
|
|
173
|
+
const password = secretData.password ||
|
|
174
|
+
secretData.PASSWORD ||
|
|
175
|
+
secretData.SALESFORCE_PASSWORD ||
|
|
176
|
+
secretData.pass;
|
|
177
|
+
const securityToken = secretData.securityToken ||
|
|
178
|
+
secretData.SECURITY_TOKEN ||
|
|
179
|
+
secretData.SALESFORCE_TOKEN ||
|
|
180
|
+
secretData.token ||
|
|
181
|
+
secretData.TOKEN;
|
|
182
|
+
if (!username || !password || !securityToken) {
|
|
183
|
+
throw new Error(`Secret ${secretName} must contain either: (1) client_id, username, and private_key for JWT authentication, or (2) username, password, and securityToken for username/password authentication. Found keys: ${Object.keys(secretData).join(", ")}`);
|
|
184
|
+
}
|
|
185
|
+
return { type: "username_password", username, password, securityToken };
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
throw new Error(`Failed to retrieve Salesforce credentials from AWS Secrets Manager (${secretName}): ${error instanceof Error ? error.message : String(error)}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Option 3: Fallback to environment variables
|
|
192
|
+
// Check for JWT authentication first
|
|
193
|
+
const clientId = config.salesforceClientId;
|
|
194
|
+
const username = config.salesforceUsername;
|
|
195
|
+
const privateKey = config.salesforcePrivateKey;
|
|
196
|
+
if (clientId && username && privateKey) {
|
|
197
|
+
// Format private key: handle escaped newlines, space-separated format, and ensure proper PEM format
|
|
198
|
+
let formattedPrivateKey = privateKey
|
|
199
|
+
.replace(/\\n/g, "\n") // Replace escaped newlines (from JSON)
|
|
200
|
+
.replace(/\\r/g, "") // Remove escaped carriage returns
|
|
201
|
+
.trim();
|
|
202
|
+
// If key is still a single line (no actual newlines), it might be space-separated
|
|
203
|
+
// Format: "-----BEGIN PRIVATE KEY----- <base64> -----END PRIVATE KEY-----"
|
|
204
|
+
if (!formattedPrivateKey.includes("\n")) {
|
|
205
|
+
const match = formattedPrivateKey.match(/^(-----BEGIN PRIVATE KEY-----) (.+) (-----END PRIVATE KEY-----)$/);
|
|
206
|
+
if (match) {
|
|
207
|
+
const [, header, body, footer] = match;
|
|
208
|
+
// Split body into 64-character lines (standard PEM format)
|
|
209
|
+
const lines = [];
|
|
210
|
+
for (let i = 0; i < body.length; i += 64) {
|
|
211
|
+
lines.push(body.substring(i, i + 64));
|
|
212
|
+
}
|
|
213
|
+
formattedPrivateKey = `${header}\n${lines.join("\n")}\n${footer}`;
|
|
214
|
+
}
|
|
215
|
+
else if (!formattedPrivateKey.includes("BEGIN")) {
|
|
216
|
+
// If key doesn't have PEM headers, add them (assuming it's just the key content)
|
|
217
|
+
const keyContent = formattedPrivateKey.replace(/\s/g, "");
|
|
218
|
+
formattedPrivateKey = `-----BEGIN PRIVATE KEY-----\n${keyContent}\n-----END PRIVATE KEY-----`;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
type: "jwt",
|
|
223
|
+
clientId,
|
|
224
|
+
username,
|
|
225
|
+
privateKey: formattedPrivateKey,
|
|
226
|
+
loginUrl: config.salesforceLoginUrl,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// Fallback to username/password
|
|
230
|
+
const password = config.salesforcePassword;
|
|
231
|
+
const securityToken = config.salesforceToken;
|
|
232
|
+
if (!username || !password || !securityToken) {
|
|
233
|
+
throw new Error("Salesforce credentials not configured. Either set AWS_SALESFORCE_SECRET_NAME for AWS Secrets Manager, or set SALESFORCE_USERNAME, SALESFORCE_PASSWORD, and SALESFORCE_TOKEN (or SALESFORCE_CLIENT_ID, SALESFORCE_USERNAME, SALESFORCE_PRIVATE_KEY for JWT) environment variables.");
|
|
234
|
+
}
|
|
235
|
+
return { type: "username_password", username, password, securityToken };
|
|
236
|
+
}
|
|
237
|
+
export async function getSalesforceConnection() {
|
|
238
|
+
// Return existing connection if available
|
|
239
|
+
if (salesforceConnection && salesforceConnection.accessToken) {
|
|
240
|
+
return salesforceConnection;
|
|
241
|
+
}
|
|
242
|
+
// Return existing promise if connection is in progress
|
|
243
|
+
if (salesforceConnectionPromise) {
|
|
244
|
+
return salesforceConnectionPromise;
|
|
245
|
+
}
|
|
246
|
+
// Get credentials (from AWS Secrets Manager or environment variables)
|
|
247
|
+
const credentials = await getSalesforceCredentials();
|
|
248
|
+
salesforceConnectionPromise = (async () => {
|
|
249
|
+
try {
|
|
250
|
+
if (credentials.type === "jwt") {
|
|
251
|
+
// JWT Bearer Token Flow
|
|
252
|
+
const loginUrl = credentials.loginUrl || "https://login.salesforce.com";
|
|
253
|
+
// Create JWT assertion
|
|
254
|
+
const now = Math.floor(Date.now() / 1000);
|
|
255
|
+
const assertion = jwt.sign({
|
|
256
|
+
iss: credentials.clientId,
|
|
257
|
+
sub: credentials.username,
|
|
258
|
+
aud: loginUrl,
|
|
259
|
+
exp: now + 300, // 5 minutes
|
|
260
|
+
iat: now,
|
|
261
|
+
}, credentials.privateKey, { algorithm: "RS256" });
|
|
262
|
+
// Exchange JWT for access token
|
|
263
|
+
const tokenUrl = `${loginUrl}/services/oauth2/token`;
|
|
264
|
+
const response = await fetch(tokenUrl, {
|
|
265
|
+
method: "POST",
|
|
266
|
+
headers: {
|
|
267
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
268
|
+
},
|
|
269
|
+
body: new URLSearchParams({
|
|
270
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
271
|
+
assertion: assertion,
|
|
272
|
+
}),
|
|
273
|
+
});
|
|
274
|
+
if (!response.ok) {
|
|
275
|
+
const errorText = await response.text();
|
|
276
|
+
throw new Error(`JWT authentication failed: ${response.status} ${errorText}`);
|
|
277
|
+
}
|
|
278
|
+
const tokenData = (await response.json());
|
|
279
|
+
// Create new connection with access token
|
|
280
|
+
const conn = new Connection({
|
|
281
|
+
accessToken: tokenData.access_token,
|
|
282
|
+
instanceUrl: tokenData.instance_url,
|
|
283
|
+
});
|
|
284
|
+
salesforceConnection = conn;
|
|
285
|
+
salesforceConnectionPromise = null;
|
|
286
|
+
return conn;
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
// Username/Password authentication
|
|
290
|
+
const loginUrl = config.salesforceLoginUrl || "https://login.salesforce.com";
|
|
291
|
+
const conn = new Connection({
|
|
292
|
+
loginUrl,
|
|
293
|
+
});
|
|
294
|
+
await conn.login(credentials.username, credentials.password + credentials.securityToken);
|
|
295
|
+
salesforceConnection = conn;
|
|
296
|
+
salesforceConnectionPromise = null;
|
|
297
|
+
return conn;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
salesforceConnectionPromise = null;
|
|
302
|
+
throw new Error(`Failed to connect to Salesforce: ${error instanceof Error ? error.message : String(error)}`);
|
|
303
|
+
}
|
|
304
|
+
})();
|
|
305
|
+
return salesforceConnectionPromise;
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=salesforce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"salesforce.js","sourceRoot":"","sources":["../../src/connections/salesforce.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { createServer } from "./server.js";
|
|
5
|
+
import { config } from "./config.js";
|
|
6
|
+
import { getToolDefinitions } from "./tools/definitions.js";
|
|
7
|
+
import { handleToolCall } from "./tools/index.js";
|
|
8
|
+
import { setupPaymentContextWatcher, setupFailedPaymentPolling, getPaymentContextResource, } from "./resources/payment-context.js";
|
|
9
|
+
import { startWebhookServer, getWebhookUrl } from "./webhooks/listener.js";
|
|
10
|
+
import { startNgrokTunnel } from "./webhooks/ngrok.js";
|
|
11
|
+
import { logger } from "./utils/logger.js";
|
|
12
|
+
// Initialize config (triggers SDK setup)
|
|
13
|
+
config;
|
|
14
|
+
// Create server instance
|
|
15
|
+
const server = createServer();
|
|
16
|
+
// Register tool definitions
|
|
17
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
18
|
+
return {
|
|
19
|
+
tools: getToolDefinitions(),
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
// Register tool execution handler
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
24
|
+
const { name, arguments: args } = request.params;
|
|
25
|
+
return await handleToolCall(name, args);
|
|
26
|
+
});
|
|
27
|
+
// Register resource handlers (if enabled)
|
|
28
|
+
if (config.enableResources) {
|
|
29
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
30
|
+
return {
|
|
31
|
+
resources: [
|
|
32
|
+
{
|
|
33
|
+
uri: "lemonsqueezy://payment-context",
|
|
34
|
+
name: "Current Payment Context",
|
|
35
|
+
description: "Recent payment events, failed payments, and important updates. Automatically updated from webhooks or polling.",
|
|
36
|
+
mimeType: "application/json",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
42
|
+
const { uri } = request.params;
|
|
43
|
+
if (uri === "lemonsqueezy://payment-context") {
|
|
44
|
+
const context = getPaymentContextResource();
|
|
45
|
+
return {
|
|
46
|
+
contents: [
|
|
47
|
+
{
|
|
48
|
+
uri,
|
|
49
|
+
mimeType: "application/json",
|
|
50
|
+
text: JSON.stringify(context, null, 2),
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
56
|
+
});
|
|
57
|
+
// Setup resource watchers/polling (legacy file watcher - deprecated in favor of webhook server)
|
|
58
|
+
if (config.webhookLogPath) {
|
|
59
|
+
setupPaymentContextWatcher();
|
|
60
|
+
}
|
|
61
|
+
setupFailedPaymentPolling();
|
|
62
|
+
}
|
|
63
|
+
// Start webhook server if resources are enabled
|
|
64
|
+
if (config.enableResources) {
|
|
65
|
+
startWebhookServer()
|
|
66
|
+
.then(async (server) => {
|
|
67
|
+
const webhookUrl = getWebhookUrl();
|
|
68
|
+
logger.info({ webhookUrl }, "Webhook server started");
|
|
69
|
+
// Start ngrok tunnel if enabled
|
|
70
|
+
if (config.enableNgrok) {
|
|
71
|
+
try {
|
|
72
|
+
const tunnel = await startNgrokTunnel(config.webhookPort);
|
|
73
|
+
logger.info({ publicUrl: tunnel.publicUrl, localUrl: tunnel.localUrl }, "Ngrok tunnel established");
|
|
74
|
+
logger.info({ webhookUrl: `${tunnel.publicUrl}/webhooks` }, "Configure this URL in Lemon Squeezy");
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
logger.warn({ error }, "Ngrok failed, using local URL only");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
logger.info({ webhookUrl }, "To expose publicly, set ENABLE_NGROK=true");
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.catch((error) => {
|
|
85
|
+
logger.error({ error }, "Failed to start webhook server");
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// Connect transport and start server
|
|
89
|
+
async function main() {
|
|
90
|
+
const transport = new StdioServerTransport();
|
|
91
|
+
await server.connect(transport);
|
|
92
|
+
logger.info("Lemon Squeezy MCP Server running on stdio");
|
|
93
|
+
if (config.enableResources) {
|
|
94
|
+
logger.info("Proactive context enabled");
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
main().catch((error) => {
|
|
98
|
+
logger.fatal({ error }, "Fatal error");
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { PaymentEvent } from "../types.js";
|
|
2
|
+
export declare function addPaymentEvent(event: PaymentEvent): void;
|
|
3
|
+
export declare function setupPaymentContextWatcher(): void;
|
|
4
|
+
export declare function setupFailedPaymentPolling(): void;
|
|
5
|
+
export declare function getPaymentContextResource(): {
|
|
6
|
+
lastUpdated: string;
|
|
7
|
+
totalEvents: number;
|
|
8
|
+
events: PaymentEvent[];
|
|
9
|
+
summary: {
|
|
10
|
+
failedPayments: number;
|
|
11
|
+
recentActivity: string[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=payment-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-context.d.ts","sourceRoot":"","sources":["../../src/resources/payment-context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMhD,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,QAKlD;AAED,wBAAgB,0BAA0B,SAmDzC;AAED,wBAAgB,yBAAyB,SAyCxC;AAED,wBAAgB,yBAAyB;;;;;;;;EAYxC"}
|