@hasna/connectors 0.7.0 → 0.7.2
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/bin/index.js +39 -39
- package/bin/mcp.js +1 -1
- package/bin/serve.js +38 -38
- package/connectors/connect-gmail/src/cli/index.ts +43 -2
- package/package.json +1 -1
package/bin/index.js
CHANGED
|
@@ -5254,13 +5254,38 @@ function getAllConnectorsWithAuth() {
|
|
|
5254
5254
|
};
|
|
5255
5255
|
});
|
|
5256
5256
|
}
|
|
5257
|
-
function
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5257
|
+
function oauthPage(type, title, message, hint, extra) {
|
|
5258
|
+
const icons = {
|
|
5259
|
+
success: `<div class="icon icon-success"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg></div>`,
|
|
5260
|
+
error: `<div class="icon icon-error"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg></div>`,
|
|
5261
|
+
warning: `<div class="icon icon-warning"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg></div>`
|
|
5262
|
+
};
|
|
5263
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
5264
|
+
<style>
|
|
5265
|
+
* { margin:0; padding:0; box-sizing:border-box; }
|
|
5266
|
+
body { font-family:ui-sans-serif,system-ui,-apple-system,sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; background:#09090b; color:#fafafa; }
|
|
5267
|
+
.card { background:#18181b; border:1px solid #27272a; border-radius:12px; padding:48px 40px; max-width:420px; width:100%; text-align:center; }
|
|
5268
|
+
.icon { width:64px; height:64px; border-radius:50%; display:flex; align-items:center; justify-content:center; margin:0 auto 24px; }
|
|
5269
|
+
.icon svg { width:32px; height:32px; }
|
|
5270
|
+
.icon-success { background:#052e16; }
|
|
5271
|
+
.icon-success svg { color:#22c55e; }
|
|
5272
|
+
.icon-error { background:#450a0a; }
|
|
5273
|
+
.icon-error svg { color:#ef4444; }
|
|
5274
|
+
.icon-warning { background:#422006; }
|
|
5275
|
+
.icon-warning svg { color:#eab308; }
|
|
5276
|
+
h2 { font-size:24px; font-weight:600; margin-bottom:8px; color:#fafafa; }
|
|
5277
|
+
.subtitle { color:#a1a1aa; font-size:15px; margin-top:12px; line-height:1.5; }
|
|
5278
|
+
.connector { color:#22c55e; font-weight:600; }
|
|
5279
|
+
.hint { color:#52525b; font-size:13px; margin-top:24px; }
|
|
5280
|
+
code, .cmd { background:#27272a; color:#e4e4e7; padding:2px 8px; border-radius:4px; font-family:ui-monospace,monospace; font-size:12px; }
|
|
5281
|
+
</style>
|
|
5282
|
+
</head><body>
|
|
5283
|
+
<div class="card">
|
|
5284
|
+
${icons[type]}
|
|
5285
|
+
<h2>${title}</h2>
|
|
5286
|
+
<p class="subtitle">${message}</p>
|
|
5287
|
+
${hint ? `<p class="hint">${hint}</p>` : ""}
|
|
5288
|
+
${extra?.script ? `<script>${extra.script}</script>` : ""}
|
|
5264
5289
|
</div>
|
|
5265
5290
|
</body></html>`;
|
|
5266
5291
|
}
|
|
@@ -5586,7 +5611,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
5586
5611
|
const redirectUri = `http://localhost:${port}/oauth/${name}/callback`;
|
|
5587
5612
|
const authUrl = getOAuthStartUrl(name, redirectUri);
|
|
5588
5613
|
if (!authUrl) {
|
|
5589
|
-
return htmlResponse(
|
|
5614
|
+
return htmlResponse(oauthPage("warning", "OAuth Not Available", `No OAuth client credentials found for <span class="connector">${name}</span>.`, `Set up credentials at <code>~/.connectors/connect-${name}/credentials.json</code>`));
|
|
5590
5615
|
}
|
|
5591
5616
|
return Response.redirect(authUrl, 302);
|
|
5592
5617
|
}
|
|
@@ -5597,46 +5622,21 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
5597
5622
|
const error = url2.searchParams.get("error");
|
|
5598
5623
|
const state = url2.searchParams.get("state");
|
|
5599
5624
|
if (error) {
|
|
5600
|
-
return htmlResponse(
|
|
5625
|
+
return htmlResponse(oauthPage("error", "Authentication Failed", error, "You can close this window."));
|
|
5601
5626
|
}
|
|
5602
5627
|
if (!validateOAuthState(state, name)) {
|
|
5603
|
-
return htmlResponse(
|
|
5628
|
+
return htmlResponse(oauthPage("error", "Invalid State", "CSRF validation failed. The OAuth state parameter is missing or invalid.", "Please try again from the dashboard."));
|
|
5604
5629
|
}
|
|
5605
5630
|
if (!code) {
|
|
5606
|
-
return htmlResponse(
|
|
5631
|
+
return htmlResponse(oauthPage("error", "Missing Authorization Code", "No code received from the OAuth provider.", "You can close this window and try again."));
|
|
5607
5632
|
}
|
|
5608
5633
|
try {
|
|
5609
5634
|
const redirectUri = `http://localhost:${port}/oauth/${name}/callback`;
|
|
5610
5635
|
await exchangeOAuthCode(name, code, redirectUri);
|
|
5611
5636
|
logActivity("oauth_connected", name);
|
|
5612
|
-
return htmlResponse(
|
|
5613
|
-
<style>
|
|
5614
|
-
* { margin:0; padding:0; box-sizing:border-box; }
|
|
5615
|
-
body { font-family:ui-sans-serif,system-ui,-apple-system,sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; background:#09090b; color:#fafafa; }
|
|
5616
|
-
.card { background:#18181b; border:1px solid #27272a; border-radius:12px; padding:48px 40px; max-width:420px; text-align:center; }
|
|
5617
|
-
.icon { width:64px; height:64px; border-radius:50%; background:#052e16; display:flex; align-items:center; justify-content:center; margin:0 auto 24px; }
|
|
5618
|
-
.icon svg { width:32px; height:32px; color:#22c55e; }
|
|
5619
|
-
h2 { font-size:24px; font-weight:600; margin-bottom:8px; color:#fafafa; }
|
|
5620
|
-
.connector { color:#22c55e; font-weight:600; }
|
|
5621
|
-
.subtitle { color:#a1a1aa; font-size:15px; margin-top:12px; line-height:1.5; }
|
|
5622
|
-
.hint { color:#52525b; font-size:13px; margin-top:24px; }
|
|
5623
|
-
.cmd { background:#27272a; color:#e4e4e7; padding:2px 8px; border-radius:4px; font-family:ui-monospace,monospace; font-size:12px; }
|
|
5624
|
-
</style>
|
|
5625
|
-
</head><body>
|
|
5626
|
-
<div class="card">
|
|
5627
|
-
<div class="icon"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg></div>
|
|
5628
|
-
<h2>Connected!</h2>
|
|
5629
|
-
<p class="subtitle"><span class="connector">${name}</span> is now authenticated and ready to use.</p>
|
|
5630
|
-
<p class="hint">You can close this window.<br>Try <span class="cmd">connectors run ${name} --help</span></p>
|
|
5631
|
-
<script>
|
|
5632
|
-
if (window.opener) {
|
|
5633
|
-
window.opener.postMessage({ type: 'oauth-complete', connector: '${name}' }, 'http://localhost:${port}');
|
|
5634
|
-
}
|
|
5635
|
-
</script>
|
|
5636
|
-
</div>
|
|
5637
|
-
</body></html>`);
|
|
5637
|
+
return htmlResponse(oauthPage("success", "Connected!", `<span class="connector">${name}</span> is now authenticated and ready to use.`, `You can close this window.<br>Try <code>connectors run ${name} --help</code>`, { script: `if(window.opener){window.opener.postMessage({type:'oauth-complete',connector:'${name}'},'http://localhost:${port}');}` }));
|
|
5638
5638
|
} catch (e) {
|
|
5639
|
-
return htmlResponse(
|
|
5639
|
+
return htmlResponse(oauthPage("error", "Authentication Failed", e instanceof Error ? e.message : "Unknown error", "You can close this window."));
|
|
5640
5640
|
}
|
|
5641
5641
|
}
|
|
5642
5642
|
if (method === "OPTIONS") {
|
|
@@ -7545,7 +7545,7 @@ var PRESETS = {
|
|
|
7545
7545
|
commerce: { description: "Commerce and finance", connectors: ["stripe", "shopify", "revolut", "mercury", "pandadoc"] }
|
|
7546
7546
|
};
|
|
7547
7547
|
var program2 = new Command;
|
|
7548
|
-
program2.name("connectors").description("Install API connectors for your project").version("0.7.
|
|
7548
|
+
program2.name("connectors").description("Install API connectors for your project").version("0.7.2").enablePositionalOptions();
|
|
7549
7549
|
program2.command("interactive", { isDefault: true }).alias("i").description("Interactive connector browser").action(() => {
|
|
7550
7550
|
if (!isTTY) {
|
|
7551
7551
|
console.log(`Non-interactive environment detected. Use a subcommand:
|
package/bin/mcp.js
CHANGED
|
@@ -21013,7 +21013,7 @@ async function getConnectorCommandHelp(name, command) {
|
|
|
21013
21013
|
loadConnectorVersions();
|
|
21014
21014
|
var server = new McpServer({
|
|
21015
21015
|
name: "connectors",
|
|
21016
|
-
version: "0.7.
|
|
21016
|
+
version: "0.7.2"
|
|
21017
21017
|
});
|
|
21018
21018
|
server.registerTool("search_connectors", {
|
|
21019
21019
|
title: "Search Connectors",
|
package/bin/serve.js
CHANGED
|
@@ -1732,13 +1732,38 @@ function getAllConnectorsWithAuth() {
|
|
|
1732
1732
|
};
|
|
1733
1733
|
});
|
|
1734
1734
|
}
|
|
1735
|
-
function
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1735
|
+
function oauthPage(type, title, message, hint, extra) {
|
|
1736
|
+
const icons = {
|
|
1737
|
+
success: `<div class="icon icon-success"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg></div>`,
|
|
1738
|
+
error: `<div class="icon icon-error"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg></div>`,
|
|
1739
|
+
warning: `<div class="icon icon-warning"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg></div>`
|
|
1740
|
+
};
|
|
1741
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
1742
|
+
<style>
|
|
1743
|
+
* { margin:0; padding:0; box-sizing:border-box; }
|
|
1744
|
+
body { font-family:ui-sans-serif,system-ui,-apple-system,sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; background:#09090b; color:#fafafa; }
|
|
1745
|
+
.card { background:#18181b; border:1px solid #27272a; border-radius:12px; padding:48px 40px; max-width:420px; width:100%; text-align:center; }
|
|
1746
|
+
.icon { width:64px; height:64px; border-radius:50%; display:flex; align-items:center; justify-content:center; margin:0 auto 24px; }
|
|
1747
|
+
.icon svg { width:32px; height:32px; }
|
|
1748
|
+
.icon-success { background:#052e16; }
|
|
1749
|
+
.icon-success svg { color:#22c55e; }
|
|
1750
|
+
.icon-error { background:#450a0a; }
|
|
1751
|
+
.icon-error svg { color:#ef4444; }
|
|
1752
|
+
.icon-warning { background:#422006; }
|
|
1753
|
+
.icon-warning svg { color:#eab308; }
|
|
1754
|
+
h2 { font-size:24px; font-weight:600; margin-bottom:8px; color:#fafafa; }
|
|
1755
|
+
.subtitle { color:#a1a1aa; font-size:15px; margin-top:12px; line-height:1.5; }
|
|
1756
|
+
.connector { color:#22c55e; font-weight:600; }
|
|
1757
|
+
.hint { color:#52525b; font-size:13px; margin-top:24px; }
|
|
1758
|
+
code, .cmd { background:#27272a; color:#e4e4e7; padding:2px 8px; border-radius:4px; font-family:ui-monospace,monospace; font-size:12px; }
|
|
1759
|
+
</style>
|
|
1760
|
+
</head><body>
|
|
1761
|
+
<div class="card">
|
|
1762
|
+
${icons[type]}
|
|
1763
|
+
<h2>${title}</h2>
|
|
1764
|
+
<p class="subtitle">${message}</p>
|
|
1765
|
+
${hint ? `<p class="hint">${hint}</p>` : ""}
|
|
1766
|
+
${extra?.script ? `<script>${extra.script}</script>` : ""}
|
|
1742
1767
|
</div>
|
|
1743
1768
|
</body></html>`;
|
|
1744
1769
|
}
|
|
@@ -2064,7 +2089,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
2064
2089
|
const redirectUri = `http://localhost:${port}/oauth/${name}/callback`;
|
|
2065
2090
|
const authUrl = getOAuthStartUrl(name, redirectUri);
|
|
2066
2091
|
if (!authUrl) {
|
|
2067
|
-
return htmlResponse(
|
|
2092
|
+
return htmlResponse(oauthPage("warning", "OAuth Not Available", `No OAuth client credentials found for <span class="connector">${name}</span>.`, `Set up credentials at <code>~/.connectors/connect-${name}/credentials.json</code>`));
|
|
2068
2093
|
}
|
|
2069
2094
|
return Response.redirect(authUrl, 302);
|
|
2070
2095
|
}
|
|
@@ -2075,46 +2100,21 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
2075
2100
|
const error = url2.searchParams.get("error");
|
|
2076
2101
|
const state = url2.searchParams.get("state");
|
|
2077
2102
|
if (error) {
|
|
2078
|
-
return htmlResponse(
|
|
2103
|
+
return htmlResponse(oauthPage("error", "Authentication Failed", error, "You can close this window."));
|
|
2079
2104
|
}
|
|
2080
2105
|
if (!validateOAuthState(state, name)) {
|
|
2081
|
-
return htmlResponse(
|
|
2106
|
+
return htmlResponse(oauthPage("error", "Invalid State", "CSRF validation failed. The OAuth state parameter is missing or invalid.", "Please try again from the dashboard."));
|
|
2082
2107
|
}
|
|
2083
2108
|
if (!code) {
|
|
2084
|
-
return htmlResponse(
|
|
2109
|
+
return htmlResponse(oauthPage("error", "Missing Authorization Code", "No code received from the OAuth provider.", "You can close this window and try again."));
|
|
2085
2110
|
}
|
|
2086
2111
|
try {
|
|
2087
2112
|
const redirectUri = `http://localhost:${port}/oauth/${name}/callback`;
|
|
2088
2113
|
await exchangeOAuthCode(name, code, redirectUri);
|
|
2089
2114
|
logActivity("oauth_connected", name);
|
|
2090
|
-
return htmlResponse(
|
|
2091
|
-
<style>
|
|
2092
|
-
* { margin:0; padding:0; box-sizing:border-box; }
|
|
2093
|
-
body { font-family:ui-sans-serif,system-ui,-apple-system,sans-serif; display:flex; justify-content:center; align-items:center; min-height:100vh; background:#09090b; color:#fafafa; }
|
|
2094
|
-
.card { background:#18181b; border:1px solid #27272a; border-radius:12px; padding:48px 40px; max-width:420px; text-align:center; }
|
|
2095
|
-
.icon { width:64px; height:64px; border-radius:50%; background:#052e16; display:flex; align-items:center; justify-content:center; margin:0 auto 24px; }
|
|
2096
|
-
.icon svg { width:32px; height:32px; color:#22c55e; }
|
|
2097
|
-
h2 { font-size:24px; font-weight:600; margin-bottom:8px; color:#fafafa; }
|
|
2098
|
-
.connector { color:#22c55e; font-weight:600; }
|
|
2099
|
-
.subtitle { color:#a1a1aa; font-size:15px; margin-top:12px; line-height:1.5; }
|
|
2100
|
-
.hint { color:#52525b; font-size:13px; margin-top:24px; }
|
|
2101
|
-
.cmd { background:#27272a; color:#e4e4e7; padding:2px 8px; border-radius:4px; font-family:ui-monospace,monospace; font-size:12px; }
|
|
2102
|
-
</style>
|
|
2103
|
-
</head><body>
|
|
2104
|
-
<div class="card">
|
|
2105
|
-
<div class="icon"><svg fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7"/></svg></div>
|
|
2106
|
-
<h2>Connected!</h2>
|
|
2107
|
-
<p class="subtitle"><span class="connector">${name}</span> is now authenticated and ready to use.</p>
|
|
2108
|
-
<p class="hint">You can close this window.<br>Try <span class="cmd">connectors run ${name} --help</span></p>
|
|
2109
|
-
<script>
|
|
2110
|
-
if (window.opener) {
|
|
2111
|
-
window.opener.postMessage({ type: 'oauth-complete', connector: '${name}' }, 'http://localhost:${port}');
|
|
2112
|
-
}
|
|
2113
|
-
</script>
|
|
2114
|
-
</div>
|
|
2115
|
-
</body></html>`);
|
|
2115
|
+
return htmlResponse(oauthPage("success", "Connected!", `<span class="connector">${name}</span> is now authenticated and ready to use.`, `You can close this window.<br>Try <code>connectors run ${name} --help</code>`, { script: `if(window.opener){window.opener.postMessage({type:'oauth-complete',connector:'${name}'},'http://localhost:${port}');}` }));
|
|
2116
2116
|
} catch (e) {
|
|
2117
|
-
return htmlResponse(
|
|
2117
|
+
return htmlResponse(oauthPage("error", "Authentication Failed", e instanceof Error ? e.message : "Unknown error", "You can close this window."));
|
|
2118
2118
|
}
|
|
2119
2119
|
}
|
|
2120
2120
|
if (method === "OPTIONS") {
|
|
@@ -747,6 +747,7 @@ labelsCmd
|
|
|
747
747
|
type: l.type,
|
|
748
748
|
messagesTotal: l.messagesTotal,
|
|
749
749
|
messagesUnread: l.messagesUnread,
|
|
750
|
+
...(l.color ? { backgroundColor: l.color.backgroundColor, textColor: l.color.textColor } : {}),
|
|
750
751
|
}));
|
|
751
752
|
|
|
752
753
|
print(labels, getFormat(labelsCmd));
|
|
@@ -759,12 +760,52 @@ labelsCmd
|
|
|
759
760
|
labelsCmd
|
|
760
761
|
.command('create <name>')
|
|
761
762
|
.description('Create a new label')
|
|
762
|
-
.
|
|
763
|
+
.option('--bg-color <hex>', 'Background color (e.g. #16a765)')
|
|
764
|
+
.option('--text-color <hex>', 'Text color (e.g. #ffffff)')
|
|
765
|
+
.action(async (name: string, opts: { bgColor?: string; textColor?: string }) => {
|
|
763
766
|
try {
|
|
764
767
|
const gmail = requireAuth();
|
|
765
|
-
const label = await gmail.labels.create({
|
|
768
|
+
const label = await gmail.labels.create({
|
|
769
|
+
name,
|
|
770
|
+
backgroundColor: opts.bgColor,
|
|
771
|
+
textColor: opts.textColor,
|
|
772
|
+
});
|
|
766
773
|
success(`Label "${name}" created`);
|
|
767
774
|
info(`Label ID: ${label.id}`);
|
|
775
|
+
if (label.color) {
|
|
776
|
+
info(`Color: bg=${label.color.backgroundColor} text=${label.color.textColor}`);
|
|
777
|
+
}
|
|
778
|
+
} catch (err) {
|
|
779
|
+
error(String(err));
|
|
780
|
+
process.exit(1);
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
labelsCmd
|
|
785
|
+
.command('update <labelId>')
|
|
786
|
+
.description('Update a label name and/or color')
|
|
787
|
+
.option('--name <name>', 'New label name')
|
|
788
|
+
.option('--bg-color <hex>', 'Background color (e.g. #16a765)')
|
|
789
|
+
.option('--text-color <hex>', 'Text color (e.g. #ffffff)')
|
|
790
|
+
.action(async (labelId: string, opts: { name?: string; bgColor?: string; textColor?: string }) => {
|
|
791
|
+
try {
|
|
792
|
+
if (!opts.name && !opts.bgColor && !opts.textColor) {
|
|
793
|
+
error('At least one of --name, --bg-color, or --text-color is required');
|
|
794
|
+
process.exit(1);
|
|
795
|
+
}
|
|
796
|
+
const gmail = requireAuth();
|
|
797
|
+
const label = await gmail.labels.update(labelId, {
|
|
798
|
+
name: opts.name,
|
|
799
|
+
backgroundColor: opts.bgColor,
|
|
800
|
+
textColor: opts.textColor,
|
|
801
|
+
});
|
|
802
|
+
success(`Label ${labelId} updated`);
|
|
803
|
+
if (label.name) {
|
|
804
|
+
info(`Name: ${label.name}`);
|
|
805
|
+
}
|
|
806
|
+
if (label.color) {
|
|
807
|
+
info(`Color: bg=${label.color.backgroundColor} text=${label.color.textColor}`);
|
|
808
|
+
}
|
|
768
809
|
} catch (err) {
|
|
769
810
|
error(String(err));
|
|
770
811
|
process.exit(1);
|