@moltium/world-core 0.1.7 → 0.1.9
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/CardFetcher-3QKJ2I5P.js +9 -0
- package/dist/CardFetcher-3QKJ2I5P.js.map +1 -0
- package/dist/CardFetcher-AR7IANM7.cjs +9 -0
- package/dist/CardFetcher-AR7IANM7.cjs.map +1 -0
- package/dist/LevelDBAdapter-TGQYZHZH.cjs +147 -0
- package/dist/LevelDBAdapter-TGQYZHZH.cjs.map +1 -0
- package/dist/LevelDBAdapter-ZV2ZTDOV.js +147 -0
- package/dist/LevelDBAdapter-ZV2ZTDOV.js.map +1 -0
- package/dist/MongoAdapter-TCY6JOZH.js +137 -0
- package/dist/MongoAdapter-TCY6JOZH.js.map +1 -0
- package/dist/MongoAdapter-XEHWKU2F.cjs +137 -0
- package/dist/MongoAdapter-XEHWKU2F.cjs.map +1 -0
- package/dist/PostgresAdapter-PLXDLHVF.js +240 -0
- package/dist/PostgresAdapter-PLXDLHVF.js.map +1 -0
- package/dist/PostgresAdapter-WL5SLUDL.cjs +240 -0
- package/dist/PostgresAdapter-WL5SLUDL.cjs.map +1 -0
- package/dist/RedisAdapter-CT3SNBIS.cjs +122 -0
- package/dist/RedisAdapter-CT3SNBIS.cjs.map +1 -0
- package/dist/RedisAdapter-OL4FVEGL.js +122 -0
- package/dist/RedisAdapter-OL4FVEGL.js.map +1 -0
- package/dist/chunk-JW3PZRCW.js +130 -0
- package/dist/chunk-JW3PZRCW.js.map +1 -0
- package/dist/chunk-NEXCYEQT.cjs +130 -0
- package/dist/chunk-NEXCYEQT.cjs.map +1 -0
- package/dist/index.cjs +356 -1323
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +216 -1146
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
var _chunkNEXCYEQTcjs = require('./chunk-NEXCYEQT.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
exports.CardFetcher = _chunkNEXCYEQTcjs.CardFetcher; exports.normalizeAgentUrl = _chunkNEXCYEQTcjs.normalizeAgentUrl;
|
|
9
|
+
//# sourceMappingURL=CardFetcher-AR7IANM7.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/brooklyn/Desktop/SchrodingerLabs/Byzantium/packages/world-core/dist/CardFetcher-AR7IANM7.cjs"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACE;AACA;AACF,qHAAC","file":"/Users/brooklyn/Desktop/SchrodingerLabs/Byzantium/packages/world-core/dist/CardFetcher-AR7IANM7.cjs"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/persistence/adapters/LevelDBAdapter.ts
|
|
2
|
+
var _level = require('level');
|
|
3
|
+
var LevelDBAdapter = (_class = class {
|
|
4
|
+
constructor(config) {;_class.prototype.__init.call(this);
|
|
5
|
+
this.config = config;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
__init() {this.connected = false}
|
|
9
|
+
async connect() {
|
|
10
|
+
try {
|
|
11
|
+
this.db = new (0, _level.Level)(this.config.path, {
|
|
12
|
+
valueEncoding: "json"
|
|
13
|
+
});
|
|
14
|
+
await this.db.open();
|
|
15
|
+
this.connected = true;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
throw new Error(`LevelDB connection failed: ${error.message}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async saveState(state) {
|
|
21
|
+
await this.db.put("state:current", JSON.stringify(state));
|
|
22
|
+
const historyKey = `state:history:${state.timestamp}`;
|
|
23
|
+
await this.db.put(historyKey, JSON.stringify(state));
|
|
24
|
+
}
|
|
25
|
+
async loadState() {
|
|
26
|
+
try {
|
|
27
|
+
const data = await this.db.get("state:current");
|
|
28
|
+
return JSON.parse(data);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code === "LEVEL_NOT_FOUND") {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async saveEvent(event) {
|
|
37
|
+
const key = `event:${event.timestamp}:${event.id}`;
|
|
38
|
+
await this.db.put(key, JSON.stringify(event));
|
|
39
|
+
const typeKey = `event:type:${event.type}:${event.timestamp}:${event.id}`;
|
|
40
|
+
await this.db.put(typeKey, JSON.stringify(event));
|
|
41
|
+
if (event.agentUrl) {
|
|
42
|
+
const agentKey = `event:agent:${event.agentUrl}:${event.timestamp}:${event.id}`;
|
|
43
|
+
await this.db.put(agentKey, JSON.stringify(event));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async getEvents(filter) {
|
|
47
|
+
const events = [];
|
|
48
|
+
let prefix = "event:";
|
|
49
|
+
if (_optionalChain([filter, 'optionalAccess', _ => _.type])) {
|
|
50
|
+
prefix = `event:type:${filter.type}:`;
|
|
51
|
+
} else if (_optionalChain([filter, 'optionalAccess', _2 => _2.agentUrl])) {
|
|
52
|
+
prefix = `event:agent:${filter.agentUrl}:`;
|
|
53
|
+
}
|
|
54
|
+
const iterator = this.db.iterator({
|
|
55
|
+
gte: prefix,
|
|
56
|
+
lte: prefix + "\uFFFF",
|
|
57
|
+
reverse: true,
|
|
58
|
+
// Most recent first
|
|
59
|
+
limit: _optionalChain([filter, 'optionalAccess', _3 => _3.limit]) || -1
|
|
60
|
+
});
|
|
61
|
+
for await (const [key, value] of iterator) {
|
|
62
|
+
const event = JSON.parse(value);
|
|
63
|
+
if (_optionalChain([filter, 'optionalAccess', _4 => _4.since]) && event.timestamp < filter.since) continue;
|
|
64
|
+
if (_optionalChain([filter, 'optionalAccess', _5 => _5.until]) && event.timestamp > filter.until) continue;
|
|
65
|
+
if (_optionalChain([filter, 'optionalAccess', _6 => _6.type]) && !prefix.includes("type:") && event.type !== filter.type) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (_optionalChain([filter, 'optionalAccess', _7 => _7.agentUrl]) && !prefix.includes("agent:") && event.agentUrl !== filter.agentUrl) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
events.push(event);
|
|
72
|
+
if (_optionalChain([filter, 'optionalAccess', _8 => _8.limit]) && events.length >= filter.limit) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return events;
|
|
77
|
+
}
|
|
78
|
+
async saveAgent(profile) {
|
|
79
|
+
const key = `agent:${profile.url}`;
|
|
80
|
+
await this.db.put(key, JSON.stringify(profile));
|
|
81
|
+
const listKey = `agent:list:${profile.joinedAt}:${profile.url}`;
|
|
82
|
+
await this.db.put(listKey, profile.url);
|
|
83
|
+
}
|
|
84
|
+
async removeAgent(agentUrl) {
|
|
85
|
+
const key = `agent:${agentUrl}`;
|
|
86
|
+
try {
|
|
87
|
+
const data = await this.db.get(key);
|
|
88
|
+
const profile = JSON.parse(data);
|
|
89
|
+
await this.db.del(key);
|
|
90
|
+
const listKey = `agent:list:${profile.joinedAt}:${agentUrl}`;
|
|
91
|
+
await this.db.del(listKey);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error.code !== "LEVEL_NOT_FOUND") {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async getAgents() {
|
|
99
|
+
const agents = [];
|
|
100
|
+
const iterator = this.db.iterator({
|
|
101
|
+
gte: "agent:list:",
|
|
102
|
+
lte: "agent:list:\uFFFF"
|
|
103
|
+
});
|
|
104
|
+
for await (const [key, agentUrl] of iterator) {
|
|
105
|
+
try {
|
|
106
|
+
const data = await this.db.get(`agent:${agentUrl}`);
|
|
107
|
+
agents.push(JSON.parse(data));
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error.code !== "LEVEL_NOT_FOUND") {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return agents;
|
|
115
|
+
}
|
|
116
|
+
async getAgent(agentUrl) {
|
|
117
|
+
try {
|
|
118
|
+
const data = await this.db.get(`agent:${agentUrl}`);
|
|
119
|
+
return JSON.parse(data);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error.code === "LEVEL_NOT_FOUND") {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async disconnect() {
|
|
128
|
+
await this.db.close();
|
|
129
|
+
this.connected = false;
|
|
130
|
+
}
|
|
131
|
+
async healthCheck() {
|
|
132
|
+
try {
|
|
133
|
+
await this.db.get("health:check").catch(() => {
|
|
134
|
+
});
|
|
135
|
+
return true;
|
|
136
|
+
} catch (e) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async clear() {
|
|
141
|
+
await this.db.clear();
|
|
142
|
+
}
|
|
143
|
+
}, _class);
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
exports.LevelDBAdapter = LevelDBAdapter;
|
|
147
|
+
//# sourceMappingURL=LevelDBAdapter-TGQYZHZH.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/brooklyn/Desktop/SchrodingerLabs/Byzantium/packages/world-core/dist/LevelDBAdapter-TGQYZHZH.cjs","../src/persistence/adapters/LevelDBAdapter.ts"],"names":[],"mappings":"AAAA;ACEA,8BAAsB;AAef,IAAM,eAAA,YAAN,MAAmD;AAAA,EAIxD,WAAA,CAAoB,MAAA,EAAuB;AAAvB,IAAA,IAAA,CAAA,OAAA,EAAA,MAAA;AAAA,EAAwB;AAAA,EAHpC;AAAA,iBACA,UAAA,EAAY,MAAA;AAAA,EAIpB,MAAM,OAAA,CAAA,EAAyB;AAC7B,IAAA,IAAI;AACF,MAAA,IAAA,CAAK,GAAA,EAAK,IAAI,iBAAA,CAAM,IAAA,CAAK,MAAA,CAAO,IAAA,EAAM;AAAA,QACpC,aAAA,EAAe;AAAA,MACjB,CAAC,CAAA;AACD,MAAA,MAAM,IAAA,CAAK,EAAA,CAAG,IAAA,CAAK,CAAA;AACnB,MAAA,IAAA,CAAK,UAAA,EAAY,IAAA;AAAA,IACnB,EAAA,MAAA,CAAS,KAAA,EAAY;AACnB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,KAAA,CAAM,OAAO,CAAA,CAAA;AAC7D,IAAA;AACF,EAAA;AAE0D,EAAA;AAEA,IAAA;AAGL,IAAA;AACA,IAAA;AACrD,EAAA;AAEsD,EAAA;AAChD,IAAA;AAC4C,MAAA;AACxB,MAAA;AACH,IAAA;AACmB,MAAA;AAC7B,QAAA;AACT,MAAA;AACM,MAAA;AACR,IAAA;AACF,EAAA;AAEkD,EAAA;AAEA,IAAA;AACJ,IAAA;AAGe,IAAA;AACX,IAAA;AAG5B,IAAA;AACsC,MAAA;AACP,MAAA;AACnD,IAAA;AACF,EAAA;AAE6D,EAAA;AAC7B,IAAA;AACjB,IAAA;AAGK,IAAA;AACkB,MAAA;AACP,IAAA;AACY,MAAA;AACzC,IAAA;AAGkC,IAAA;AAC3B,MAAA;AACS,MAAA;AACL,MAAA;AAAA;AACe,MAAA;AACzB,IAAA;AAE0C,IAAA;AACD,MAAA;AAGa,MAAA;AACA,MAAA;AAGE,MAAA;AACrD,QAAA;AACF,MAAA;AAG4D,MAAA;AAC1D,QAAA;AACF,MAAA;AAEiB,MAAA;AAEmC,MAAA;AAClD,QAAA;AACF,MAAA;AACF,IAAA;AAEO,IAAA;AACT,EAAA;AAEsD,EAAA;AACpB,IAAA;AACc,IAAA;AAGe,IAAA;AACvB,IAAA;AACxC,EAAA;AAEmD,EAAA;AACpB,IAAA;AAEzB,IAAA;AAEgC,MAAA;AACH,MAAA;AAGV,MAAA;AAGqC,MAAA;AACjC,MAAA;AACN,IAAA;AACmB,MAAA;AAC9B,QAAA;AACR,MAAA;AACF,IAAA;AACF,EAAA;AAE2C,EAAA;AACT,IAAA;AAEE,IAAA;AAC3B,MAAA;AACA,MAAA;AACN,IAAA;AAE6C,IAAA;AACxC,MAAA;AACgD,QAAA;AACZ,QAAA;AACnB,MAAA;AAEmB,QAAA;AAC9B,UAAA;AACR,QAAA;AACF,MAAA;AACF,IAAA;AAEO,IAAA;AACT,EAAA;AAE+D,EAAA;AACzD,IAAA;AACgD,MAAA;AAC5B,MAAA;AACH,IAAA;AACmB,MAAA;AAC7B,QAAA;AACT,MAAA;AACM,MAAA;AACR,IAAA;AACF,EAAA;AAEkC,EAAA;AACZ,IAAA;AACH,IAAA;AACnB,EAAA;AAEsC,EAAA;AAChC,IAAA;AAE4C,MAAA;AAAE,MAAA;AACzC,MAAA;AACD,IAAA;AACC,MAAA;AACT,IAAA;AACF,EAAA;AAE6B,EAAA;AACP,IAAA;AACtB,EAAA;AACF;AD1DkE;AACA;AACA","file":"/Users/brooklyn/Desktop/SchrodingerLabs/Byzantium/packages/world-core/dist/LevelDBAdapter-TGQYZHZH.cjs","sourcesContent":[null,"import type { PersistenceAdapter, EventFilter } from '../PersistenceAdapter.js';\nimport type { WorldStateSnapshot, WorldEvent, AgentProfile } from '../../config/types.js';\nimport { Level } from 'level';\n\n/**\n * ============================================================================\n * LEVELDB ADAPTER\n * ============================================================================\n * \n * Embedded key-value persistence using LevelDB.\n * Features: Zero-config, embedded database, fast local storage.\n */\n\nexport interface LevelDBConfig {\n path: string; // Database file path\n}\n\nexport class LevelDBAdapter implements PersistenceAdapter {\n private db!: Level<string, string>;\n private connected = false;\n\n constructor(private config: LevelDBConfig) {}\n\n async connect(): Promise<void> {\n try {\n this.db = new Level(this.config.path, {\n valueEncoding: 'json',\n });\n await this.db.open();\n this.connected = true;\n } catch (error: any) {\n throw new Error(`LevelDB connection failed: ${error.message}`);\n }\n }\n\n async saveState(state: WorldStateSnapshot): Promise<void> {\n // Save current state\n await this.db.put('state:current', JSON.stringify(state));\n \n // Save to history with timestamp key\n const historyKey = `state:history:${state.timestamp}`;\n await this.db.put(historyKey, JSON.stringify(state));\n }\n\n async loadState(): Promise<WorldStateSnapshot | null> {\n try {\n const data = await this.db.get('state:current');\n return JSON.parse(data);\n } catch (error: any) {\n if (error.code === 'LEVEL_NOT_FOUND') {\n return null;\n }\n throw error;\n }\n }\n\n async saveEvent(event: WorldEvent): Promise<void> {\n // Save event with composite key: timestamp:id for ordering\n const key = `event:${event.timestamp}:${event.id}`;\n await this.db.put(key, JSON.stringify(event));\n \n // Index by type\n const typeKey = `event:type:${event.type}:${event.timestamp}:${event.id}`;\n await this.db.put(typeKey, JSON.stringify(event));\n \n // Index by agent if present\n if (event.agentUrl) {\n const agentKey = `event:agent:${event.agentUrl}:${event.timestamp}:${event.id}`;\n await this.db.put(agentKey, JSON.stringify(event));\n }\n }\n\n async getEvents(filter?: EventFilter): Promise<WorldEvent[]> {\n const events: WorldEvent[] = [];\n let prefix = 'event:';\n \n // Use index if filtering\n if (filter?.type) {\n prefix = `event:type:${filter.type}:`;\n } else if (filter?.agentUrl) {\n prefix = `event:agent:${filter.agentUrl}:`;\n }\n \n // LevelDB iterates in key order, so we iterate and filter\n const iterator = this.db.iterator({\n gte: prefix,\n lte: prefix + '\\uffff',\n reverse: true, // Most recent first\n limit: filter?.limit || -1,\n });\n \n for await (const [key, value] of iterator) {\n const event = JSON.parse(value as string);\n \n // Apply timestamp filters\n if (filter?.since && event.timestamp < filter.since) continue;\n if (filter?.until && event.timestamp > filter.until) continue;\n \n // Apply type filter if not already indexed\n if (filter?.type && !prefix.includes('type:') && event.type !== filter.type) {\n continue;\n }\n \n // Apply agent filter if not already indexed\n if (filter?.agentUrl && !prefix.includes('agent:') && event.agentUrl !== filter.agentUrl) {\n continue;\n }\n \n events.push(event);\n \n if (filter?.limit && events.length >= filter.limit) {\n break;\n }\n }\n \n return events;\n }\n\n async saveAgent(profile: AgentProfile): Promise<void> {\n const key = `agent:${profile.url}`;\n await this.db.put(key, JSON.stringify(profile));\n \n // Add to agents list with joinedAt for ordering\n const listKey = `agent:list:${profile.joinedAt}:${profile.url}`;\n await this.db.put(listKey, profile.url);\n }\n\n async removeAgent(agentUrl: string): Promise<void> {\n const key = `agent:${agentUrl}`;\n \n try {\n // Get agent to find joinedAt for list cleanup\n const data = await this.db.get(key);\n const profile = JSON.parse(data);\n \n // Remove from main storage\n await this.db.del(key);\n \n // Remove from list\n const listKey = `agent:list:${profile.joinedAt}:${agentUrl}`;\n await this.db.del(listKey);\n } catch (error: any) {\n if (error.code !== 'LEVEL_NOT_FOUND') {\n throw error;\n }\n }\n }\n\n async getAgents(): Promise<AgentProfile[]> {\n const agents: AgentProfile[] = [];\n \n const iterator = this.db.iterator({\n gte: 'agent:list:',\n lte: 'agent:list:\\uffff',\n });\n \n for await (const [key, agentUrl] of iterator) {\n try {\n const data = await this.db.get(`agent:${agentUrl}`);\n agents.push(JSON.parse(data as string));\n } catch (error: any) {\n // Skip if agent was deleted\n if (error.code !== 'LEVEL_NOT_FOUND') {\n throw error;\n }\n }\n }\n \n return agents;\n }\n\n async getAgent(agentUrl: string): Promise<AgentProfile | null> {\n try {\n const data = await this.db.get(`agent:${agentUrl}`);\n return JSON.parse(data);\n } catch (error: any) {\n if (error.code === 'LEVEL_NOT_FOUND') {\n return null;\n }\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n await this.db.close();\n this.connected = false;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n // Try a simple get operation\n await this.db.get('health:check').catch(() => {});\n return true;\n } catch {\n return false;\n }\n }\n\n async clear(): Promise<void> {\n await this.db.clear();\n }\n}\n"]}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// src/persistence/adapters/LevelDBAdapter.ts
|
|
2
|
+
import { Level } from "level";
|
|
3
|
+
var LevelDBAdapter = class {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
}
|
|
7
|
+
db;
|
|
8
|
+
connected = false;
|
|
9
|
+
async connect() {
|
|
10
|
+
try {
|
|
11
|
+
this.db = new Level(this.config.path, {
|
|
12
|
+
valueEncoding: "json"
|
|
13
|
+
});
|
|
14
|
+
await this.db.open();
|
|
15
|
+
this.connected = true;
|
|
16
|
+
} catch (error) {
|
|
17
|
+
throw new Error(`LevelDB connection failed: ${error.message}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async saveState(state) {
|
|
21
|
+
await this.db.put("state:current", JSON.stringify(state));
|
|
22
|
+
const historyKey = `state:history:${state.timestamp}`;
|
|
23
|
+
await this.db.put(historyKey, JSON.stringify(state));
|
|
24
|
+
}
|
|
25
|
+
async loadState() {
|
|
26
|
+
try {
|
|
27
|
+
const data = await this.db.get("state:current");
|
|
28
|
+
return JSON.parse(data);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code === "LEVEL_NOT_FOUND") {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async saveEvent(event) {
|
|
37
|
+
const key = `event:${event.timestamp}:${event.id}`;
|
|
38
|
+
await this.db.put(key, JSON.stringify(event));
|
|
39
|
+
const typeKey = `event:type:${event.type}:${event.timestamp}:${event.id}`;
|
|
40
|
+
await this.db.put(typeKey, JSON.stringify(event));
|
|
41
|
+
if (event.agentUrl) {
|
|
42
|
+
const agentKey = `event:agent:${event.agentUrl}:${event.timestamp}:${event.id}`;
|
|
43
|
+
await this.db.put(agentKey, JSON.stringify(event));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async getEvents(filter) {
|
|
47
|
+
const events = [];
|
|
48
|
+
let prefix = "event:";
|
|
49
|
+
if (filter?.type) {
|
|
50
|
+
prefix = `event:type:${filter.type}:`;
|
|
51
|
+
} else if (filter?.agentUrl) {
|
|
52
|
+
prefix = `event:agent:${filter.agentUrl}:`;
|
|
53
|
+
}
|
|
54
|
+
const iterator = this.db.iterator({
|
|
55
|
+
gte: prefix,
|
|
56
|
+
lte: prefix + "\uFFFF",
|
|
57
|
+
reverse: true,
|
|
58
|
+
// Most recent first
|
|
59
|
+
limit: filter?.limit || -1
|
|
60
|
+
});
|
|
61
|
+
for await (const [key, value] of iterator) {
|
|
62
|
+
const event = JSON.parse(value);
|
|
63
|
+
if (filter?.since && event.timestamp < filter.since) continue;
|
|
64
|
+
if (filter?.until && event.timestamp > filter.until) continue;
|
|
65
|
+
if (filter?.type && !prefix.includes("type:") && event.type !== filter.type) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (filter?.agentUrl && !prefix.includes("agent:") && event.agentUrl !== filter.agentUrl) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
events.push(event);
|
|
72
|
+
if (filter?.limit && events.length >= filter.limit) {
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return events;
|
|
77
|
+
}
|
|
78
|
+
async saveAgent(profile) {
|
|
79
|
+
const key = `agent:${profile.url}`;
|
|
80
|
+
await this.db.put(key, JSON.stringify(profile));
|
|
81
|
+
const listKey = `agent:list:${profile.joinedAt}:${profile.url}`;
|
|
82
|
+
await this.db.put(listKey, profile.url);
|
|
83
|
+
}
|
|
84
|
+
async removeAgent(agentUrl) {
|
|
85
|
+
const key = `agent:${agentUrl}`;
|
|
86
|
+
try {
|
|
87
|
+
const data = await this.db.get(key);
|
|
88
|
+
const profile = JSON.parse(data);
|
|
89
|
+
await this.db.del(key);
|
|
90
|
+
const listKey = `agent:list:${profile.joinedAt}:${agentUrl}`;
|
|
91
|
+
await this.db.del(listKey);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (error.code !== "LEVEL_NOT_FOUND") {
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async getAgents() {
|
|
99
|
+
const agents = [];
|
|
100
|
+
const iterator = this.db.iterator({
|
|
101
|
+
gte: "agent:list:",
|
|
102
|
+
lte: "agent:list:\uFFFF"
|
|
103
|
+
});
|
|
104
|
+
for await (const [key, agentUrl] of iterator) {
|
|
105
|
+
try {
|
|
106
|
+
const data = await this.db.get(`agent:${agentUrl}`);
|
|
107
|
+
agents.push(JSON.parse(data));
|
|
108
|
+
} catch (error) {
|
|
109
|
+
if (error.code !== "LEVEL_NOT_FOUND") {
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return agents;
|
|
115
|
+
}
|
|
116
|
+
async getAgent(agentUrl) {
|
|
117
|
+
try {
|
|
118
|
+
const data = await this.db.get(`agent:${agentUrl}`);
|
|
119
|
+
return JSON.parse(data);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error.code === "LEVEL_NOT_FOUND") {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async disconnect() {
|
|
128
|
+
await this.db.close();
|
|
129
|
+
this.connected = false;
|
|
130
|
+
}
|
|
131
|
+
async healthCheck() {
|
|
132
|
+
try {
|
|
133
|
+
await this.db.get("health:check").catch(() => {
|
|
134
|
+
});
|
|
135
|
+
return true;
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async clear() {
|
|
141
|
+
await this.db.clear();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
export {
|
|
145
|
+
LevelDBAdapter
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=LevelDBAdapter-ZV2ZTDOV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/persistence/adapters/LevelDBAdapter.ts"],"sourcesContent":["import type { PersistenceAdapter, EventFilter } from '../PersistenceAdapter.js';\nimport type { WorldStateSnapshot, WorldEvent, AgentProfile } from '../../config/types.js';\nimport { Level } from 'level';\n\n/**\n * ============================================================================\n * LEVELDB ADAPTER\n * ============================================================================\n * \n * Embedded key-value persistence using LevelDB.\n * Features: Zero-config, embedded database, fast local storage.\n */\n\nexport interface LevelDBConfig {\n path: string; // Database file path\n}\n\nexport class LevelDBAdapter implements PersistenceAdapter {\n private db!: Level<string, string>;\n private connected = false;\n\n constructor(private config: LevelDBConfig) {}\n\n async connect(): Promise<void> {\n try {\n this.db = new Level(this.config.path, {\n valueEncoding: 'json',\n });\n await this.db.open();\n this.connected = true;\n } catch (error: any) {\n throw new Error(`LevelDB connection failed: ${error.message}`);\n }\n }\n\n async saveState(state: WorldStateSnapshot): Promise<void> {\n // Save current state\n await this.db.put('state:current', JSON.stringify(state));\n \n // Save to history with timestamp key\n const historyKey = `state:history:${state.timestamp}`;\n await this.db.put(historyKey, JSON.stringify(state));\n }\n\n async loadState(): Promise<WorldStateSnapshot | null> {\n try {\n const data = await this.db.get('state:current');\n return JSON.parse(data);\n } catch (error: any) {\n if (error.code === 'LEVEL_NOT_FOUND') {\n return null;\n }\n throw error;\n }\n }\n\n async saveEvent(event: WorldEvent): Promise<void> {\n // Save event with composite key: timestamp:id for ordering\n const key = `event:${event.timestamp}:${event.id}`;\n await this.db.put(key, JSON.stringify(event));\n \n // Index by type\n const typeKey = `event:type:${event.type}:${event.timestamp}:${event.id}`;\n await this.db.put(typeKey, JSON.stringify(event));\n \n // Index by agent if present\n if (event.agentUrl) {\n const agentKey = `event:agent:${event.agentUrl}:${event.timestamp}:${event.id}`;\n await this.db.put(agentKey, JSON.stringify(event));\n }\n }\n\n async getEvents(filter?: EventFilter): Promise<WorldEvent[]> {\n const events: WorldEvent[] = [];\n let prefix = 'event:';\n \n // Use index if filtering\n if (filter?.type) {\n prefix = `event:type:${filter.type}:`;\n } else if (filter?.agentUrl) {\n prefix = `event:agent:${filter.agentUrl}:`;\n }\n \n // LevelDB iterates in key order, so we iterate and filter\n const iterator = this.db.iterator({\n gte: prefix,\n lte: prefix + '\\uffff',\n reverse: true, // Most recent first\n limit: filter?.limit || -1,\n });\n \n for await (const [key, value] of iterator) {\n const event = JSON.parse(value as string);\n \n // Apply timestamp filters\n if (filter?.since && event.timestamp < filter.since) continue;\n if (filter?.until && event.timestamp > filter.until) continue;\n \n // Apply type filter if not already indexed\n if (filter?.type && !prefix.includes('type:') && event.type !== filter.type) {\n continue;\n }\n \n // Apply agent filter if not already indexed\n if (filter?.agentUrl && !prefix.includes('agent:') && event.agentUrl !== filter.agentUrl) {\n continue;\n }\n \n events.push(event);\n \n if (filter?.limit && events.length >= filter.limit) {\n break;\n }\n }\n \n return events;\n }\n\n async saveAgent(profile: AgentProfile): Promise<void> {\n const key = `agent:${profile.url}`;\n await this.db.put(key, JSON.stringify(profile));\n \n // Add to agents list with joinedAt for ordering\n const listKey = `agent:list:${profile.joinedAt}:${profile.url}`;\n await this.db.put(listKey, profile.url);\n }\n\n async removeAgent(agentUrl: string): Promise<void> {\n const key = `agent:${agentUrl}`;\n \n try {\n // Get agent to find joinedAt for list cleanup\n const data = await this.db.get(key);\n const profile = JSON.parse(data);\n \n // Remove from main storage\n await this.db.del(key);\n \n // Remove from list\n const listKey = `agent:list:${profile.joinedAt}:${agentUrl}`;\n await this.db.del(listKey);\n } catch (error: any) {\n if (error.code !== 'LEVEL_NOT_FOUND') {\n throw error;\n }\n }\n }\n\n async getAgents(): Promise<AgentProfile[]> {\n const agents: AgentProfile[] = [];\n \n const iterator = this.db.iterator({\n gte: 'agent:list:',\n lte: 'agent:list:\\uffff',\n });\n \n for await (const [key, agentUrl] of iterator) {\n try {\n const data = await this.db.get(`agent:${agentUrl}`);\n agents.push(JSON.parse(data as string));\n } catch (error: any) {\n // Skip if agent was deleted\n if (error.code !== 'LEVEL_NOT_FOUND') {\n throw error;\n }\n }\n }\n \n return agents;\n }\n\n async getAgent(agentUrl: string): Promise<AgentProfile | null> {\n try {\n const data = await this.db.get(`agent:${agentUrl}`);\n return JSON.parse(data);\n } catch (error: any) {\n if (error.code === 'LEVEL_NOT_FOUND') {\n return null;\n }\n throw error;\n }\n }\n\n async disconnect(): Promise<void> {\n await this.db.close();\n this.connected = false;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n // Try a simple get operation\n await this.db.get('health:check').catch(() => {});\n return true;\n } catch {\n return false;\n }\n }\n\n async clear(): Promise<void> {\n await this.db.clear();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// src/persistence/adapters/MongoAdapter.ts
|
|
2
|
+
import { MongoClient } from "mongodb";
|
|
3
|
+
var MongoAdapter = class {
|
|
4
|
+
constructor(config) {
|
|
5
|
+
this.config = config;
|
|
6
|
+
this.client = new MongoClient(config.url, {
|
|
7
|
+
useUnifiedTopology: config.useUnifiedTopology !== false
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
client;
|
|
11
|
+
db;
|
|
12
|
+
stateCollection;
|
|
13
|
+
eventsCollection;
|
|
14
|
+
agentsCollection;
|
|
15
|
+
connected = false;
|
|
16
|
+
async connect() {
|
|
17
|
+
try {
|
|
18
|
+
await this.client.connect();
|
|
19
|
+
this.db = this.client.db(this.config.database);
|
|
20
|
+
this.stateCollection = this.db.collection("world_state");
|
|
21
|
+
this.eventsCollection = this.db.collection("world_events");
|
|
22
|
+
this.agentsCollection = this.db.collection("agent_profiles");
|
|
23
|
+
await this.initIndexes();
|
|
24
|
+
this.connected = true;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw new Error(`MongoDB connection failed: ${error.message}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async initIndexes() {
|
|
30
|
+
await this.eventsCollection.createIndex({ type: 1 });
|
|
31
|
+
await this.eventsCollection.createIndex({ timestamp: -1 });
|
|
32
|
+
await this.eventsCollection.createIndex({ agentUrl: 1 });
|
|
33
|
+
await this.eventsCollection.createIndex({ type: 1, timestamp: -1 });
|
|
34
|
+
await this.agentsCollection.createIndex({ url: 1 }, { unique: true });
|
|
35
|
+
await this.agentsCollection.createIndex({ joinedAt: 1 });
|
|
36
|
+
await this.stateCollection.createIndex({ timestamp: -1 });
|
|
37
|
+
}
|
|
38
|
+
async saveState(state) {
|
|
39
|
+
await this.stateCollection.insertOne({
|
|
40
|
+
...state,
|
|
41
|
+
_createdAt: /* @__PURE__ */ new Date()
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async loadState() {
|
|
45
|
+
const doc = await this.stateCollection.findOne(
|
|
46
|
+
{},
|
|
47
|
+
{ sort: { timestamp: -1 } }
|
|
48
|
+
);
|
|
49
|
+
if (!doc) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const { _id, _createdAt, ...state } = doc;
|
|
53
|
+
return state;
|
|
54
|
+
}
|
|
55
|
+
async saveEvent(event) {
|
|
56
|
+
await this.eventsCollection.insertOne({
|
|
57
|
+
_id: event.id,
|
|
58
|
+
...event,
|
|
59
|
+
_createdAt: /* @__PURE__ */ new Date()
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async getEvents(filter) {
|
|
63
|
+
const query = {};
|
|
64
|
+
if (filter?.type) {
|
|
65
|
+
query.type = filter.type;
|
|
66
|
+
}
|
|
67
|
+
if (filter?.agentUrl) {
|
|
68
|
+
query.agentUrl = filter.agentUrl;
|
|
69
|
+
}
|
|
70
|
+
if (filter?.since || filter?.until) {
|
|
71
|
+
query.timestamp = {};
|
|
72
|
+
if (filter.since) {
|
|
73
|
+
query.timestamp.$gte = filter.since;
|
|
74
|
+
}
|
|
75
|
+
if (filter.until) {
|
|
76
|
+
query.timestamp.$lte = filter.until;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const cursor = this.eventsCollection.find(query).sort({ timestamp: -1 });
|
|
80
|
+
if (filter?.limit) {
|
|
81
|
+
cursor.limit(filter.limit);
|
|
82
|
+
}
|
|
83
|
+
const docs = await cursor.toArray();
|
|
84
|
+
return docs.map((doc) => {
|
|
85
|
+
const { _id, _createdAt, ...event } = doc;
|
|
86
|
+
return event;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async saveAgent(profile) {
|
|
90
|
+
await this.agentsCollection.updateOne(
|
|
91
|
+
{ url: profile.url },
|
|
92
|
+
{ $set: { ...profile, _updatedAt: /* @__PURE__ */ new Date() } },
|
|
93
|
+
{ upsert: true }
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
async removeAgent(agentUrl) {
|
|
97
|
+
await this.agentsCollection.deleteOne({ url: agentUrl });
|
|
98
|
+
}
|
|
99
|
+
async getAgents() {
|
|
100
|
+
const docs = await this.agentsCollection.find({}).sort({ joinedAt: 1 }).toArray();
|
|
101
|
+
return docs.map((doc) => {
|
|
102
|
+
const { _id, _updatedAt, ...profile } = doc;
|
|
103
|
+
return profile;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async getAgent(agentUrl) {
|
|
107
|
+
const doc = await this.agentsCollection.findOne({ url: agentUrl });
|
|
108
|
+
if (!doc) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const { _id, _updatedAt, ...profile } = doc;
|
|
112
|
+
return profile;
|
|
113
|
+
}
|
|
114
|
+
async disconnect() {
|
|
115
|
+
await this.client.close();
|
|
116
|
+
this.connected = false;
|
|
117
|
+
}
|
|
118
|
+
async healthCheck() {
|
|
119
|
+
try {
|
|
120
|
+
await this.db.admin().ping();
|
|
121
|
+
return true;
|
|
122
|
+
} catch {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async clear() {
|
|
127
|
+
await Promise.all([
|
|
128
|
+
this.stateCollection.deleteMany({}),
|
|
129
|
+
this.eventsCollection.deleteMany({}),
|
|
130
|
+
this.agentsCollection.deleteMany({})
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
export {
|
|
135
|
+
MongoAdapter
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=MongoAdapter-TCY6JOZH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/persistence/adapters/MongoAdapter.ts"],"sourcesContent":["import type { PersistenceAdapter, EventFilter } from '../PersistenceAdapter.js';\nimport type { WorldStateSnapshot, WorldEvent, AgentProfile } from '../../config/types.js';\nimport { MongoClient, Db, Collection } from 'mongodb';\n\n/**\n * ============================================================================\n * MONGODB ADAPTER\n * ============================================================================\n * \n * Flexible schema persistence using MongoDB.\n * Features: JSON-native storage, powerful aggregations, horizontal scaling.\n */\n\nexport interface MongoConfig {\n url: string;\n database: string;\n useUnifiedTopology?: boolean;\n}\n\nexport class MongoAdapter implements PersistenceAdapter {\n private client: MongoClient;\n private db!: Db;\n private stateCollection!: Collection;\n private eventsCollection!: Collection;\n private agentsCollection!: Collection;\n private connected = false;\n\n constructor(private config: MongoConfig) {\n this.client = new MongoClient(config.url, {\n useUnifiedTopology: config.useUnifiedTopology !== false,\n } as any);\n }\n\n async connect(): Promise<void> {\n try {\n await this.client.connect();\n this.db = this.client.db(this.config.database);\n \n // Initialize collections\n this.stateCollection = this.db.collection('world_state');\n this.eventsCollection = this.db.collection('world_events');\n this.agentsCollection = this.db.collection('agent_profiles');\n \n // Create indexes\n await this.initIndexes();\n \n this.connected = true;\n } catch (error: any) {\n throw new Error(`MongoDB connection failed: ${error.message}`);\n }\n }\n\n private async initIndexes(): Promise<void> {\n // Events indexes\n await this.eventsCollection.createIndex({ type: 1 });\n await this.eventsCollection.createIndex({ timestamp: -1 });\n await this.eventsCollection.createIndex({ agentUrl: 1 });\n await this.eventsCollection.createIndex({ type: 1, timestamp: -1 });\n \n // Agents index\n await this.agentsCollection.createIndex({ url: 1 }, { unique: true });\n await this.agentsCollection.createIndex({ joinedAt: 1 });\n \n // State index\n await this.stateCollection.createIndex({ timestamp: -1 });\n }\n\n async saveState(state: WorldStateSnapshot): Promise<void> {\n await this.stateCollection.insertOne({\n ...state,\n _createdAt: new Date(),\n });\n }\n\n async loadState(): Promise<WorldStateSnapshot | null> {\n const doc = await this.stateCollection.findOne(\n {},\n { sort: { timestamp: -1 } }\n );\n \n if (!doc) {\n return null;\n }\n \n const { _id, _createdAt, ...state } = doc;\n return state as WorldStateSnapshot;\n }\n\n async saveEvent(event: WorldEvent): Promise<void> {\n await this.eventsCollection.insertOne({\n _id: event.id,\n ...event,\n _createdAt: new Date(),\n });\n }\n\n async getEvents(filter?: EventFilter): Promise<WorldEvent[]> {\n const query: any = {};\n \n if (filter?.type) {\n query.type = filter.type;\n }\n \n if (filter?.agentUrl) {\n query.agentUrl = filter.agentUrl;\n }\n \n if (filter?.since || filter?.until) {\n query.timestamp = {};\n if (filter.since) {\n query.timestamp.$gte = filter.since;\n }\n if (filter.until) {\n query.timestamp.$lte = filter.until;\n }\n }\n \n const cursor = this.eventsCollection\n .find(query)\n .sort({ timestamp: -1 });\n \n if (filter?.limit) {\n cursor.limit(filter.limit);\n }\n \n const docs = await cursor.toArray();\n \n return docs.map(doc => {\n const { _id, _createdAt, ...event } = doc;\n return event as WorldEvent;\n });\n }\n\n async saveAgent(profile: AgentProfile): Promise<void> {\n await this.agentsCollection.updateOne(\n { url: profile.url },\n { $set: { ...profile, _updatedAt: new Date() } },\n { upsert: true }\n );\n }\n\n async removeAgent(agentUrl: string): Promise<void> {\n await this.agentsCollection.deleteOne({ url: agentUrl });\n }\n\n async getAgents(): Promise<AgentProfile[]> {\n const docs = await this.agentsCollection\n .find({})\n .sort({ joinedAt: 1 })\n .toArray();\n \n return docs.map(doc => {\n const { _id, _updatedAt, ...profile } = doc;\n return profile as AgentProfile;\n });\n }\n\n async getAgent(agentUrl: string): Promise<AgentProfile | null> {\n const doc = await this.agentsCollection.findOne({ url: agentUrl });\n \n if (!doc) {\n return null;\n }\n \n const { _id, _updatedAt, ...profile } = doc;\n return profile as AgentProfile;\n }\n\n async disconnect(): Promise<void> {\n await this.client.close();\n this.connected = false;\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n await this.db.admin().ping();\n return true;\n } catch {\n return false;\n }\n }\n\n async clear(): Promise<void> {\n await Promise.all([\n this.stateCollection.deleteMany({}),\n this.eventsCollection.deleteMany({}),\n this.agentsCollection.deleteMany({}),\n ]);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/persistence/adapters/MongoAdapter.ts
|
|
2
|
+
var _mongodb = require('mongodb');
|
|
3
|
+
var MongoAdapter = (_class = class {
|
|
4
|
+
constructor(config) {;_class.prototype.__init.call(this);
|
|
5
|
+
this.config = config;
|
|
6
|
+
this.client = new (0, _mongodb.MongoClient)(config.url, {
|
|
7
|
+
useUnifiedTopology: config.useUnifiedTopology !== false
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__init() {this.connected = false}
|
|
16
|
+
async connect() {
|
|
17
|
+
try {
|
|
18
|
+
await this.client.connect();
|
|
19
|
+
this.db = this.client.db(this.config.database);
|
|
20
|
+
this.stateCollection = this.db.collection("world_state");
|
|
21
|
+
this.eventsCollection = this.db.collection("world_events");
|
|
22
|
+
this.agentsCollection = this.db.collection("agent_profiles");
|
|
23
|
+
await this.initIndexes();
|
|
24
|
+
this.connected = true;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throw new Error(`MongoDB connection failed: ${error.message}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async initIndexes() {
|
|
30
|
+
await this.eventsCollection.createIndex({ type: 1 });
|
|
31
|
+
await this.eventsCollection.createIndex({ timestamp: -1 });
|
|
32
|
+
await this.eventsCollection.createIndex({ agentUrl: 1 });
|
|
33
|
+
await this.eventsCollection.createIndex({ type: 1, timestamp: -1 });
|
|
34
|
+
await this.agentsCollection.createIndex({ url: 1 }, { unique: true });
|
|
35
|
+
await this.agentsCollection.createIndex({ joinedAt: 1 });
|
|
36
|
+
await this.stateCollection.createIndex({ timestamp: -1 });
|
|
37
|
+
}
|
|
38
|
+
async saveState(state) {
|
|
39
|
+
await this.stateCollection.insertOne({
|
|
40
|
+
...state,
|
|
41
|
+
_createdAt: /* @__PURE__ */ new Date()
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async loadState() {
|
|
45
|
+
const doc = await this.stateCollection.findOne(
|
|
46
|
+
{},
|
|
47
|
+
{ sort: { timestamp: -1 } }
|
|
48
|
+
);
|
|
49
|
+
if (!doc) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
const { _id, _createdAt, ...state } = doc;
|
|
53
|
+
return state;
|
|
54
|
+
}
|
|
55
|
+
async saveEvent(event) {
|
|
56
|
+
await this.eventsCollection.insertOne({
|
|
57
|
+
_id: event.id,
|
|
58
|
+
...event,
|
|
59
|
+
_createdAt: /* @__PURE__ */ new Date()
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
async getEvents(filter) {
|
|
63
|
+
const query = {};
|
|
64
|
+
if (_optionalChain([filter, 'optionalAccess', _ => _.type])) {
|
|
65
|
+
query.type = filter.type;
|
|
66
|
+
}
|
|
67
|
+
if (_optionalChain([filter, 'optionalAccess', _2 => _2.agentUrl])) {
|
|
68
|
+
query.agentUrl = filter.agentUrl;
|
|
69
|
+
}
|
|
70
|
+
if (_optionalChain([filter, 'optionalAccess', _3 => _3.since]) || _optionalChain([filter, 'optionalAccess', _4 => _4.until])) {
|
|
71
|
+
query.timestamp = {};
|
|
72
|
+
if (filter.since) {
|
|
73
|
+
query.timestamp.$gte = filter.since;
|
|
74
|
+
}
|
|
75
|
+
if (filter.until) {
|
|
76
|
+
query.timestamp.$lte = filter.until;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const cursor = this.eventsCollection.find(query).sort({ timestamp: -1 });
|
|
80
|
+
if (_optionalChain([filter, 'optionalAccess', _5 => _5.limit])) {
|
|
81
|
+
cursor.limit(filter.limit);
|
|
82
|
+
}
|
|
83
|
+
const docs = await cursor.toArray();
|
|
84
|
+
return docs.map((doc) => {
|
|
85
|
+
const { _id, _createdAt, ...event } = doc;
|
|
86
|
+
return event;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
async saveAgent(profile) {
|
|
90
|
+
await this.agentsCollection.updateOne(
|
|
91
|
+
{ url: profile.url },
|
|
92
|
+
{ $set: { ...profile, _updatedAt: /* @__PURE__ */ new Date() } },
|
|
93
|
+
{ upsert: true }
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
async removeAgent(agentUrl) {
|
|
97
|
+
await this.agentsCollection.deleteOne({ url: agentUrl });
|
|
98
|
+
}
|
|
99
|
+
async getAgents() {
|
|
100
|
+
const docs = await this.agentsCollection.find({}).sort({ joinedAt: 1 }).toArray();
|
|
101
|
+
return docs.map((doc) => {
|
|
102
|
+
const { _id, _updatedAt, ...profile } = doc;
|
|
103
|
+
return profile;
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
async getAgent(agentUrl) {
|
|
107
|
+
const doc = await this.agentsCollection.findOne({ url: agentUrl });
|
|
108
|
+
if (!doc) {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const { _id, _updatedAt, ...profile } = doc;
|
|
112
|
+
return profile;
|
|
113
|
+
}
|
|
114
|
+
async disconnect() {
|
|
115
|
+
await this.client.close();
|
|
116
|
+
this.connected = false;
|
|
117
|
+
}
|
|
118
|
+
async healthCheck() {
|
|
119
|
+
try {
|
|
120
|
+
await this.db.admin().ping();
|
|
121
|
+
return true;
|
|
122
|
+
} catch (e) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async clear() {
|
|
127
|
+
await Promise.all([
|
|
128
|
+
this.stateCollection.deleteMany({}),
|
|
129
|
+
this.eventsCollection.deleteMany({}),
|
|
130
|
+
this.agentsCollection.deleteMany({})
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
133
|
+
}, _class);
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
exports.MongoAdapter = MongoAdapter;
|
|
137
|
+
//# sourceMappingURL=MongoAdapter-XEHWKU2F.cjs.map
|