@agentadmit/sdk 1.0.0

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/src/storage.ts ADDED
@@ -0,0 +1,228 @@
1
+ /**
2
+ * agentadmit/storage.ts
3
+ * Abstract storage interface + MongoDB + Memory implementations.
4
+ */
5
+
6
+ export interface StorageBackend {
7
+ storeConnection(connection: Record<string, any>): Promise<void>;
8
+ getConnection(connectionId: string): Promise<Record<string, any> | null>;
9
+ getActiveConnection(connectionId: string): Promise<Record<string, any> | null>;
10
+ updateConnection(connectionId: string, updates: Record<string, any>): Promise<boolean>;
11
+ revokeConnection(connectionId: string): Promise<boolean>;
12
+ listConnections(userId: string): Promise<Record<string, any>[]>;
13
+ countActiveConnections(userId: string): Promise<number>;
14
+ storeToken(tokenRecord: Record<string, any>): Promise<void>;
15
+ getToken(tokenHash: string): Promise<Record<string, any> | null>;
16
+ markTokenUsed(tokenHash: string): Promise<boolean>;
17
+ logAccess(entry: Record<string, any>): Promise<void>;
18
+ countAuditCalls(userId: string, periodStart: Date, periodEnd: Date): Promise<number>;
19
+ getUser(userId: string, lookupField: string): Promise<Record<string, any> | null>;
20
+ }
21
+
22
+ export class MongoDBStorage implements StorageBackend {
23
+ private db: any;
24
+ private connections: any;
25
+ private auditLog: any;
26
+ private tokens: any;
27
+ private users: any = null;
28
+
29
+ constructor(
30
+ uri: string,
31
+ database: string,
32
+ connectionsCollection: string,
33
+ auditLogCollection: string,
34
+ tokensCollection: string,
35
+ ) {
36
+ // Lazy import to keep mongodb as optional peer dep
37
+ const { MongoClient } = require('mongodb');
38
+ const client = new MongoClient(uri);
39
+ this.db = client.db(database);
40
+ this.connections = this.db.collection(connectionsCollection);
41
+ this.auditLog = this.db.collection(auditLogCollection);
42
+ this.tokens = this.db.collection(tokensCollection);
43
+
44
+ // Create indexes
45
+ this.connections.createIndex({ connection_id: 1 }, { unique: true }).catch(() => {});
46
+ this.connections.createIndex({ user_id: 1, status: 1 }).catch(() => {});
47
+ this.tokens.createIndex({ token_hash: 1 }, { unique: true }).catch(() => {});
48
+ this.auditLog.createIndex({ user_id: 1, timestamp: -1 }).catch(() => {});
49
+
50
+ console.log(`[AgentAdmit] MongoDB storage initialized: ${database}`);
51
+ }
52
+
53
+ setUsersCollection(name: string) {
54
+ this.users = this.db.collection(name);
55
+ }
56
+
57
+ async storeConnection(connection: Record<string, any>): Promise<void> {
58
+ await this.connections.insertOne(connection);
59
+ }
60
+
61
+ async getConnection(connectionId: string): Promise<Record<string, any> | null> {
62
+ return this.connections.findOne({ connection_id: connectionId });
63
+ }
64
+
65
+ async getActiveConnection(connectionId: string): Promise<Record<string, any> | null> {
66
+ return this.connections.findOne({ connection_id: connectionId, status: 'active' });
67
+ }
68
+
69
+ async updateConnection(connectionId: string, updates: Record<string, any>): Promise<boolean> {
70
+ const result = await this.connections.updateOne(
71
+ { connection_id: connectionId },
72
+ { $set: updates },
73
+ );
74
+ return result.modifiedCount > 0;
75
+ }
76
+
77
+ async revokeConnection(connectionId: string): Promise<boolean> {
78
+ const result = await this.connections.updateOne(
79
+ { connection_id: connectionId, status: 'active' },
80
+ { $set: { status: 'revoked', revoked_at: new Date() } },
81
+ );
82
+ return result.modifiedCount > 0;
83
+ }
84
+
85
+ async listConnections(userId: string): Promise<Record<string, any>[]> {
86
+ return this.connections.find({ user_id: userId }, { projection: { _id: 0 } }).sort({ created_at: -1 }).toArray();
87
+ }
88
+
89
+ async countActiveConnections(userId: string): Promise<number> {
90
+ return this.connections.countDocuments({ user_id: userId, status: 'active' });
91
+ }
92
+
93
+ async storeToken(tokenRecord: Record<string, any>): Promise<void> {
94
+ await this.tokens.insertOne(tokenRecord);
95
+ }
96
+
97
+ async getToken(tokenHash: string): Promise<Record<string, any> | null> {
98
+ return this.tokens.findOne({ token_hash: tokenHash });
99
+ }
100
+
101
+ async markTokenUsed(tokenHash: string): Promise<boolean> {
102
+ const result = await this.tokens.updateOne(
103
+ { token_hash: tokenHash, used: false },
104
+ { $set: { used: true, used_at: new Date() } },
105
+ );
106
+ return result.modifiedCount > 0;
107
+ }
108
+
109
+ async logAccess(entry: Record<string, any>): Promise<void> {
110
+ try {
111
+ await this.auditLog.insertOne(entry);
112
+ } catch (err) {
113
+ console.error('[AgentAdmit] Audit log failed:', err);
114
+ }
115
+ }
116
+
117
+ async countAuditCalls(userId: string, periodStart: Date, periodEnd: Date): Promise<number> {
118
+ return this.auditLog.countDocuments({
119
+ user_id: userId,
120
+ timestamp: { $gte: periodStart, $lt: periodEnd },
121
+ });
122
+ }
123
+
124
+ async getUser(userId: string, lookupField: string = 'user_id'): Promise<Record<string, any> | null> {
125
+ if (!this.users) return null;
126
+ return this.users.findOne({ [lookupField]: userId });
127
+ }
128
+ }
129
+
130
+ export class MemoryStorage implements StorageBackend {
131
+ private _connections: Map<string, Record<string, any>> = new Map();
132
+ private _tokens: Map<string, Record<string, any>> = new Map();
133
+ private _auditLog: Record<string, any>[] = [];
134
+ private _users: Map<string, Record<string, any>> = new Map();
135
+
136
+ async storeConnection(connection: Record<string, any>): Promise<void> {
137
+ this._connections.set(connection.connection_id, connection);
138
+ }
139
+
140
+ async getConnection(connectionId: string): Promise<Record<string, any> | null> {
141
+ return this._connections.get(connectionId) || null;
142
+ }
143
+
144
+ async getActiveConnection(connectionId: string): Promise<Record<string, any> | null> {
145
+ const conn = this._connections.get(connectionId);
146
+ return conn?.status === 'active' ? conn : null;
147
+ }
148
+
149
+ async updateConnection(connectionId: string, updates: Record<string, any>): Promise<boolean> {
150
+ const conn = this._connections.get(connectionId);
151
+ if (!conn) return false;
152
+ Object.assign(conn, updates);
153
+ return true;
154
+ }
155
+
156
+ async revokeConnection(connectionId: string): Promise<boolean> {
157
+ const conn = this._connections.get(connectionId);
158
+ if (!conn || conn.status !== 'active') return false;
159
+ conn.status = 'revoked';
160
+ conn.revoked_at = new Date();
161
+ return true;
162
+ }
163
+
164
+ async listConnections(userId: string): Promise<Record<string, any>[]> {
165
+ return Array.from(this._connections.values()).filter(c => c.user_id === userId);
166
+ }
167
+
168
+ async countActiveConnections(userId: string): Promise<number> {
169
+ return Array.from(this._connections.values()).filter(c => c.user_id === userId && c.status === 'active').length;
170
+ }
171
+
172
+ async storeToken(tokenRecord: Record<string, any>): Promise<void> {
173
+ this._tokens.set(tokenRecord.token_hash, tokenRecord);
174
+ }
175
+
176
+ async getToken(tokenHash: string): Promise<Record<string, any> | null> {
177
+ return this._tokens.get(tokenHash) || null;
178
+ }
179
+
180
+ async markTokenUsed(tokenHash: string): Promise<boolean> {
181
+ const token = this._tokens.get(tokenHash);
182
+ if (!token || token.used) return false;
183
+ token.used = true;
184
+ token.used_at = new Date();
185
+ return true;
186
+ }
187
+
188
+ async logAccess(entry: Record<string, any>): Promise<void> {
189
+ this._auditLog.push(entry);
190
+ }
191
+
192
+ async countAuditCalls(userId: string, periodStart: Date, periodEnd: Date): Promise<number> {
193
+ return this._auditLog.filter(e =>
194
+ e.user_id === userId &&
195
+ e.timestamp >= periodStart &&
196
+ e.timestamp < periodEnd
197
+ ).length;
198
+ }
199
+
200
+ async getUser(userId: string, lookupField: string = 'user_id'): Promise<Record<string, any> | null> {
201
+ return this._users.get(userId) || null;
202
+ }
203
+
204
+ addTestUser(userId: string, data: Record<string, any>): void {
205
+ this._users.set(userId, data);
206
+ }
207
+ }
208
+
209
+ export function createStorage(config: any): StorageBackend {
210
+ const backend = config.storage?.backend || 'mongodb';
211
+
212
+ if (backend === 'mongodb') {
213
+ const s = new MongoDBStorage(
214
+ config.storage.uri,
215
+ config.storage.database,
216
+ config.storage.connections_collection || 'agentadmit_connections',
217
+ config.storage.audit_log_collection || 'agentadmit_audit_log',
218
+ config.storage.tokens_collection || 'agentadmit_tokens',
219
+ );
220
+ return s;
221
+ }
222
+
223
+ if (backend === 'memory') {
224
+ return new MemoryStorage();
225
+ }
226
+
227
+ throw new Error(`Unsupported storage backend: ${backend}`);
228
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "declaration": true,
7
+ "strict": true,
8
+ "noImplicitAny": true,
9
+ "strictNullChecks": true,
10
+ "outDir": "./dist",
11
+ "rootDir": "./src",
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "resolveJsonModule": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist", "tests"]
19
+ }