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.
- package/dist/connectors/index.d.ts +84 -0
- package/dist/connectors/server.d.ts +46 -0
- package/dist/connectors/smoke-test.d.ts +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/research-agent.cjs.js +1 -1
- package/dist/research-agent.cjs.js.map +1 -1
- package/dist/research-agent.es.js +1 -1
- package/dist/research-agent.es.js.map +1 -1
- package/package.json +13 -2
- package/src/connectors/README.md +374 -0
- package/src/connectors/catalog.json +1 -0
- package/src/connectors/index.ts +128 -0
- package/src/connectors/oomol-saas-server.js +125 -0
- package/src/connectors/package-lock.json +872 -0
- package/src/connectors/package.json +19 -0
- package/src/connectors/server.js +125 -0
- package/src/connectors/server.ts +220 -0
- package/src/connectors/smoke-test.js +14 -0
- package/src/connectors/smoke-test.ts +44 -0
- package/src/index.ts +4 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "oomol-saas-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"start": "node server.js",
|
|
9
|
+
"build": "node --check server.js && node smoke-test.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@oomol-lab/connector": "^1.0.0",
|
|
17
|
+
"express": "^5.2.1"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -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)`));
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-tenant connector server on OOMOL Cloud.
|
|
3
|
+
*
|
|
4
|
+
* This is a standalone Node.js Express server that manages OAuth credentials
|
|
5
|
+
* and API key connections for your app's users. It's NOT for browser/client code.
|
|
6
|
+
*
|
|
7
|
+
* OOMOL handles everything server-side:
|
|
8
|
+
* - OAuth apps & client secrets
|
|
9
|
+
* - Credential vault (encrypted storage)
|
|
10
|
+
* - Token refresh
|
|
11
|
+
* - Provider API calls
|
|
12
|
+
*
|
|
13
|
+
* Your app's users link THEIR OWN accounts (Gmail, Slack, GitHub, ...) via
|
|
14
|
+
* ProjectConnector — similar to Composio or Pipedream's "managed auth" model.
|
|
15
|
+
*
|
|
16
|
+
* @fileoverview OOMOL SaaS Connector Server
|
|
17
|
+
* @module connectors/server
|
|
18
|
+
*
|
|
19
|
+
* Setup:
|
|
20
|
+
* 1. Create a project in the OOMOL console and copy its API key (oo_proj_...).
|
|
21
|
+
* 2. Set OOMOL_PROJECT_API_KEY=oo_proj_... and run:
|
|
22
|
+
* ```bash
|
|
23
|
+
* cd packages/agent-toolkit/src/connectors
|
|
24
|
+
* npm install
|
|
25
|
+
* npm start
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Environment variables:
|
|
29
|
+
* - OOMOL_PROJECT_API_KEY: Your OOMOL project API key (required)
|
|
30
|
+
* - PORT: Server port (default: 8787)
|
|
31
|
+
* - APP_ORIGIN: Your app's origin for OAuth redirect (default: http://localhost:8787)
|
|
32
|
+
*
|
|
33
|
+
* API Endpoints:
|
|
34
|
+
* GET /api/catalog - List/search providers
|
|
35
|
+
* POST /api/connections - Start OAuth or API-key connection
|
|
36
|
+
* GET /api/connections/requests/:id - Poll OAuth status
|
|
37
|
+
* POST /api/actions/:actionId - Execute a provider action
|
|
38
|
+
* GET /connected - OAuth redirect landing page
|
|
39
|
+
*
|
|
40
|
+
* SECURITY: externalUserId = your app's own user id (from auth/session layer).
|
|
41
|
+
* NEVER let the client pick another user's id — derive it server-side from
|
|
42
|
+
* the authenticated session.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
import express, { Request, Response, NextFunction } from "express";
|
|
46
|
+
import { readFile } from "node:fs/promises";
|
|
47
|
+
import { ConnectorError, ProjectConnector } from "@oomol-lab/connector";
|
|
48
|
+
import { catalog } from "./index.js";
|
|
49
|
+
|
|
50
|
+
const PORT = process.env.PORT ?? 8787;
|
|
51
|
+
const APP_ORIGIN = process.env.APP_ORIGIN ?? `http://localhost:${PORT}`;
|
|
52
|
+
|
|
53
|
+
const project = new ProjectConnector({
|
|
54
|
+
apiKey: process.env.OOMOL_PROJECT_API_KEY ?? "oo_proj_missing",
|
|
55
|
+
// baseUrl defaults to OOMOL Cloud: https://connector.oomol.com/v1
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Build a Map for fast service lookup
|
|
59
|
+
const byService = new Map(catalog.map((p) => [p.service, p]));
|
|
60
|
+
|
|
61
|
+
const app = express();
|
|
62
|
+
app.use(express.json());
|
|
63
|
+
|
|
64
|
+
// DEMO ONLY: replace with your real session auth. Everything below trusts req.userId.
|
|
65
|
+
// In production, use middleware like passport, express-session, or JWT.
|
|
66
|
+
app.use((req: Request, _res: Response, next: NextFunction) => {
|
|
67
|
+
(req as any).userId = req.get("x-user-id") ?? "demo_user";
|
|
68
|
+
next();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* GET /api/catalog
|
|
73
|
+
* Provider catalog for your "add a connection" picker.
|
|
74
|
+
* @query q Search term (optional, case-insensitive)
|
|
75
|
+
* @query limit Max results (default: 100)
|
|
76
|
+
*/
|
|
77
|
+
app.get("/api/catalog", (req: Request, res: Response) => {
|
|
78
|
+
const q = (req.query.q ?? "").toString().toLowerCase();
|
|
79
|
+
const list = q
|
|
80
|
+
? catalog.filter(
|
|
81
|
+
(p) =>
|
|
82
|
+
p.service.includes(q) || p.displayName.toLowerCase().includes(q)
|
|
83
|
+
)
|
|
84
|
+
: catalog;
|
|
85
|
+
res.json(list.slice(0, Number(req.query.limit ?? 100)));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* POST /api/connections
|
|
90
|
+
* Start a connection for the logged-in user.
|
|
91
|
+
*
|
|
92
|
+
* OAuth providers: returns { pending: true, authorizationUrl, requestId }
|
|
93
|
+
* → redirect the user to authorizationUrl, then poll /api/connections/requests/:id
|
|
94
|
+
*
|
|
95
|
+
* API-key or custom credential: pass { apiKey } or { values }
|
|
96
|
+
* → returns { pending: false, connectedAccountId, status, available }
|
|
97
|
+
*
|
|
98
|
+
* @body service The provider service ID (e.g., "gmail", "slack")
|
|
99
|
+
* @body connectionName Optional friendly name for this connection
|
|
100
|
+
* @body apiKey Optional API key (for api_key auth providers)
|
|
101
|
+
* @body values Optional custom credential values object
|
|
102
|
+
*/
|
|
103
|
+
app.post("/api/connections", async (req: Request, res: Response) => {
|
|
104
|
+
const { service, connectionName, apiKey, values } = req.body ?? {};
|
|
105
|
+
const provider = byService.get(service);
|
|
106
|
+
if (!provider)
|
|
107
|
+
return res.status(404).json({ error: "unknown_service", service });
|
|
108
|
+
|
|
109
|
+
const userId = (req as any).userId;
|
|
110
|
+
const user = project.forUser(userId);
|
|
111
|
+
try {
|
|
112
|
+
if (provider.authTypes.includes("oauth2") && !apiKey && !values) {
|
|
113
|
+
const request = await user.connect.oauth({
|
|
114
|
+
service,
|
|
115
|
+
connectionName,
|
|
116
|
+
returnUri: `${APP_ORIGIN}/connected?service=${encodeURIComponent(service)}`,
|
|
117
|
+
});
|
|
118
|
+
// Redirect your user to authorizationUrl; poll GET /api/connections/requests/:id after.
|
|
119
|
+
return res.json({
|
|
120
|
+
pending: true,
|
|
121
|
+
requestId: request.id,
|
|
122
|
+
authorizationUrl: request.authorizationUrl,
|
|
123
|
+
status: request.status,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const account = apiKey
|
|
127
|
+
? await user.connect.apiKey({ service, apiKey, connectionName })
|
|
128
|
+
: await user.connect.customCredential({
|
|
129
|
+
service,
|
|
130
|
+
values: values ?? {},
|
|
131
|
+
connectionName,
|
|
132
|
+
});
|
|
133
|
+
return res.json({
|
|
134
|
+
pending: false,
|
|
135
|
+
connectedAccountId: account.connectedAccountId,
|
|
136
|
+
status: account.status,
|
|
137
|
+
available: account.available,
|
|
138
|
+
});
|
|
139
|
+
} catch (err) {
|
|
140
|
+
return sendConnectorError(res, err);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* GET /api/connections/requests/:id
|
|
146
|
+
* Poll an OAuth connection request until the user finishes authorizing.
|
|
147
|
+
* @param id The request ID from POST /api/connections
|
|
148
|
+
* @returns { status: "initiated" | "connected" | "failed" | "expired", ... }
|
|
149
|
+
*/
|
|
150
|
+
app.get("/api/connections/requests/:id", async (req: Request, res: Response) => {
|
|
151
|
+
try {
|
|
152
|
+
const request = await project.getConnectionRequest(req.params.id);
|
|
153
|
+
res.json(request);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
sendConnectorError(res, err);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* POST /api/actions/:actionId
|
|
161
|
+
* Run any catalog action as the logged-in user.
|
|
162
|
+
* @param actionId The action ID (e.g., "gmail.search_threads")
|
|
163
|
+
* @body input Input parameters for the action
|
|
164
|
+
* @body connectionName Optional connection name to use (if user has multiple)
|
|
165
|
+
* @returns { data, executionId, actionId, message }
|
|
166
|
+
*/
|
|
167
|
+
app.post("/api/actions/:actionId", async (req: Request, res: Response) => {
|
|
168
|
+
const { input = {}, connectionName } = req.body ?? {};
|
|
169
|
+
try {
|
|
170
|
+
const userId = (req as any).userId;
|
|
171
|
+
const out = await project
|
|
172
|
+
.forUser(userId)
|
|
173
|
+
.executeRaw(
|
|
174
|
+
req.params.actionId,
|
|
175
|
+
input,
|
|
176
|
+
connectionName ? { connectionName } : undefined
|
|
177
|
+
);
|
|
178
|
+
res.json(out);
|
|
179
|
+
} catch (err) {
|
|
180
|
+
sendConnectorError(res, err);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* GET /connected
|
|
186
|
+
* Landing page: OOMOL redirects the user here after OAuth consent.
|
|
187
|
+
* You can customize this to show a success message or redirect to your app.
|
|
188
|
+
*/
|
|
189
|
+
app.get("/connected", (req: Request, res: Response) => {
|
|
190
|
+
res.send(
|
|
191
|
+
`<p>${req.query.service ?? "Account"} connected — you can close this tab.</p>`
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Handle OOMOL connector errors with proper HTTP status codes.
|
|
197
|
+
*/
|
|
198
|
+
function sendConnectorError(res: Response, err: unknown) {
|
|
199
|
+
if (err instanceof ConnectorError) {
|
|
200
|
+
// OOMOL error codes: provider_config_not_found, connection_alias_conflict,
|
|
201
|
+
// app_not_ready, client_wait_timeout, etc.
|
|
202
|
+
return res
|
|
203
|
+
.status(err.status || 502)
|
|
204
|
+
.json({ error: err.code, message: err.message });
|
|
205
|
+
}
|
|
206
|
+
console.error("Server error:", err);
|
|
207
|
+
return res.status(500).json({ error: "internal_error" });
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const server = app.listen(PORT, () => {
|
|
211
|
+
console.log(
|
|
212
|
+
`\n✓ OOMOL SaaS Connector server started on http://localhost:${PORT}`
|
|
213
|
+
);
|
|
214
|
+
console.log(
|
|
215
|
+
` Gateway: https://connector.oomol.com/v1 (OOMOL_PROJECT_API_KEY required)`
|
|
216
|
+
);
|
|
217
|
+
console.log(` Environment: APP_ORIGIN=${APP_ORIGIN}\n`);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
export { app, server };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Build-time smoke test: verify the SDK imports, client constructs, and routes register.
|
|
2
|
+
import { ProjectConnector, ConnectorError } from "@oomol-lab/connector";
|
|
3
|
+
const p = new ProjectConnector({ apiKey: "oo_proj_smoke" });
|
|
4
|
+
const u = p.forUser("user_1");
|
|
5
|
+
for (const [obj, keys] of [
|
|
6
|
+
[p, ["connect", "getConnectionRequest", "waitForConnection", "execute", "executeRaw", "forUser"]],
|
|
7
|
+
[u, ["connect", "execute", "executeRaw", "waitForConnection"]],
|
|
8
|
+
]) for (const k of keys) if (typeof obj[k] !== "function" && typeof obj[k] !== "object") throw new Error(`missing ${k}`);
|
|
9
|
+
if (typeof ConnectorError !== "function") throw new Error("missing ConnectorError");
|
|
10
|
+
// Boot the server without a listener conflict, then exit.
|
|
11
|
+
process.env.PORT = "0";
|
|
12
|
+
await import("./server.js");
|
|
13
|
+
console.log("smoke test passed");
|
|
14
|
+
setTimeout(() => process.exit(0), 300);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build-time smoke test: verify the OOMOL SDK imports, client constructs, and routes register.
|
|
3
|
+
* Run with: npm run build (from the connectors directory)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ProjectConnector, ConnectorError } from "@oomol-lab/connector";
|
|
7
|
+
|
|
8
|
+
const p = new ProjectConnector({ apiKey: "oo_proj_smoke" });
|
|
9
|
+
const u = p.forUser("user_1");
|
|
10
|
+
|
|
11
|
+
// Verify ProjectConnector and UserConnector have expected methods
|
|
12
|
+
for (const [obj, keys] of [
|
|
13
|
+
[
|
|
14
|
+
p,
|
|
15
|
+
[
|
|
16
|
+
"connect",
|
|
17
|
+
"getConnectionRequest",
|
|
18
|
+
"waitForConnection",
|
|
19
|
+
"execute",
|
|
20
|
+
"executeRaw",
|
|
21
|
+
"forUser",
|
|
22
|
+
],
|
|
23
|
+
],
|
|
24
|
+
[u, ["connect", "execute", "executeRaw", "waitForConnection"]],
|
|
25
|
+
] as const) {
|
|
26
|
+
for (const k of keys) {
|
|
27
|
+
const val = (obj as any)[k];
|
|
28
|
+
if (typeof val !== "function" && typeof val !== "object") {
|
|
29
|
+
throw new Error(`missing ${k} on ${obj.constructor.name}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Verify ConnectorError is exported
|
|
35
|
+
if (typeof ConnectorError !== "function") {
|
|
36
|
+
throw new Error("missing ConnectorError class");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Boot the server without a listener conflict, then exit.
|
|
40
|
+
process.env.PORT = "0";
|
|
41
|
+
await import("./server.js");
|
|
42
|
+
|
|
43
|
+
console.log("✓ OOMOL Connector smoke test passed");
|
|
44
|
+
setTimeout(() => process.exit(0), 300);
|
package/src/index.ts
CHANGED
|
@@ -25,3 +25,7 @@ export { configManager, ModelRegistry, getEnv, getModelProvidersUIConfigSection
|
|
|
25
25
|
export type { Config, ConfigModelProvider, MCPServerConfig, UIConfigSections, Model, ModelWithProvider } from "./config";
|
|
26
26
|
export { cropProvider, cropProviderAsBlob, cropProviderAsDataURL, getProviderImage, getProviderNames } from "./utils/provider-image-cropper";
|
|
27
27
|
export type { Provider } from "./utils/provider-image-cropper";
|
|
28
|
+
|
|
29
|
+
// OpenConnector integration: multi-tenant OAuth & credential management
|
|
30
|
+
export * from "./connectors";
|
|
31
|
+
export * as connectors from "./connectors";
|