chat-agent-toolkit 1.2.73 → 1.2.75

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.
@@ -0,0 +1,128 @@
1
+ /**
2
+ * OpenConnector Integration for OOMOL SaaS
3
+ *
4
+ * Multi-tenant connector platform for OAuth & credential management.
5
+ * Allows users to link external accounts (Gmail, Slack, GitHub, Airtable, etc.)
6
+ * securely managed by OOMOL Cloud.
7
+ *
8
+ * @module connectors
9
+ * @see {@link https://connector.oomol.com}
10
+ * @example
11
+ * ```ts
12
+ * import { ProjectConnector } from "chat-agent-toolkit/connectors";
13
+ *
14
+ * const project = new ProjectConnector({
15
+ * apiKey: process.env.OOMOL_PROJECT_API_KEY,
16
+ * });
17
+ *
18
+ * const user = project.forUser(userId);
19
+ * const oauth = await user.connect.oauth({
20
+ * service: "gmail",
21
+ * returnUri: "https://myapp.com/oauth-callback",
22
+ * });
23
+ * ```
24
+ */
25
+
26
+ // Re-export OOMOL Connector SDK types and classes
27
+ export type {
28
+ ConnectorError as OOMOLConnectorError,
29
+ ProjectConnector as OOMOLProjectConnector,
30
+ } from "@oomol-lab/connector";
31
+ export { ConnectorError, ProjectConnector } from "@oomol-lab/connector";
32
+
33
+ // Catalog data: 900+ integrated providers with OAuth/API-key support
34
+ import catalogJson from "./catalog.json";
35
+ import providerIndexJson from "./openconnector-providers-index.json";
36
+
37
+ export type CatalogProvider = {
38
+ service: string;
39
+ displayName: string;
40
+ categories: string[];
41
+ authTypes: ("oauth2" | "api_key" | "custom_credential" | "no_auth")[];
42
+ actionCount: number;
43
+ };
44
+
45
+ export type ProviderIndexEntry = CatalogProvider & {
46
+ homepageUrl?: string;
47
+ actions?: string[];
48
+ };
49
+
50
+ /**
51
+ * Lightweight provider catalog (basic info: service, display name, auth types).
52
+ * ~900 providers, fast catalog search and picker UI.
53
+ */
54
+ export const catalog: CatalogProvider[] = catalogJson as CatalogProvider[];
55
+
56
+ /**
57
+ * Detailed provider index with action lists and metadata.
58
+ * Use for deep integration: listing available actions, mapping capabilities.
59
+ */
60
+ export const providerIndex: ProviderIndexEntry[] =
61
+ providerIndexJson as ProviderIndexEntry[];
62
+
63
+ /**
64
+ * Search the catalog by service name or display name.
65
+ * @param query Search term (case-insensitive)
66
+ * @param limit Max results
67
+ * @returns Matching providers
68
+ */
69
+ export function searchCatalog(query: string, limit = 100): CatalogProvider[] {
70
+ const q = query.toLowerCase();
71
+ return catalog
72
+ .filter(
73
+ (p) =>
74
+ p.service.toLowerCase().includes(q) ||
75
+ p.displayName.toLowerCase().includes(q)
76
+ )
77
+ .slice(0, limit);
78
+ }
79
+
80
+ /**
81
+ * Get a provider by service ID.
82
+ * @param serviceId The provider's service identifier (e.g., "gmail", "slack")
83
+ * @returns Provider info or undefined
84
+ */
85
+ export function getCatalogProvider(serviceId: string): CatalogProvider | undefined {
86
+ return catalog.find((p) => p.service === serviceId);
87
+ }
88
+
89
+ /**
90
+ * Get detailed provider info including actions.
91
+ * @param serviceId The provider's service identifier
92
+ * @returns Detailed provider entry or undefined
93
+ */
94
+ export function getProviderDetails(serviceId: string): ProviderIndexEntry | undefined {
95
+ return providerIndex.find((p) => p.service === serviceId);
96
+ }
97
+
98
+ /**
99
+ * Filter catalog by authentication type.
100
+ * @param authType The auth type to filter by
101
+ * @returns Providers supporting this auth type
102
+ */
103
+ export function getCatalogByAuthType(
104
+ authType: "oauth2" | "api_key" | "custom_credential" | "no_auth"
105
+ ): CatalogProvider[] {
106
+ return catalog.filter((p) => p.authTypes.includes(authType));
107
+ }
108
+
109
+ /**
110
+ * Filter catalog by category.
111
+ * @param category The category to filter by (e.g., "Communication", "Productivity")
112
+ * @returns Providers in this category
113
+ */
114
+ export function getCatalogByCategory(category: string): CatalogProvider[] {
115
+ return catalog.filter((p) => p.categories.includes(category));
116
+ }
117
+
118
+ /**
119
+ * Get all unique categories in the catalog.
120
+ * @returns Sorted list of category names
121
+ */
122
+ export function getCatalogCategories(): string[] {
123
+ const categories = new Set<string>();
124
+ catalog.forEach((p) => p.categories.forEach((c) => categories.add(c)));
125
+ return Array.from(categories).sort();
126
+ }
127
+
128
+ export type { Express } from "express";
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Multi-tenant connector server on OOMOL Cloud (https://connector.oomol.com/v1).
3
+ *
4
+ * OOMOL hosts everything: OAuth apps, credential vault, token refresh, provider calls.
5
+ * Each of YOUR app's users links THEIR OWN accounts (Gmail, Slack, GitHub, ...) via
6
+ * ProjectConnector — the composio/pipedream "managed auth" model.
7
+ *
8
+ * Setup:
9
+ * 1. Create a project in the OOMOL console and copy its API key (oo_proj_...).
10
+ * 2. OOMOL_PROJECT_API_KEY=oo_proj_... npm start
11
+ *
12
+ * externalUserId = your app's own user id (from your auth/session layer). NEVER let the
13
+ * client pick another user's id — derive it server-side from the authenticated session.
14
+ */
15
+ import express from "express";
16
+ import { readFile } from "node:fs/promises";
17
+ import { ConnectorError, ProjectConnector } from "@oomol-lab/connector";
18
+
19
+ const PORT = process.env.PORT ?? 8787;
20
+ const APP_ORIGIN = process.env.APP_ORIGIN ?? `http://localhost:${PORT}`;
21
+
22
+ const project = new ProjectConnector({
23
+ apiKey: process.env.OOMOL_PROJECT_API_KEY ?? "oo_proj_missing",
24
+ // baseUrl defaults to OOMOL Cloud: https://connector.oomol.com/v1
25
+ });
26
+
27
+ const catalog = JSON.parse(await readFile(new URL("./catalog.json", import.meta.url), "utf8"));
28
+ const byService = new Map(catalog.map((p) => [p.service, p]));
29
+
30
+ const app = express();
31
+ app.use(express.json());
32
+
33
+ // DEMO ONLY: replace with your real session auth. Everything below trusts req.userId.
34
+ app.use((req, _res, next) => {
35
+ req.userId = req.get("x-user-id") ?? "demo_user";
36
+ next();
37
+ });
38
+
39
+ /** Provider catalog for your "add a connection" picker. */
40
+ app.get("/api/catalog", (req, res) => {
41
+ const q = (req.query.q ?? "").toString().toLowerCase();
42
+ const list = q
43
+ ? catalog.filter((p) => p.service.includes(q) || p.displayName.toLowerCase().includes(q))
44
+ : catalog;
45
+ res.json(list.slice(0, Number(req.query.limit ?? 100)));
46
+ });
47
+
48
+ /**
49
+ * Start a connection for the logged-in user.
50
+ * OAuth providers -> returns { authorizationUrl, requestId } — redirect the user there.
51
+ * API-key/custom -> pass { apiKey } or { values } — connects synchronously.
52
+ */
53
+ app.post("/api/connections", async (req, res) => {
54
+ const { service, connectionName, apiKey, values } = req.body ?? {};
55
+ const provider = byService.get(service);
56
+ if (!provider) return res.status(404).json({ error: "unknown_service", service });
57
+
58
+ const user = project.forUser(req.userId);
59
+ try {
60
+ if (provider.authTypes.includes("oauth2") && !apiKey && !values) {
61
+ const request = await user.connect.oauth({
62
+ service,
63
+ connectionName,
64
+ returnUri: `${APP_ORIGIN}/connected?service=${encodeURIComponent(service)}`,
65
+ });
66
+ // Redirect your user to authorizationUrl; poll GET /api/connections/requests/:id after.
67
+ return res.json({
68
+ pending: true,
69
+ requestId: request.id,
70
+ authorizationUrl: request.authorizationUrl,
71
+ status: request.status,
72
+ });
73
+ }
74
+ const account = apiKey
75
+ ? await user.connect.apiKey({ service, apiKey, connectionName })
76
+ : await user.connect.customCredential({ service, values: values ?? {}, connectionName });
77
+ return res.json({
78
+ pending: false,
79
+ connectedAccountId: account.connectedAccountId,
80
+ status: account.status,
81
+ available: account.available,
82
+ });
83
+ } catch (err) {
84
+ return sendConnectorError(res, err);
85
+ }
86
+ });
87
+
88
+ /** Poll an OAuth connection request until the user finishes authorizing. */
89
+ app.get("/api/connections/requests/:id", async (req, res) => {
90
+ try {
91
+ const request = await project.getConnectionRequest(req.params.id);
92
+ res.json(request); // status: initiated | connected | failed | expired
93
+ } catch (err) {
94
+ sendConnectorError(res, err);
95
+ }
96
+ });
97
+
98
+ /** Run any catalog action as the logged-in user (e.g. "gmail.search_threads"). */
99
+ app.post("/api/actions/:actionId", async (req, res) => {
100
+ const { input = {}, connectionName } = req.body ?? {};
101
+ try {
102
+ const out = await project
103
+ .forUser(req.userId)
104
+ .executeRaw(req.params.actionId, input, connectionName ? { connectionName } : undefined);
105
+ res.json(out); // { data, executionId, actionId, message }
106
+ } catch (err) {
107
+ sendConnectorError(res, err);
108
+ }
109
+ });
110
+
111
+ /** Landing page OOMOL returns the user to after OAuth consent. */
112
+ app.get("/connected", (req, res) => {
113
+ res.send(`<p>${req.query.service ?? "Account"} connected — you can close this tab.</p>`);
114
+ });
115
+
116
+ function sendConnectorError(res, err) {
117
+ if (err instanceof ConnectorError) {
118
+ // e.g. provider_config_not_found, connection_alias_conflict, app_not_ready, client_wait_timeout
119
+ return res.status(err.status || 502).json({ error: err.code, message: err.message });
120
+ }
121
+ console.error(err);
122
+ return res.status(500).json({ error: "internal_error" });
123
+ }
124
+
125
+ app.listen(PORT, () => console.log(`OOMOL SaaS connector server on :${PORT} (gateway: connector.oomol.com)`));