@alfe.ai/openclaw-database 0.0.2 → 0.0.4
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/plugin.d.ts +2 -1
- package/dist/plugin2.js +68 -37
- package/openclaw.plugin.json +6 -1
- package/package.json +2 -2
package/dist/plugin.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
interface PluginApi {
|
|
3
3
|
logger: {
|
|
4
4
|
info: (...args: unknown[]) => void;
|
|
5
|
+
warn: (...args: unknown[]) => void;
|
|
5
6
|
error: (...args: unknown[]) => void;
|
|
6
7
|
debug: (...args: unknown[]) => void;
|
|
7
8
|
};
|
|
@@ -11,7 +12,7 @@ declare const plugin: {
|
|
|
11
12
|
id: string;
|
|
12
13
|
name: string;
|
|
13
14
|
version: string;
|
|
14
|
-
activate(api: PluginApi):
|
|
15
|
+
activate(api: PluginApi): void;
|
|
15
16
|
deactivate(api: PluginApi): Promise<void>;
|
|
16
17
|
};
|
|
17
18
|
//#endregion
|
package/dist/plugin2.js
CHANGED
|
@@ -14,11 +14,17 @@ function optStr() {
|
|
|
14
14
|
default: ""
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
function registerTools(api,
|
|
18
|
-
function db(name) {
|
|
17
|
+
function registerTools(api, _client, _databases, audit, lazyInit) {
|
|
18
|
+
async function db(name) {
|
|
19
|
+
const { mongoClient, databases } = lazyInit ? await lazyInit() : {
|
|
20
|
+
mongoClient: _client ?? (() => {
|
|
21
|
+
throw new Error("MongoDB client not initialized");
|
|
22
|
+
})(),
|
|
23
|
+
databases: _databases
|
|
24
|
+
};
|
|
19
25
|
const dbName = name ?? DEFAULT_DB;
|
|
20
26
|
if (!databases.includes(dbName)) throw new Error(`Access denied: database "${dbName}" is not in the allowed list`);
|
|
21
|
-
return
|
|
27
|
+
return mongoClient.db(dbName);
|
|
22
28
|
}
|
|
23
29
|
api.registerTool({
|
|
24
30
|
name: "db_find",
|
|
@@ -53,7 +59,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
53
59
|
required: ["collection"]
|
|
54
60
|
},
|
|
55
61
|
execute: async (_id, p) => {
|
|
56
|
-
const docs = await db(p.database).collection(p.collection).find(p.filter).sort(p.sort).project(p.projection).skip(p.skip || 0).limit(p.limit || 20).toArray();
|
|
62
|
+
const docs = await (await db(p.database)).collection(p.collection).find(p.filter).sort(p.sort).project(p.projection).skip(p.skip || 0).limit(p.limit || 20).toArray();
|
|
57
63
|
return {
|
|
58
64
|
documents: docs,
|
|
59
65
|
count: docs.length
|
|
@@ -81,7 +87,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
81
87
|
required: ["collection"]
|
|
82
88
|
},
|
|
83
89
|
execute: async (_id, p) => {
|
|
84
|
-
return await db(p.database).collection(p.collection).findOne(p.filter, { projection: p.projection }) ?? { _not_found: true };
|
|
90
|
+
return await (await db(p.database)).collection(p.collection).findOne(p.filter, { projection: p.projection }) ?? { _not_found: true };
|
|
85
91
|
}
|
|
86
92
|
});
|
|
87
93
|
api.registerTool({
|
|
@@ -102,7 +108,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
102
108
|
},
|
|
103
109
|
execute: async (_id, p) => {
|
|
104
110
|
const docs = p.documents;
|
|
105
|
-
const result = await db(p.database).collection(p.collection).insertMany(docs);
|
|
111
|
+
const result = await (await db(p.database)).collection(p.collection).insertMany(docs);
|
|
106
112
|
audit({
|
|
107
113
|
database: p.database || DEFAULT_DB,
|
|
108
114
|
collection: p.collection,
|
|
@@ -138,7 +144,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
138
144
|
]
|
|
139
145
|
},
|
|
140
146
|
execute: async (_id, p) => {
|
|
141
|
-
const result = await db(p.database).collection(p.collection).updateMany(p.filter, p.update, { upsert: p.upsert || false });
|
|
147
|
+
const result = await (await db(p.database)).collection(p.collection).updateMany(p.filter, p.update, { upsert: p.upsert || false });
|
|
142
148
|
audit({
|
|
143
149
|
database: p.database || DEFAULT_DB,
|
|
144
150
|
collection: p.collection,
|
|
@@ -166,7 +172,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
166
172
|
required: ["collection", "filter"]
|
|
167
173
|
},
|
|
168
174
|
execute: async (_id, p) => {
|
|
169
|
-
const result = await db(p.database).collection(p.collection).deleteMany(p.filter);
|
|
175
|
+
const result = await (await db(p.database)).collection(p.collection).deleteMany(p.filter);
|
|
170
176
|
audit({
|
|
171
177
|
database: p.database || DEFAULT_DB,
|
|
172
178
|
collection: p.collection,
|
|
@@ -193,7 +199,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
193
199
|
required: ["collection"]
|
|
194
200
|
},
|
|
195
201
|
execute: async (_id, p) => {
|
|
196
|
-
return { count: await db(p.database).collection(p.collection).countDocuments(p.filter) };
|
|
202
|
+
return { count: await (await db(p.database)).collection(p.collection).countDocuments(p.filter) };
|
|
197
203
|
}
|
|
198
204
|
});
|
|
199
205
|
api.registerTool({
|
|
@@ -213,7 +219,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
213
219
|
required: ["collection", "pipeline"]
|
|
214
220
|
},
|
|
215
221
|
execute: async (_id, p) => {
|
|
216
|
-
const results = await db(p.database).collection(p.collection).aggregate(p.pipeline).toArray();
|
|
222
|
+
const results = await (await db(p.database)).collection(p.collection).aggregate(p.pipeline).toArray();
|
|
217
223
|
return {
|
|
218
224
|
results,
|
|
219
225
|
count: results.length
|
|
@@ -228,7 +234,10 @@ function registerTools(api, client, databases, audit) {
|
|
|
228
234
|
type: "object",
|
|
229
235
|
properties: {}
|
|
230
236
|
},
|
|
231
|
-
execute: () =>
|
|
237
|
+
execute: async () => {
|
|
238
|
+
const { databases } = lazyInit ? await lazyInit() : { databases: _databases };
|
|
239
|
+
return { databases };
|
|
240
|
+
}
|
|
232
241
|
});
|
|
233
242
|
api.registerTool({
|
|
234
243
|
name: "db_list_collections",
|
|
@@ -239,7 +248,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
239
248
|
properties: { database: optStr() }
|
|
240
249
|
},
|
|
241
250
|
execute: async (_id, p) => {
|
|
242
|
-
return { collections: (await db(p.database).listCollections().toArray()).map((c) => ({
|
|
251
|
+
return { collections: (await (await db(p.database)).listCollections().toArray()).map((c) => ({
|
|
243
252
|
name: c.name,
|
|
244
253
|
type: c.type
|
|
245
254
|
})) };
|
|
@@ -258,7 +267,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
258
267
|
required: ["collection"]
|
|
259
268
|
},
|
|
260
269
|
execute: async (_id, p) => {
|
|
261
|
-
await db(p.database).createCollection(p.collection);
|
|
270
|
+
await (await db(p.database)).createCollection(p.collection);
|
|
262
271
|
audit({
|
|
263
272
|
database: p.database || DEFAULT_DB,
|
|
264
273
|
collection: p.collection,
|
|
@@ -280,7 +289,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
280
289
|
required: ["collection"]
|
|
281
290
|
},
|
|
282
291
|
execute: async (_id, p) => {
|
|
283
|
-
await db(p.database).dropCollection(p.collection);
|
|
292
|
+
await (await db(p.database)).dropCollection(p.collection);
|
|
284
293
|
audit({
|
|
285
294
|
database: p.database || DEFAULT_DB,
|
|
286
295
|
collection: p.collection,
|
|
@@ -302,7 +311,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
302
311
|
required: ["collection"]
|
|
303
312
|
},
|
|
304
313
|
execute: async (_id, p) => {
|
|
305
|
-
const sample = await db(p.database).collection(p.collection).find().limit(100).toArray();
|
|
314
|
+
const sample = await (await db(p.database)).collection(p.collection).find().limit(100).toArray();
|
|
306
315
|
const fieldTypes = /* @__PURE__ */ new Map();
|
|
307
316
|
for (const doc of sample) for (const [key, value] of Object.entries(doc)) {
|
|
308
317
|
const types = fieldTypes.get(key) ?? /* @__PURE__ */ new Set();
|
|
@@ -331,7 +340,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
331
340
|
required: ["collection"]
|
|
332
341
|
},
|
|
333
342
|
execute: async (_id, p) => {
|
|
334
|
-
const coll = db(p.database).collection(p.collection);
|
|
343
|
+
const coll = (await db(p.database)).collection(p.collection);
|
|
335
344
|
const count = await coll.countDocuments();
|
|
336
345
|
const indexes = await coll.indexes();
|
|
337
346
|
return {
|
|
@@ -362,7 +371,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
362
371
|
required: ["collection", "keys"]
|
|
363
372
|
},
|
|
364
373
|
execute: async (_id, p) => {
|
|
365
|
-
const indexName = await db(p.database).collection(p.collection).createIndex(p.keys, p.options);
|
|
374
|
+
const indexName = await (await db(p.database)).collection(p.collection).createIndex(p.keys, p.options);
|
|
366
375
|
audit({
|
|
367
376
|
database: p.database || DEFAULT_DB,
|
|
368
377
|
collection: p.collection,
|
|
@@ -385,7 +394,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
385
394
|
required: ["collection"]
|
|
386
395
|
},
|
|
387
396
|
execute: async (_id, p) => {
|
|
388
|
-
return { indexes: (await db(p.database).collection(p.collection).indexes()).map((i) => ({
|
|
397
|
+
return { indexes: (await (await db(p.database)).collection(p.collection).indexes()).map((i) => ({
|
|
389
398
|
name: i.name,
|
|
390
399
|
key: i.key,
|
|
391
400
|
unique: i.unique
|
|
@@ -406,7 +415,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
406
415
|
required: ["collection", "indexName"]
|
|
407
416
|
},
|
|
408
417
|
execute: async (_id, p) => {
|
|
409
|
-
await db(p.database).collection(p.collection).dropIndex(p.indexName);
|
|
418
|
+
await (await db(p.database)).collection(p.collection).dropIndex(p.indexName);
|
|
410
419
|
audit({
|
|
411
420
|
database: p.database || DEFAULT_DB,
|
|
412
421
|
collection: p.collection,
|
|
@@ -420,6 +429,7 @@ function registerTools(api, client, databases, audit) {
|
|
|
420
429
|
//#endregion
|
|
421
430
|
//#region src/plugin.ts
|
|
422
431
|
let mongoClient = null;
|
|
432
|
+
let initPromise = null;
|
|
423
433
|
async function fetchCredentials(apiUrl, apiKey) {
|
|
424
434
|
const res = await fetch(`${apiUrl}/agents/database/register`, {
|
|
425
435
|
method: "POST",
|
|
@@ -431,6 +441,37 @@ async function fetchCredentials(apiUrl, apiKey) {
|
|
|
431
441
|
if (!res.ok) throw new Error(`Failed to register database credentials: ${String(res.status)} ${res.statusText}`);
|
|
432
442
|
return (await res.json()).data;
|
|
433
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Lazy initializer — fetches credentials and connects to MongoDB on first use.
|
|
446
|
+
* Returns a shared promise so concurrent calls don't duplicate work.
|
|
447
|
+
*/
|
|
448
|
+
function ensureInitialized(apiUrl, apiKey) {
|
|
449
|
+
if (initPromise) return initPromise;
|
|
450
|
+
initPromise = (async () => {
|
|
451
|
+
const credentials = await fetchCredentials(apiUrl, apiKey);
|
|
452
|
+
if (!credentials.connectionString) throw new Error("No connection string returned — cluster may still be provisioning");
|
|
453
|
+
const url = new URL(credentials.connectionString);
|
|
454
|
+
url.username = credentials.username;
|
|
455
|
+
url.password = credentials.password;
|
|
456
|
+
const client = new MongoClient(url.toString(), {
|
|
457
|
+
maxPoolSize: 3,
|
|
458
|
+
minPoolSize: 1,
|
|
459
|
+
serverSelectionTimeoutMS: 5e3
|
|
460
|
+
});
|
|
461
|
+
await client.connect();
|
|
462
|
+
mongoClient = client;
|
|
463
|
+
return {
|
|
464
|
+
mongoClient: client,
|
|
465
|
+
databases: credentials.databases,
|
|
466
|
+
apiUrl,
|
|
467
|
+
apiKey
|
|
468
|
+
};
|
|
469
|
+
})();
|
|
470
|
+
initPromise.catch(() => {
|
|
471
|
+
initPromise = null;
|
|
472
|
+
});
|
|
473
|
+
return initPromise;
|
|
474
|
+
}
|
|
434
475
|
function reportAudit(apiUrl, apiKey, entry) {
|
|
435
476
|
fetch(`${apiUrl}/agents/database/audit`, {
|
|
436
477
|
method: "POST",
|
|
@@ -445,37 +486,27 @@ const plugin = {
|
|
|
445
486
|
id: "@alfe.ai/openclaw-database",
|
|
446
487
|
name: "Database",
|
|
447
488
|
version: "0.0.1",
|
|
448
|
-
|
|
489
|
+
activate(api) {
|
|
449
490
|
const log = api.logger;
|
|
450
491
|
log.info("Database plugin activating...");
|
|
451
492
|
let apiUrl;
|
|
452
493
|
let apiKey;
|
|
453
494
|
try {
|
|
454
|
-
const config =
|
|
495
|
+
const config = resolveConfig();
|
|
455
496
|
apiUrl = config.apiUrl;
|
|
456
497
|
apiKey = config.apiKey;
|
|
457
498
|
} catch (err) {
|
|
458
499
|
log.error(`Database plugin: failed to resolve config — ${err instanceof Error ? err.message : String(err)}`);
|
|
459
500
|
return;
|
|
460
501
|
}
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
466
|
-
const url = new URL(credentials.connectionString);
|
|
467
|
-
url.username = credentials.username;
|
|
468
|
-
url.password = credentials.password;
|
|
469
|
-
mongoClient = new MongoClient(url.toString(), {
|
|
470
|
-
maxPoolSize: 3,
|
|
471
|
-
minPoolSize: 1,
|
|
472
|
-
serverSelectionTimeoutMS: 5e3
|
|
502
|
+
ensureInitialized(apiUrl, apiKey).then(({ databases }) => {
|
|
503
|
+
log.info(`Database plugin connected — ${String(databases.length)} databases available`);
|
|
504
|
+
}).catch((err) => {
|
|
505
|
+
log.warn(`Database plugin: background init failed (will retry on first tool use) — ${err instanceof Error ? err.message : String(err)}`);
|
|
473
506
|
});
|
|
474
|
-
|
|
475
|
-
log.info(`Database plugin connected — ${String(credentials.databases.length)} databases available`);
|
|
476
|
-
registerTools(api, mongoClient, credentials.databases, (entry) => {
|
|
507
|
+
registerTools(api, null, [], (entry) => {
|
|
477
508
|
reportAudit(apiUrl, apiKey, entry);
|
|
478
|
-
});
|
|
509
|
+
}, () => ensureInitialized(apiUrl, apiKey));
|
|
479
510
|
},
|
|
480
511
|
async deactivate(api) {
|
|
481
512
|
api.logger.info("Database plugin deactivating...");
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,5 +3,10 @@
|
|
|
3
3
|
"name": "Database",
|
|
4
4
|
"version": "0.0.1",
|
|
5
5
|
"description": "MongoDB database access for agents — query, insert, update, delete, and manage collections",
|
|
6
|
-
"entry": "./dist/plugin.js"
|
|
6
|
+
"entry": "./dist/plugin.js",
|
|
7
|
+
"configSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": false,
|
|
10
|
+
"properties": {}
|
|
11
|
+
}
|
|
7
12
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-database",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "OpenClaw database plugin — MongoDB access for agents via MCP tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/plugin.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"mongodb": "^6.12.0",
|
|
29
|
-
"@alfe.ai/config": "0.0.
|
|
29
|
+
"@alfe.ai/config": "0.0.6"
|
|
30
30
|
},
|
|
31
31
|
"license": "UNLICENSED",
|
|
32
32
|
"scripts": {
|